pax_global_header00006660000000000000000000000064142010150410014476gustar00rootroot0000000000000052 comment=2a93df80f27739ccabb5b885cb12a8dc7595ecdf thrift-0.16.0/000077500000000000000000000000001420101504100130625ustar00rootroot00000000000000thrift-0.16.0/.asf.yaml000066400000000000000000000003721420101504100145770ustar00rootroot00000000000000notifications: commits: commits@thrift.apache.org issues: dev@thrift.apache.org pullrequests_status: dev@thrift.apache.org pullrequests_comment: notifications@thrift.apache.org jira_options: link label worklog thrift-0.16.0/.clang-format000066400000000000000000000032441420101504100154400ustar00rootroot00000000000000--- Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 ConstructorInitializerIndentWidth: 2 AlignEscapedNewlinesLeft: false AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AlwaysBreakTemplateDeclarations: true AlwaysBreakBeforeMultilineStrings: true BreakBeforeBinaryOperators: true BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BinPackParameters: false ColumnLimit: 100 ConstructorInitializerAllOnOneLineOrOnePerLine: true DerivePointerAlignment: false IndentCaseLabels: false IndentWrappedFunctionNames: false IndentFunctionDeclarationAfterType: false MaxEmptyLinesToKeep: 1 KeepEmptyLinesAtTheStartOfBlocks: true NamespaceIndentation: None ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakBeforeFirstCallParameter: 190 PenaltyBreakComment: 300 PenaltyBreakString: 10000 PenaltyBreakFirstLessLess: 120 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 1200 PointerAlignment: Left SpacesBeforeTrailingComments: 1 Cpp11BracedListStyle: true Standard: Auto IndentWidth: 2 TabWidth: 4 UseTab: Never BreakBeforeBraces: Attach SpacesInParentheses: false SpacesInAngles: false SpaceInEmptyParentheses: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: true SpaceBeforeAssignmentOperators: true ContinuationIndentWidth: 4 CommentPragmas: '^ IWYU pragma:' ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] SpaceBeforeParens: ControlStatements DisableFormat: false ... thrift-0.16.0/.dockerignore000066400000000000000000000000061420101504100155320ustar00rootroot00000000000000.git/ thrift-0.16.0/.editorconfig000077500000000000000000000032161420101504100155440ustar00rootroot00000000000000# ## Licensed to the Apache Software Foundation (ASF) under one ## or more contributor license agreements. See the NOTICE file ## distributed with this work for additional information ## regarding copyright ownership. The ASF licenses this file ## to you under the Apache License, Version 2.0 (the ## "License"); you may not use this file except in compliance ## with the License. You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, ## software distributed under the License is distributed on an ## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ## KIND, either express or implied. See the License for the ## specific language governing permissions and limitations ## under the License. ## # # EditorConfig: http://editorconfig.org # see doc/coding_standards.md root = true [*] end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true # ActionScript # [*.as] # C # [*.c] # C++ [*.cpp] indent_style = space indent_size = 2 # C-Sharp # [*.cs] # D # [*.d] # Erlang # [*.erl] # Go-lang [*.go] indent_style = tab indent_size = 8 # C header files # [*.h] # Haskell # [*.hs] # Haxe # [*.hx] # Java # [*.java] # Javascript [*.js] indent_style = space indent_size = 2 # JSON [*.json] indent_style = space indent_size = 2 # Lua # [*.lua] [*.markdown] indent_style = space trim_trailing_whitespace = false [*.md] indent_style = space trim_trailing_whitespace = false # OCaml # [*.ml] # Delphi Pascal # [*.pas] # PHP # [*.php] # Perl # [*.pm] # Python # [*.py] # Ruby # [*.rb] # Typescript # [*.ts] # XML # [*.xml] thrift-0.16.0/.eslintignore000066400000000000000000000003161420101504100155650ustar00rootroot00000000000000# TODO: Use eslint on js lib and generated code # Ignore lib/js for now, which uses jshint currently lib/js/* # Ignore all generated code for now **/gen-* # Don't lint nested node_modules **/node_modules thrift-0.16.0/.eslintrc.json000066400000000000000000000005661420101504100156650ustar00rootroot00000000000000{ "env": { "es6": true, "node": true }, "extends": [ "eslint:recommended", "plugin:prettier/recommended" ], "parserOptions": { "ecmaVersion": 2017 }, "rules": { "no-console": "off", "no-var": "error", "prefer-const": "error", "no-constant-condition": [ "error", { "checkLoops": false } ] } } thrift-0.16.0/.flake8000066400000000000000000000002401420101504100142310ustar00rootroot00000000000000[flake8] exclude = .git,__pycache__,**/gen-*/**,contrib/**,docs/source/conf.py,old,build,dist ignore = W504,E402,E501 max-complexity = 30 max-line-length = 120 thrift-0.16.0/.gitattributes000066400000000000000000000000141420101504100157500ustar00rootroot00000000000000* text=auto thrift-0.16.0/.github/000077500000000000000000000000001420101504100144225ustar00rootroot00000000000000thrift-0.16.0/.github/pull_request_template.md000066400000000000000000000015701420101504100213660ustar00rootroot00000000000000 - [ ] Did you create an [Apache Jira](https://issues.apache.org/jira/projects/THRIFT/issues/) ticket? (not required for trivial changes) - [ ] If a ticket exists: Does your pull request title follow the pattern "THRIFT-NNNN: describe my issue"? - [ ] Did you squash your changes to a single commit? (not required, but preferred) - [ ] Did you do your best to avoid breaking changes? If one was needed, did you label the Jira ticket with "Breaking-Change"? - [ ] If your change does not involve any code, include `[skip ci]` anywhere in the commit message to free up build resources. thrift-0.16.0/.github/stale.yml000066400000000000000000000036121420101504100162570ustar00rootroot00000000000000# Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale daysUntilStale: 60 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. daysUntilClose: 7 # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable exemptLabels: - Do Not Merge - blocked - pinned - security - "[Status] Maybe Later" # Set to true to ignore issues in a project (defaults to false) exemptProjects: false # Set to true to ignore issues in a milestone (defaults to false) exemptMilestones: false # Label to use when marking as stale staleLabel: wontfix # Comment to post when marking as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions. # Comment to post when removing the stale label. unmarkComment: > This issue is no longer stale. Thank you for your contributions. # Comment to post when closing a stale Issue or Pull Request. closeComment: > This issue has been automatically closed due to inactivity. Thank you for your contributions. # Limit the number of actions per hour, from 1-30. Default is 30 limitPerRun: 30 # Limit to only `issues` or `pulls` # only: issues # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': # pulls: # daysUntilStale: 30 # markComment: > # This pull request has been automatically marked as stale because it has not had # recent activity. It will be closed if no further activity occurs. Thank you # for your contributions. # issues: # exemptLabels: # - confirmed thrift-0.16.0/.gitignore000066400000000000000000000244521420101504100150610ustar00rootroot00000000000000# generic ignores *.la *.lo *.o *.deps *.dirstamp *.libs *.log *.trs *.suo *.pyc *.cache *.user *.ipch *.sdf *.jar *.exe *.dll *_ReSharper* *.opensdf *.swp *.hi *~ tags .*project .classpath .dub .settings .checkstyle junit*.properties .idea *.iml *.ipr *.iws gen-* Makefile Makefile.in aclocal.m4 acinclude.m4 apache-thrift-test-library autom4te.cache cmake-* dub.selections.json libapache-thrift.a node_modules compile test-driver erl_crash.dump project.lock.json .sonar .DS_Store .svn .vagrant .vscode .vs /aclocal/libtool.m4 /aclocal/lt*.m4 /autoscan.log /autoscan-*.log /cmake_* /compiler/cpp/compiler.VC.db /compiler/cpp/compiler.VC.VC.opendb /compiler/cpp/test/plugin/t_cpp_generator.cc /compiler/cpp/src/thrift/plugin/plugin_constants.cpp /compiler/cpp/src/thrift/plugin/plugin_constants.h /compiler/cpp/src/thrift/plugin/plugin_types.cpp /compiler/cpp/src/thrift/plugin/plugin_types.h /compiler/cpp/test/*test /compiler/cpp/test/thrift-gen-* /compiler/cpp/src/thrift/thrift-bootstrap /compiler/cpp/src/thrift/plugin/gen.stamp /compiler/cpp/Debug /compiler/cpp/Release /compiler/cpp/src/thrift/libparse.a /compiler/cpp/src/thrift/thriftl.cc /compiler/cpp/src/thrift/thrifty.cc /compiler/cpp/src/thrift/thrifty.hh /compiler/cpp/src/thrift/windows/version.h /compiler/cpp/thrift /compiler/cpp/thriftl.cc /compiler/cpp/thrifty.cc /compiler/cpp/lex.yythriftl.cc /compiler/cpp/thrifty.h /compiler/cpp/thrifty.hh /compiler/cpp/src/thrift/version.h /config.* /configure /configure.lineno /configure.scan /contrib/.vagrant/ /contrib/fb303/config.cache /contrib/fb303/config.log /contrib/fb303/config.status /contrib/fb303/configure /contrib/fb303/cpp/libfb303.a /contrib/fb303/java/build/ /contrib/fb303/py/build/ /contrib/fb303/py/fb303/FacebookService-remote /contrib/fb303/py/fb303/FacebookService.py /contrib/fb303/py/fb303/__init__.py /contrib/fb303/py/fb303/constants.py /contrib/fb303/py/fb303/ttypes.py /depcomp /install-sh /lib/cl/backport-update.zip /lib/cl/lib /lib/cl/run-tests /lib/cl/quicklisp.lisp /lib/cl/externals/ /lib/cl/run-tests /lib/cl/quicklisp/ /lib/cpp/Debug/ /lib/cpp/Debug-mt/ /lib/cpp/Release/ /lib/cpp/Release-mt/ /lib/cpp/src/thrift/qt/moc_TQTcpServer.cpp /lib/cpp/src/thrift/qt/moc__TQTcpServer.cpp /lib/cpp/src/thrift/config.h /lib/cpp/src/thrift/stamp-h2 /lib/cpp/test/Benchmark /lib/cpp/test/AllProtocolsTest /lib/cpp/test/AnnotationTest /lib/cpp/test/DebugProtoTest /lib/cpp/test/DenseProtoTest /lib/cpp/test/EnumTest /lib/cpp/test/JSONProtoTest /lib/cpp/test/OptionalRequiredTest /lib/cpp/test/SecurityTest /lib/cpp/test/SpecializationTest /lib/cpp/test/RecursiveTest /lib/cpp/test/ReflectionTest /lib/cpp/test/RenderedDoubleConstantsTest /lib/cpp/test/TFDTransportTest /lib/cpp/test/TFileTransportTest /lib/cpp/test/TInterruptTest /lib/cpp/test/TNonblockingServerTest /lib/cpp/test/TNonblockingSSLServerTest /lib/cpp/test/TPipedTransportTest /lib/cpp/test/TServerIntegrationTest /lib/cpp/test/TSocketInterruptTest /lib/cpp/test/TransportTest /lib/cpp/test/UnitTests /lib/cpp/test/ZlibTest /lib/cpp/test/OpenSSLManualInitTest /lib/cpp/test/concurrency_test /lib/cpp/test/link_test /lib/cpp/test/processor_test /lib/cpp/test/tests.xml /lib/cpp/concurrency_test /lib/cpp/*.pc /lib/cpp/x64/Debug/ /lib/cpp/x64/Debug-mt/ /lib/cpp/x64/Release /lib/cpp/x64/Release-mt /lib/c_glib/*.gcda /lib/c_glib/*.gcno /lib/c_glib/*.loT /lib/c_glib/src/thrift/config.h /lib/c_glib/src/thrift/stamp-h3 /lib/c_glib/test/*.gcno /lib/c_glib/test/testwrapper.sh /lib/c_glib/test/testwrapper-test* /lib/c_glib/test/testapplicationexception /lib/c_glib/test/testbinaryprotocol /lib/c_glib/test/testcompactprotocol /lib/c_glib/test/testbufferedtransport /lib/c_glib/test/testcontainertest /lib/c_glib/test/testdebugproto /lib/c_glib/test/testfdtransport /lib/c_glib/test/testframedtransport /lib/c_glib/test/testmemorybuffer /lib/c_glib/test/testoptionalrequired /lib/c_glib/test/testtransportsslsocket /lib/c_glib/test/testsimpleserver /lib/c_glib/test/teststruct /lib/c_glib/test/testthrifttest /lib/c_glib/test/testthrifttestclient /lib/c_glib/test/testtransportsocket /lib/c_glib/test/testserialization /lib/c_glib/thriftc.pc /lib/c_glib/thrift_c_glib.pc /lib/d/test/*.pem /lib/d/libthriftd*.a /lib/d/test/async_test /lib/d/test/client_pool_test /lib/d/test/serialization_benchmark /lib/d/test/stress_test_server /lib/d/test/thrift_test_client /lib/d/test/thrift_test_server /lib/d/test/transport_test /lib/d/unittest/ /lib/dart/coverage /lib/dart/**/.dart_tool /lib/dart/**/.packages /lib/dart/**/packages /lib/dart/**/.pub/ /lib/dart/**/pubspec.lock /lib/delphi/*.local /lib/delphi/*.identcache /lib/delphi/test/skip/bin /lib/delphi/test/serializer/*.dat /lib/delphi/**/*.identcache /lib/delphi/**/*.local /lib/delphi/**/*.dcu /lib/delphi/**/*.2007 /lib/delphi/**/codegen/*.bat /lib/erl/_build/ /lib/erl/.eunit /lib/erl/.generated /lib/erl/.rebar/ /lib/erl/_build/ /lib/erl/ebin /lib/erl/rebar.lock /lib/erl/src/thrift.app.src /lib/erl/test/*.beam /lib/erl/test/*.hrl /lib/erl/test/Thrift_omit_without.thrift /lib/haxe/test/bin /lib/haxe/test/data.tmp /lib/hs/dist /lib/java/.gradle /lib/java/android/.gradle /lib/java/build /lib/java/out /lib/java/target /lib/js/dist /lib/js/doc /lib/js/test/build /lib/netstd/**/bin /lib/netstd/**/obj /lib/nodejs/coverage /lib/nodejs/node_modules/ /lib/perl/MANIFEST /lib/perl/MYMETA.json /lib/perl/MYMETA.yml /lib/perl/Makefile-perl.mk /lib/perl/blib /lib/perl/pm_to_blib /lib/py/build /lib/py/thrift.egg-info/ /lib/rb/Gemfile.lock /lib/rb/debug_proto_test /lib/rb/.config /lib/rb/ext/conftest.dSYM/ /lib/rb/ext/mkmf.log /lib/rb/ext/thrift_native.bundle /lib/rb/ext/thrift_native.so /lib/rb/test/ /lib/rb/thrift-*.gem /lib/php/src/ext/thrift_protocol/Makefile.* /lib/php/src/ext/thrift_protocol/build/ /lib/php/src/ext/thrift_protocol/config.* /lib/php/src/ext/thrift_protocol/configure /lib/php/src/ext/thrift_protocol/configure.ac /lib/php/src/ext/thrift_protocol/configure.in /lib/php/src/ext/thrift_protocol/install-sh /lib/php/src/ext/thrift_protocol/libtool /lib/php/src/ext/thrift_protocol/ltmain.sh /lib/php/src/ext/thrift_protocol/missing /lib/php/src/ext/thrift_protocol/mkinstalldirs /lib/php/src/ext/thrift_protocol/modules/ /lib/php/src/ext/thrift_protocol/php_thrift_protocol.lo /lib/php/src/ext/thrift_protocol/php_thrift_protocol.loT /lib/php/src/ext/thrift_protocol/run-tests.php /lib/php/src/ext/thrift_protocol/thrift_protocol.la /lib/php/src/ext/thrift_protocol/tmp-php.ini /lib/php/src/packages/ /lib/php/test/TEST-*.xml /lib/php/test/packages/ /lib/py/dist/ /lib/erl/logs/ /lib/go/pkg /lib/go/src /lib/go/test/fuzz/gopathfuzz /lib/go/test/gopath/ /lib/go/test/ThriftTest.thrift /lib/nodets/test-compiled/ /lib/ocaml/_build/ /lib/ocaml/_tags /lib/ocaml/configure /lib/ocaml/setup.data /lib/ocaml/setup.ml /lib/ocaml/myocamlbuild.ml /lib/ocaml/*/META /lib/ocaml/*/*.mllib /lib/ocaml/*/*.mldylib /lib/ocaml/Makefile /lib/ocaml/OCamlMakefile /lib/rs/target/ /lib/rs/Cargo.lock /lib/rs/test/Cargo.lock /lib/rs/test/target/ /lib/rs/test/bin/ /lib/rs/test/src/base_one.rs /lib/rs/test/src/base_two.rs /lib/rs/test/src/midlayer.rs /lib/rs/test/src/recursive.rs /lib/rs/test/src/ultimate.rs /lib/rs/test/src/identifiers.rs /lib/rs/test_recursive/Cargo.lock /lib/rs/test_recursive/src/vehicles.rs /lib/rs/test_recursive/src/maintenance/maintenance_facility.rs /lib/rs/test_recursive/src/transit/buses.rs /lib/rs/test_recursive/src/transit/trains.rs /lib/rs/test_recursive/src/transit/transporters.rs /lib/rs/test_recursive/src/transit/light/light_rail.rs /lib/rs/test_recursive/src/transit/light/streetcars.rs /lib/rs/test_recursive/src/transit/services/city_services.rs /lib/rs/test_recursive/target/ /lib/rs/test_recursive/bin/ /lib/rs/*.iml /lib/rs/**/*.iml /lib/swift/.build /lib/ts/test/build/ /lib/ts/test/gen-* /libtool /ltmain.sh /missing /node_modules/ /vendor/ /composer.lock /stamp-h1 /test/features/results.json /test/results.json /test/c_glib/test_client /test/c_glib/test_server /test/cl/TestServer /test/cl/TestClient /test/cpp/StressTest /test/cpp/StressTestNonBlocking /test/cpp/TestClient /test/cpp/TestServer /test/dart/**/.dart_tool /test/dart/**/.packages /test/dart/**/packages /test/dart/**/.pub/ /test/dart/**/pubspec.lock /test/log/ /test/test.log /test/erl/.generated /test/erl/.rebar /test/erl/ebin /test/erl/_build/ /test/erl/rebar.lock /test/go/bin/ /test/go/ThriftTest.thrift /test/go/gopath /test/go/pkg/ /test/go/src/code.google.com/ /test/go/src/common/mock_handler.go /test/go/src/github.com/golang/ /test/go/src/golang.org/ /test/go/src/gen/ /test/go/src/thrift /test/haxe/bin /test/haxe/.buildtemp /test/hs/TestClient /test/hs/TestServer /test/php/php_ext_dir/ /test/py.twisted/_trial_temp/ /test/rb/Gemfile.lock /test/netstd/**/bin /test/netstd/**/obj /test/netstd/**/launchSettings.json /test/netstd/*.psess /test/netstd/*.vspx /test/netstd/*.vsp /test/netstd/*.diagsession /test/netstd/Client/ThriftTest /test/netstd/Server/ThriftTest /test/netstd/Thrift /test/php/php_ext_dir/ /test/rs/Cargo.lock /test/rs/src/thrift_test.rs /test/rs/bin/ /test/rs/target/ /test/rs/*.iml /test/rs/**/*.iml /lib/cl/backport-update.zip /lib/cl/lib /tutorial/cl/quicklisp.lisp /tutorial/cl/externals/ /tutorial/cl/quicklisp/ /tutorial/cl/TutorialClient /tutorial/cl/TutorialServer /tutorial/cl/backport-update.zip /tutorial/cl/lib/ /tutorial/cl/shared-implementation.fasl /tutorial/cl/tutorial-implementation.fasl /tutorial/cpp/TutorialClient /tutorial/cpp/TutorialServer /tutorial/c_glib/tutorial_client /tutorial/c_glib/tutorial_server /tutorial/d/async_client /tutorial/d/client /tutorial/d/server /tutorial/dart/**/.packages /tutorial/dart/**/packages /tutorial/dart/**/.pub/ /tutorial/dart/**/pubspec.lock /tutorial/delphi/**/*.dsk /tutorial/delphi/**/*.local /tutorial/delphi/**/*.tvsconfig /tutorial/delphi/**/dcu /tutorial/delphi/**/*.local /tutorial/delphi/**/*.identcache /tutorial/go/gopath /tutorial/go/go-tutorial /tutorial/go/calculator-remote /tutorial/go/src/shared /tutorial/go/src/tutorial /tutorial/go/src/git.apache.org /tutorial/go/src/golang.org /tutorial/haxe/bin /tutorial/hs/dist/ /tutorial/java/build/ /tutorial/js/build/ /tutorial/netstd/**/bin /tutorial/netstd/**/obj /tutorial/netstd/Interfaces /tutorial/rs/*.iml /tutorial/rs/src/shared.rs /tutorial/rs/src/tutorial.rs /tutorial/rs/bin /tutorial/rs/target /tutorial/rs/Cargo.lock /tutorial/netstd/Interfaces/shared /tutorial/netstd/Interfaces/tutorial /tutorial/netstd/Server/Properties/launchSettings.json /tutorial/netstd/Client/Properties/launchSettings.json /ylwrap thrift-0.16.0/.travis.yml000066400000000000000000000122531420101504100151760ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # build Apache Thrift on Travis CI - https://travis-ci.org/ # # Docker Integration # see: build/docker/README.md # sudo: required dist: trusty language: cpp services: - docker install: - if [[ `uname` == "Linux" ]]; then build/docker/refresh.sh; fi stages: - docker # docker images - thrift # thrift build jobs env: global: - SCRIPT="cmake.sh" - BUILD_ARG="" - BUILD_ENV="-e CC=gcc -e CXX=g++ -e THRIFT_CROSSTEST_CONCURRENCY=4" - DISTRO=ubuntu-bionic - BUILD_LIBS="CPP C_GLIB JAVA PYTHON TESTING TUTORIALS" # only meaningful for CMake builds - TRAVIS_BUILD_STAGE=test # DOCKER_REPO (this works for all builds as a source for docker images - you can override for fork builds in your Travis settings) - DOCKER_REPO="thrift/thrift-build" # DOCKER_USER (provide in your Travis settings if you want to build and update docker images once, instead of on every job) # DOCKER_PASS (same) jobs: include: # ========================= stage: docker ========================= - stage: docker script: true env: - JOB="Docker Build ubuntu-xenial 16.04 LTS" - DISTRO=ubuntu-xenial - TRAVIS_BUILD_STAGE=docker - script: true env: - JOB="Docker Build ubuntu-bionic 18.04 LTS" - DISTRO=ubuntu-bionic - TRAVIS_BUILD_STAGE=docker # ========================= stage: thrift ======================= # ------------------------- phase: cross ------------------------ - stage: thrift script: build/docker/run.sh env: - JOB="Cross Language Tests (Binary Protocol)" - SCRIPT="cross-test.sh" - BUILD_ARG="-'(binary)'" - stage: thrift script: build/docker/run.sh env: - JOB="Cross Language Tests (Header, JSON Protocols)" - SCRIPT="cross-test.sh" - BUILD_ARG="-'(header|json)'" - stage: thrift script: build/docker/run.sh env: - JOB="Cross Language Tests (Compact and Multiplexed Protocols)" - SCRIPT="cross-test.sh" - BUILD_ARG="-'(compact|multiplexed)'" # ------------------------- phase: sca -------------------------- # QA jobs for code analytics and metrics - stage: thrift script: build/docker/run.sh env: - JOB="Static Code Analysis" - SCRIPT="sca.sh" # C and C++ undefined behavior. # A binary crashes if undefined behavior occurs and produces a stack trace. # python is disabled, see: THRIFT-4360 - script: build/docker/run.sh env: - JOB="UBSan" - SCRIPT="ubsan.sh" - BUILD_ARG="--without-python --without-py3" # ------------------------- phase: autotools -------------------- # TODO: Remove them once migrated to CMake - script: build/docker/run.sh env: - JOB="Autotools (Ubuntu Bionic)" - SCRIPT="autotools.sh" - script: build/docker/run.sh env: - JOB="Autotools (Ubuntu Xenial)" - DISTRO=ubuntu-xenial - SCRIPT="autotools.sh" # ------------------------- phase: cmake ------------------------ - script: build/docker/run.sh env: - JOB="CMake" - BUILD_ARG="-DCMAKE_BUILD_TYPE=Debug" - script: build/docker/run.sh env: - JOB="CMake" - BUILD_ARG="-DCMAKE_BUILD_TYPE=Release" # ------------------------- phase: dist ------------------------- - script: build/docker/run.sh env: - JOB="make dist" - SCRIPT="make-dist.sh" - script: build/docker/run.sh env: - JOB="Debian Packages" - SCRIPT="dpkg.sh" # ------------------------- phase: coverity --------------------- # We build the coverity scan build once monthly using a travis cron job - if: (env(COVERITY_SCAN_NOTIFICATION_EMAIL) IS present) AND (branch IN (master)) AND (type IN (cron)) script: build/docker/run.sh env: - JOB="Coverity Scan" - SCRIPT="covscan.sh" # ------------------------- phase: swift ------------------------ # We lint the podspec - os: osx osx_image: xcode11.3 language: swift script: - gem update cocoapods - pod lib lint --allow-warnings --swift-version=5.1 env: - JOB="pod lib lint" ### ------------------------- phase: osx -------------------------- # disabled due to the time delays it imposes on build jobs # - os: osx # osx_image: xcode9 # script: build/docker/scripts/autotools.sh thrift-0.16.0/ApacheThrift.nuspec000066400000000000000000000034321420101504100166450ustar00rootroot00000000000000 ApacheThrift 0.16.0 Apache Thrift 0.16.0 Apache Thrift Developers Apache Software Foundation Apache-2.0 http://thrift.apache.org/ true Apache Thrift .NET Library Contains runtime libraries from lib/netstd for netstandard2.0 framework development. Apache Thrift RPC thrift-0.16.0/CHANGES.md000066400000000000000000014076361420101504100144750ustar00rootroot00000000000000# Apache Thrift Changelog ## 0.16.0 ### Known Open Issues (Blocker or Critical) - [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++ library don't work with HTTP (csharp server, cpp client; need cross test enhancement) - [THRIFT-5468](https://issues.apache.org/jira/browse/THRIFT-5468) - Swift service generator doesn't support oneway ### Deprecated Languages - [THRIFT-5476](https://issues.apache.org/jira/browse/THRIFT-5476) - Deprecate Common Lisp support ### Breaking Changes - (none) ### C++ - [THRIFT-5187](https://issues.apache.org/jira/browse/THRIFT-5187) - Add support for Unix domain sockets on Windows 10 or later - [THRIFT-5418](https://issues.apache.org/jira/browse/THRIFT-5418) - C++ to_string and ostream operator not always generated - [THRIFT-5456](https://issues.apache.org/jira/browse/THRIFT-5456) - ServerSocket doesn't ignore SIGPIPE ### Common LISP - [THRIFT-5476](https://issues.apache.org/jira/browse/THRIFT-5476) - Deprecate Common Lisp support ### Erlang - [THRIFT-5471](https://issues.apache.org/jira/browse/THRIFT-5471) - Introduce delimiter and app_prefix options to erl generator ### Go - [THRIFT-5461](https://issues.apache.org/jira/browse/THRIFT-5461) - Invalid golang code generated for optional set with a default value - [THRIFT-5469](https://issues.apache.org/jira/browse/THRIFT-5469) - Go lib skip map value may cause stack overflow - [THRIFT-5490](https://issues.apache.org/jira/browse/THRIFT-5490) - Improve memory efficiency in go THeader implementation - [THRIFT-5509](https://issues.apache.org/jira/browse/THRIFT-5509) - Potential connection leaks caused by the connectivity check ### Haxe - [THRIFT-5470](https://issues.apache.org/jira/browse/THRIFT-5470) - Error: Constraint check failure for haxe.ds.ObjectMap.K ### Java - [THRIFT-5443](https://issues.apache.org/jira/browse/THRIFT-5443) - add support for partial deserialization of Thrift - [THRIFT-5486](https://issues.apache.org/jira/browse/THRIFT-5486) - fix issues found by spotbugs - [THRIFT-5512](https://issues.apache.org/jira/browse/THRIFT-5512) - Update java dependencies ### JavaScript - [THRIFT-5448](https://issues.apache.org/jira/browse/THRIFT-5448) - Wrong type mapping of thrift binary type ### netstd - [THRIFT-5401](https://issues.apache.org/jira/browse/THRIFT-5401) - MaxMessageSize reached exception thrown in TEndpointTransport - [THRIFT-5408](https://issues.apache.org/jira/browse/THRIFT-5408) - Support for deprecated methods (via annotation) - [THRIFT-5479](https://issues.apache.org/jira/browse/THRIFT-5479) - Add net 6 support - [THRIFT-5480](https://issues.apache.org/jira/browse/THRIFT-5480) - TThreadPoolAsyncServer using TFramedTransport mistakenly drops client - [THRIFT-5481](https://issues.apache.org/jira/browse/THRIFT-5481) - consolidate netstd server implementation details into one common model - [THRIFT-5500](https://issues.apache.org/jira/browse/THRIFT-5500) - Uncompilable code when .thrift struct 'System' exists - [THRIFT-5504](https://issues.apache.org/jira/browse/THRIFT-5504) - CA2254 Message template should be compile time constant ### Perl - [THRIFT-5055](https://issues.apache.org/jira/browse/THRIFT-5055) - Fix build-cpan-dist.sh to create a CPAN distribution correctly - [THRIFT-5416](https://issues.apache.org/jira/browse/THRIFT-5416) - Allow UDP Socket Client In Perl ### Python - [THRIFT-5454](https://issues.apache.org/jira/browse/THRIFT-5454) - Python TProcessPoolServer does not spawn expected number of worker processes - [THRIFT-5488](https://issues.apache.org/jira/browse/THRIFT-5488) - SystemError when using fast binary or compact protocol in python 3.10 ### Rust - [THRIFT-5452](https://issues.apache.org/jira/browse/THRIFT-5452) - Make server optional - [THRIFT-5457](https://issues.apache.org/jira/browse/THRIFT-5457) - Travis fails consistently on a Rust dependency ### Test Suite - [THRIFT-5450](https://issues.apache.org/jira/browse/THRIFT-5450) - AppVeyor CI does not run any MSVC tests? ## 0.15.0 ### Known Open Issues (Blocker or Critical) - [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++: library don't work with HTTP (csharp server, cpp client; need cross test enhancement) ### Removed Languages - [THRIFT-5229](https://issues.apache.org/jira/browse/THRIFT-5229) - ActionScript 3 support dropped - [THRIFT-5347](https://issues.apache.org/jira/browse/THRIFT-5347) - Haskell support dropped ### Breaking Changes - [THRIFT-5381](https://issues.apache.org/jira/browse/THRIFT-5381) - possible collisions at VOID type with some 3rd-party libraries on Haxe cpp targets - [THRIFT-5396](https://issues.apache.org/jira/browse/THRIFT-5396) - deprecate netstd "Async" method postfix - [THRIFT-5453](https://issues.apache.org/jira/browse/THRIFT-5453) - go: NewTSocketConf and NewTSSLSocketConf no longer return an error ### AS3 - [THRIFT-5229](https://issues.apache.org/jira/browse/THRIFT-5229) - Deprecate/remove ActionScript 3 support ### Build Process - [THRIFT-5334](https://issues.apache.org/jira/browse/THRIFT-5334) - version of thrift-maven-plugin is not sync with the main project - [THRIFT-5394](https://issues.apache.org/jira/browse/THRIFT-5394) - AppVeyor CI tries to download outdated cmake - [THRIFT-5429](https://issues.apache.org/jira/browse/THRIFT-5429) - build: autotools: add foreign to AM_INIT_AUTOMAKE ### C glib - [THRIFT-5244](https://issues.apache.org/jira/browse/THRIFT-5244) - Dynamic exception specifications are deprecated in C++11[-Wdeprecated] - [THRIFT-5265](https://issues.apache.org/jira/browse/THRIFT-5265) - Add the zlib transport to c_glib - [THRIFT-5399](https://issues.apache.org/jira/browse/THRIFT-5399) - Fix socket leak in abnormal situation - [THRIFT-5421](https://issues.apache.org/jira/browse/THRIFT-5421) - Fix the problem of incorrect setting of errno in some files ### C++ - [THRIFT-5341](https://issues.apache.org/jira/browse/THRIFT-5341) - Fix Old-Style-Cast, Missing override and Possible noexcept - [THRIFT-5342](https://issues.apache.org/jira/browse/THRIFT-5342) - Apply 'noexcept' attribute to Init/Copy/Move Constructors and Assignments - [THRIFT-5355](https://issues.apache.org/jira/browse/THRIFT-5355) - Do not rely on compiler and check boundaries ### D language - [THRIFT-4303](https://issues.apache.org/jira/browse/THRIFT-4303) - D deprecation warnings - [THRIFT-4979](https://issues.apache.org/jira/browse/THRIFT-4979) - Still D deprecation warnings about std.datetime.* in current master - [THRIFT-5376](https://issues.apache.org/jira/browse/THRIFT-5376) - Fix deprecation warnings in D library ### Dart - [THRIFT-5285](https://issues.apache.org/jira/browse/THRIFT-5285) - Update to dart 2, widen range on http package ### Delphi - [THRIFT-5350](https://issues.apache.org/jira/browse/THRIFT-5350) - 0.14.0 fails to build on non-x86 - [THRIFT-5438](https://issues.apache.org/jira/browse/THRIFT-5438) - Inconsistent handling of exceptions during message read vs. message write phase - [THRIFT-5384](https://issues.apache.org/jira/browse/THRIFT-5384) - Improved error message for HTTP transports - [THRIFT-5385](https://issues.apache.org/jira/browse/THRIFT-5385) - XML-HTTP client reports IsOpen=TRUE even if it is not - [THRIFT-5386](https://issues.apache.org/jira/browse/THRIFT-5386) - XML-HTTP client may throw "max message size reached" incorrectly - [THRIFT-5387](https://issues.apache.org/jira/browse/THRIFT-5387) - Improved and simplified Delphi test setup - [THRIFT-5390](https://issues.apache.org/jira/browse/THRIFT-5390) - Named Pipes transport hardening - [THRIFT-5428](https://issues.apache.org/jira/browse/THRIFT-5428) - Prevent costly reallocations to improve performance - [THRIFT-5437](https://issues.apache.org/jira/browse/THRIFT-5437) - Make TProtocolImpl CTOR virtual ### Documentation - [THRIFT-5332](https://issues.apache.org/jira/browse/THRIFT-5332) - Question: list all the reserved words in thrift doc - [THRIFT-5348](https://issues.apache.org/jira/browse/THRIFT-5348) - Update debian/copyright ### Erlang - [THRIFT-5377](https://issues.apache.org/jira/browse/THRIFT-5377) - Remove Erlang R16 support ### Go - [THRIFT-5337](https://issues.apache.org/jira/browse/THRIFT-5337) - Go set fields write improvement - [THRIFT-5353](https://issues.apache.org/jira/browse/THRIFT-5353) - Namespace from type is ignored in generated code - [THRIFT-5358](https://issues.apache.org/jira/browse/THRIFT-5358) - Add go.mod file(s) - [THRIFT-5369](https://issues.apache.org/jira/browse/THRIFT-5369) - Malformed payload can still cause huge allocations - [THRIFT-5389](https://issues.apache.org/jira/browse/THRIFT-5389) - Thrift compiler generates uncompilable go code around optional constants - [THRIFT-5404](https://issues.apache.org/jira/browse/THRIFT-5404) - TTransportException.Timeout would correctly return true when it's connect timeout during TSocket.Open call - [THRIFT-5447](https://issues.apache.org/jira/browse/THRIFT-5447) - Update supported Go versions before 0.15.0 release - [THRIFT-5453](https://issues.apache.org/jira/browse/THRIFT-5453) - go: NewTSocketConf should not call net.ResolveTCPAddr - [THRIFT-5459](https://issues.apache.org/jira/browse/THRIFT-5459) - Adding a new exception to an endpoint is kinda breaking in go - [THRIFT-5453](https://issues.apache.org/jira/browse/THRIFT-5453) - Defer DNS lookups from NewTSocketConf (without any timeout check) to TSocket.Open (subject to ConnectTimeout set in TConfiguration) - [THRIFT-5459](https://issues.apache.org/jira/browse/THRIFT-5459) - Client calls will return TApplicationException with MISSING_RESULT when the result is a struct but is unset, and no other error is known. ### Haskell - [THRIFT-5347](https://issues.apache.org/jira/browse/THRIFT-5347) - Deprecate Haskell bindings ### Haxe - [THRIFT-5370](https://issues.apache.org/jira/browse/THRIFT-5370) - Haxe 4 compatibility - [THRIFT-5381](https://issues.apache.org/jira/browse/THRIFT-5381) - possible collisions at VOID type with some 3rd-party libraries on Haxe cpp targets - [THRIFT-5393](https://issues.apache.org/jira/browse/THRIFT-5393) - Incorrect namespaces for included types - [THRIFT-3036](https://issues.apache.org/jira/browse/THRIFT-3036) - create official haxelib Thrift package - [THRIFT-5413](https://issues.apache.org/jira/browse/THRIFT-5413) - Int vs String in method get_size required by property size ### Java - [THRIFT-5375](https://issues.apache.org/jira/browse/THRIFT-5375) - Put org.apache.tomcat.embed:tomcat-embed-core into scope test - [THRIFT-5383](https://issues.apache.org/jira/browse/THRIFT-5383) - TJSONProtocol Java readString throws on bounds check - [THRIFT-5400](https://issues.apache.org/jira/browse/THRIFT-5400) - Java library does not export the .annotation package - [THRIFT-5425](https://issues.apache.org/jira/browse/THRIFT-5425) - Throw an exception when reading TSimpleJson in Java - [THRIFT-5430](https://issues.apache.org/jira/browse/THRIFT-5430) - FieldMetaData synchronized method can trigger deadlock during static class initialization in JVM native code - [THRIFT-5432](https://issues.apache.org/jira/browse/THRIFT-5432) - TSaslTransport throw TTransportException of MaxMessageSize reached - [THRIFT-5433](https://issues.apache.org/jira/browse/THRIFT-5433) - Add Counter To Thread Name of TThreadPoolServer ### JavaScript - [THRIFT-3508](https://issues.apache.org/jira/browse/THRIFT-3508) - JS:TS Generator set all fields of the struct as required ### Lua - [THRIFT-5417](https://issues.apache.org/jira/browse/THRIFT-5417) - Fix Lua compiler omitting default values in Lua service functions - [THRIFT-5439](https://issues.apache.org/jira/browse/THRIFT-5439) - Lua Generator does not support const i64 ### netstd - [THRIFT-5354](https://issues.apache.org/jira/browse/THRIFT-5354) - disable IDE0083 warning - [THRIFT-5382](https://issues.apache.org/jira/browse/THRIFT-5382) - Netstd default list/set enums values are generated incorrectly in some cases - [THRIFT-5395](https://issues.apache.org/jira/browse/THRIFT-5395) - inconsistent treatment of methods ending in "Async" - [THRIFT-5396](https://issues.apache.org/jira/browse/THRIFT-5396) - deprecate "Async" method postfix - [THRIFT-5408](https://issues.apache.org/jira/browse/THRIFT-5408) - Support for deprecated methods (via annotation) - [THRIFT-5414](https://issues.apache.org/jira/browse/THRIFT-5414) - Use of specific parameter names generates uncompileable code - [THRIFT-5442](https://issues.apache.org/jira/browse/THRIFT-5442) - Separate client service calls into send/recv methods and make them public - [THRIFT-5444](https://issues.apache.org/jira/browse/THRIFT-5444) - Netstd generator produces uncompileable code for enums ending with "_result" or "_args" - [THRIFT-5445](https://issues.apache.org/jira/browse/THRIFT-5445) - "cancellationToken" cannot be used as argument name - [THRIFT-5236](https://issues.apache.org/jira/browse/THRIFT-5236) - THttpTransport.cs still has bad timeout code - [THRIFT-5349](https://issues.apache.org/jira/browse/THRIFT-5349) - Add net5.0 as supported platform - [THRIFT-5373](https://issues.apache.org/jira/browse/THRIFT-5373) - HTTP status in case of Protocol/Transport exceptions - [THRIFT-5391](https://issues.apache.org/jira/browse/THRIFT-5391) - Named pipes transport hardening - [THRIFT-5398](https://issues.apache.org/jira/browse/THRIFT-5398) - ThreadPoolServer not stoppable via CancellationToken - [THRIFT-5407](https://issues.apache.org/jira/browse/THRIFT-5407) - Keep support for .NET Core 3.1 - [THRIFT-5419](https://issues.apache.org/jira/browse/THRIFT-5419) - Incorrect usage of thread pool in TThreadPoolAsyncServer may lead to poor performance - [THRIFT-5422](https://issues.apache.org/jira/browse/THRIFT-5422) - add threadpool server to netstd test suite impl - [THRIFT-5431](https://issues.apache.org/jira/browse/THRIFT-5431) - Response should include 'content-type' header - [THRIFT-5436](https://issues.apache.org/jira/browse/THRIFT-5436) - Timeout.Infinite is not a good default ### PHP - [THRIFT-5318](https://issues.apache.org/jira/browse/THRIFT-5318) - PHP 8 compatible version of binary protocol - [THRIFT-5440](https://issues.apache.org/jira/browse/THRIFT-5440) - Add php8 to composer.json ### Python - [THRIFT-5352](https://issues.apache.org/jira/browse/THRIFT-5352) - Python: IDL exceptions with no fields can't be instantiated ### Ruby - [THRIFT-5312](https://issues.apache.org/jira/browse/THRIFT-5312) - The Ruby compilation configuration in the .gemspec file is modified to be compatible with later bundler versions. - [THRIFT-5367](https://issues.apache.org/jira/browse/THRIFT-5367) - Ruby library crashes when using GC.compact ### Rust - [THRIFT-4098](https://issues.apache.org/jira/browse/THRIFT-4098) - Support user-defined output namespaces in generated Rust modules - [THRIFT-4101](https://issues.apache.org/jira/browse/THRIFT-4101) - Make auto-generated Rust enums and unions more user-extensible - [THRIFT-5314](https://issues.apache.org/jira/browse/THRIFT-5314) - Enum forward compatibility - [THRIFT-5363](https://issues.apache.org/jira/browse/THRIFT-5363) - All-caps constant rendered incorrectly ## 0.14.2 ### Java - [THRIFT-5383](https://issues.apache.org/jira/browse/THRIFT-5383) - THRIFT-5383 TJSONProtocol Java readString throws on bounds check ### Go - [THRIFT-5369](https://issues.apache.org/jira/browse/THRIFT-5369) - TConfiguration.GetMaxMessageSize() now also applies to container sizes in TProtocol implementations provided ## 0.14.1 ### Known Open Issues (Blocker or Critical) - [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++: library don't work with HTTP (csharp server, cpp client; need cross test enhancement) - [THRIFT-5098](https://issues.apache.org/jira/browse/THRIFT-5098) - Deprecated: "The high level Network interface is no longer supported. Please use Network.Socket." and other Haskell issues - [THRIFT-5245](https://issues.apache.org/jira/browse/THRIFT-5245) - NPE when the value of map's key is null ### Deprecated Languages - [THRIFT-5347](https://issues.apache.org/jira/browse/THRIFT-5347) - Deprecate Haskell bindings ### Build Process - [THRIFT-5334](https://issues.apache.org/jira/browse/THRIFT-5334) - version of thrift-maven-plugin is not sync with the main project ### Delphi - [THRIFT-5350](https://issues.apache.org/jira/browse/THRIFT-5350) - 0.14.0 fails to build on non-x86 ### Go - [THRIFT-5353](https://issues.apache.org/jira/browse/THRIFT-5353) - Namespace from type is ignored in generated code ### Python - [THRIFT-5352](https://issues.apache.org/jira/browse/THRIFT-5352) - Python: IDL exceptions with no fields can't be instantiated ### Rust - [THRIFT-5299](https://issues.apache.org/jira/browse/THRIFT-5299) - rs implementation compact protocol seq_id should not use zigzag encoding. ## 0.14.0 ### Deprecated Languages - [THRIFT-5229](https://issues.apache.org/jira/browse/THRIFT-5229) - Deprecate ActionScript 3 support ### Removed Languages - [THRIFT-4980](https://issues.apache.org/jira/browse/THRIFT-4980) - Remove deprecated C# and netcore bindings from the code base - [THRIFT-4981](https://issues.apache.org/jira/browse/THRIFT-4981) - Remove deprecated netcore bindings from the code base - [THRIFT-4982](https://issues.apache.org/jira/browse/THRIFT-4982) - Remove deprecated C# bindings from the code base ### Breaking Changes - [THRIFT-4981](https://issues.apache.org/jira/browse/THRIFT-4981) - Remove deprecated netcore bindings from the code base - [THRIFT-4982](https://issues.apache.org/jira/browse/THRIFT-4982) - Remove deprecated csharp bindings from the code base - [THRIFT-4990](https://issues.apache.org/jira/browse/THRIFT-4990) - Upgrade to .NET Core 3.1 (LTS) - [THRIFT-5006](https://issues.apache.org/jira/browse/THRIFT-5006) - Implement DEFAULT_MAX_LENGTH at TFramedTransport - [THRIFT-5069](https://issues.apache.org/jira/browse/THRIFT-5069) - In Go library TDeserializer.Transport is now typed \*TMemoryBuffer instead of TTransport - [THRIFT-5072](https://issues.apache.org/jira/browse/THRIFT-5072) - Haskell generator fails to distinguish between multiple enum types with conflicting enum identifiers - [THRIFT-5116](https://issues.apache.org/jira/browse/THRIFT-5116) - Upgrade NodeJS to 10.x - [THRIFT-5138](https://issues.apache.org/jira/browse/THRIFT-5138) - Swift generator does not escape keywords properly - [THRIFT-5164](https://issues.apache.org/jira/browse/THRIFT-5164) - In Go library TProcessor interface now includes ProcessorMap and AddToProcessorMap functions. - [THRIFT-5186](https://issues.apache.org/jira/browse/THRIFT-5186) - cpp: use all getaddrinfo() results when retrying failed bind() in T{Nonblocking,}ServerSocket - [THRIFT-5233](https://issues.apache.org/jira/browse/THRIFT-5233) - go: Now all Read*, Write* and Skip functions in TProtocol accept context arg - [THRIFT-5152](https://issues.apache.org/jira/browse/THRIFT-5152) - go: TSocket and TSSLSocket now have separated connect timeout and socket timeout - c++: dropped support for Windows XP - [THRIFT-5326](https://issues.apache.org/jira/browse/THRIFT-5326) - go: TException interface now has a new function: TExceptionType - [THRIFT-4914](https://issues.apache.org/jira/browse/THRIFT-4914) - go: TClient.Call now returns ResponseMeta in addition to error ### Known Open Issues (Blocker or Critical) - [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++: library don't work with HTTP (csharp server, cpp client; need cross test enhancement) - [THRIFT-5098](https://issues.apache.org/jira/browse/THRIFT-5098) - Deprecated: "The high level Network interface is no longer supported. Please use Network.Socket." and other Haskell issues - [THRIFT-5245](https://issues.apache.org/jira/browse/THRIFT-5245) - NPE when the value of map's key is null - [THRIFT-4687](https://issues.apache.org/jira/browse/THRIFT-4687) - Add thrift 0.12.0 to pypi and/or enable more maintainers ### Build Process - [THRIFT-4976](https://issues.apache.org/jira/browse/THRIFT-4976) - Docker build: Test failure for `StalenessCheckTest` on MacOS - [THRIFT-5087](https://issues.apache.org/jira/browse/THRIFT-5087) - test/test.py fails with "AssertionError: Python 3.3 or later is required for proper operation." - [THRIFT-5097](https://issues.apache.org/jira/browse/THRIFT-5097) - Incorrect THRIFT_VERSION in ThriftConfig.cmake - [THRIFT-5109](https://issues.apache.org/jira/browse/THRIFT-5109) - Misc CMake improvements - [THRIFT-5147](https://issues.apache.org/jira/browse/THRIFT-5147) - Add uninstall function - [THRIFT-5218](https://issues.apache.org/jira/browse/THRIFT-5218) - Automated Github release artifacts do not match checksums provided - [THRIFT-5249](https://issues.apache.org/jira/browse/THRIFT-5249) - travis-ci : Failed to run FastbinaryTest.py ### C glib - [THRIFT-4873](https://issues.apache.org/jira/browse/THRIFT-4873) - Memory leak in c_glib - [THRIFT-5118](https://issues.apache.org/jira/browse/THRIFT-5118) - Fix memory leak when the handler method return a exception - [THRIFT-5134](https://issues.apache.org/jira/browse/THRIFT-5134) - Fix memory leak when the handler method return FALSE - [THRIFT-5144](https://issues.apache.org/jira/browse/THRIFT-5144) - Fix memory leak when generate deserialize list element - [THRIFT-4272](https://issues.apache.org/jira/browse/THRIFT-4272) - warnings in glibc library - [THRIFT-4952](https://issues.apache.org/jira/browse/THRIFT-4952) - Modified ssl_read feedback value break all the time error. - [THRIFT-5076](https://issues.apache.org/jira/browse/THRIFT-5076) - Improve CMake OpenSSL usage - [THRIFT-5094](https://issues.apache.org/jira/browse/THRIFT-5094) - Fix memory leak in thrift_server_set_property() - [THRIFT-5101](https://issues.apache.org/jira/browse/THRIFT-5101) - Return NULL install of FALSE for thrift_server_socket_accept() - [THRIFT-5102](https://issues.apache.org/jira/browse/THRIFT-5102) - Fix memory leak in thrift_simple_server_serve() - [THRIFT-5136](https://issues.apache.org/jira/browse/THRIFT-5136) - Fix memory leak in thrift_multiplexed_processor_process_impl() - [THRIFT-5221](https://issues.apache.org/jira/browse/THRIFT-5221) - Fix stack overflow when reading buffer - [THRIFT-5237](https://issues.apache.org/jira/browse/THRIFT-5237) - Implement MAX_MESSAGE_SIZE and consolidate limits into a TConfiguration class - [THRIFT-5255](https://issues.apache.org/jira/browse/THRIFT-5255) - Fix stack overflow in framed transport - [THRIFT-5256](https://issues.apache.org/jira/browse/THRIFT-5256) - Fix some compile warnings - [THRIFT-5268](https://issues.apache.org/jira/browse/THRIFT-5268) - Fix some file loss ')' in define ### C++ - [THRIFT-1513](https://issues.apache.org/jira/browse/THRIFT-1513) - Thrift compiler generates inconsistent code with some complex values (causing g++ to error: "has no member named '__isset') - [THRIFT-5168](https://issues.apache.org/jira/browse/THRIFT-5168) - Useless generated code when .thrift file only has service type - [THRIFT-5179](https://issues.apache.org/jira/browse/THRIFT-5179) - Thrift compiler will generate wrong code if IDL struct's name is 'a' or 'b' - [THRIFT-5200](https://issues.apache.org/jira/browse/THRIFT-5200) - Thrift compiler will generate incorrect code when add 'cob_style' option. - [THRIFT-4282](https://issues.apache.org/jira/browse/THRIFT-4282) - StressTestNonBlocking is disabled in Appveyor as it is unstable on Windows in general - [THRIFT-4682](https://issues.apache.org/jira/browse/THRIFT-4682) - C++ TBinaryProtocol crashes on port scan - [THRIFT-4963](https://issues.apache.org/jira/browse/THRIFT-4963) - TNonblockingServer blocked int addTask(IOThread) and notify(workerThread) - [THRIFT-5047](https://issues.apache.org/jira/browse/THRIFT-5047) - fix cmake support to build cpp server without OPENSSL - [THRIFT-5076](https://issues.apache.org/jira/browse/THRIFT-5076) - Improve CMake OpenSSL usage - [THRIFT-5078](https://issues.apache.org/jira/browse/THRIFT-5078) - Handle named pipe clients quickly disconnecting - [THRIFT-5086](https://issues.apache.org/jira/browse/THRIFT-5086) - CMake target thrift::thrift has no INTERFACE_INCLUDE_DIRECTORIES property - [THRIFT-5110](https://issues.apache.org/jira/browse/THRIFT-5110) - Added a number of required libs for using static OpenSSL - [THRIFT-5114](https://issues.apache.org/jira/browse/THRIFT-5114) - Simplify the computation of the size of TMemoryBuffer - [THRIFT-5177](https://issues.apache.org/jira/browse/THRIFT-5177) - getaddrinfo() should not be used for Unix sockets - [THRIFT-5178](https://issues.apache.org/jira/browse/THRIFT-5178) - THttpClient should work without specifying host - [THRIFT-5185](https://issues.apache.org/jira/browse/THRIFT-5185) - C++: Add WebSocket Server Transport - [THRIFT-5186](https://issues.apache.org/jira/browse/THRIFT-5186) - AI_ADDRCONFIG: Thrift libraries crash with localhost-only network. - [THRIFT-5215](https://issues.apache.org/jira/browse/THRIFT-5215) - C++: Remove portable_endian.h - [THRIFT-5217](https://issues.apache.org/jira/browse/THRIFT-5217) - Deprecated boost header - [THRIFT-5237](https://issues.apache.org/jira/browse/THRIFT-5237) - Implement MAX_MESSAGE_SIZE and consolidate limits into a TConfiguration class - [THRIFT-5290](https://issues.apache.org/jira/browse/THRIFT-5290) - Adjusting cpp *.cproj msvcrt options according to LEGAL-538 - [THRIFT-5295](https://issues.apache.org/jira/browse/THRIFT-5295) - Thread and ThreadFactory should be extensible - [THRIFT-5344](https://issues.apache.org/jira/browse/THRIFT-5344) - TTransport may throw raw pointer exceptions ### Compiler (General) - [THRIFT-4173](https://issues.apache.org/jira/browse/THRIFT-4173) - Go: thrift compiler generates wrong code for list of aliased type - [THRIFT-4938](https://issues.apache.org/jira/browse/THRIFT-4938) - Issues with version.h treatment - [THRIFT-4973](https://issues.apache.org/jira/browse/THRIFT-4973) - Add deprecation messages for csharp and netcore - [THRIFT-4980](https://issues.apache.org/jira/browse/THRIFT-4980) - Remove deprecated C# and netcore bindings from the code base - [THRIFT-4982](https://issues.apache.org/jira/browse/THRIFT-4982) - Remove deprecated C# bindings from the code baseï…‚ - [THRIFT-5153](https://issues.apache.org/jira/browse/THRIFT-5153) - Deprecate byte - [THRIFT-5225](https://issues.apache.org/jira/browse/THRIFT-5225) - Use nullptr instead of NULL - [THRIFT-5302](https://issues.apache.org/jira/browse/THRIFT-5302) - Add recursive function name uniqueness check ### D - [THRIFT-5059](https://issues.apache.org/jira/browse/THRIFT-5059) - Add cross tests for TZlibTransport in D - [THRIFT-5156](https://issues.apache.org/jira/browse/THRIFT-5156) - D: Fix library compilation on Windows and compiler warnings - [THRIFT-5166](https://issues.apache.org/jira/browse/THRIFT-5166) - Add WebSocket Server Transport - [THRIFT-5184](https://issues.apache.org/jira/browse/THRIFT-5184) - D: WebSocket Server Transport Fix for Firefox ### Delphi - [THRIFT-5044](https://issues.apache.org/jira/browse/THRIFT-5044) - Improve serialization support for TApplicationExceptions and custom exceptions - [THRIFT-5154](https://issues.apache.org/jira/browse/THRIFT-5154) - Generate interface IDs (IID) for Windows platforms - [THRIFT-5235](https://issues.apache.org/jira/browse/THRIFT-5235) - Add property setter for isset flags - [THRIFT-5261](https://issues.apache.org/jira/browse/THRIFT-5261) - Support for deprecated methods (via annotation) - [THRIFT-5004](https://issues.apache.org/jira/browse/THRIFT-5004) - Make exception implementations more consistent - [THRIFT-5005](https://issues.apache.org/jira/browse/THRIFT-5005) - Refactoring of the Delphi libs - [THRIFT-5006](https://issues.apache.org/jira/browse/THRIFT-5006) - Implement DEFAULT_MAX_LENGTH at TFramedTransport - [THRIFT-5007](https://issues.apache.org/jira/browse/THRIFT-5007) - Implement MAX_MESSAGE_SIZE and remaining read bytes control - [THRIFT-5009](https://issues.apache.org/jira/browse/THRIFT-5009) - Serializer implemtation lacks support for layered transports - [THRIFT-5012](https://issues.apache.org/jira/browse/THRIFT-5012) - Centralize configuration aspects into a commonly used configuration object - [THRIFT-5015](https://issues.apache.org/jira/browse/THRIFT-5015) - WinHTTP QueryDataAvailable cannot be used to retrieve total response size - [THRIFT-5036](https://issues.apache.org/jira/browse/THRIFT-5036) - buffered transport over sockets may run into unexpected timeouts - [THRIFT-5048](https://issues.apache.org/jira/browse/THRIFT-5048) - EnumUtils.ToString() throws for elements not known to the receiving end - [THRIFT-5088](https://issues.apache.org/jira/browse/THRIFT-5088) - Memory leak in TEndpointTransportBase - [THRIFT-5123](https://issues.apache.org/jira/browse/THRIFT-5123) - add possibility to query HTTP status code with WinHTTP - [THRIFT-5146](https://issues.apache.org/jira/browse/THRIFT-5146) - Align Delphi to the test suite arguments rules (its "--switch=value", not "--switch value") - [THRIFT-5186](https://issues.apache.org/jira/browse/THRIFT-5186) - AI_ADDRCONFIG: Thrift libraries crash with localhost-only network. - [THRIFT-5188](https://issues.apache.org/jira/browse/THRIFT-5188) - Occasional ERROR_INSUFFICIENT_BUFFER at WinHttpQueryHeaders() - [THRIFT-5251](https://issues.apache.org/jira/browse/THRIFT-5251) - StringUtils.ToString() raises an exception for enum values outside range - [THRIFT-5304](https://issues.apache.org/jira/browse/THRIFT-5304) - TWinHTTPClientImpl may incorrectly report that the message size is reached ### Documentation - [THRIFT-5037](https://issues.apache.org/jira/browse/THRIFT-5037) - Documentation for TConfiguration - [THRIFT-5065](https://issues.apache.org/jira/browse/THRIFT-5065) - Fix broken links in the IDL document - [THRIFT-5074](https://issues.apache.org/jira/browse/THRIFT-5074) - Cleanup test suite command line options ### Go - [THRIFT-4914](https://issues.apache.org/jira/browse/THRIFT-4914) - Compiler generated service clients now provide a new function, LastResponseMeta_(), to get the response metadata (e.g. headers from THeader) from the last client call. - [THRIFT-4984](https://issues.apache.org/jira/browse/THRIFT-4984) - Scary and spammy "error processing request: EOF" logs from TSimpleServer - [THRIFT-4985](https://issues.apache.org/jira/browse/THRIFT-4985) - Clean up logging in go library - [THRIFT-5002](https://issues.apache.org/jira/browse/THRIFT-5002) - remote client fails to compile when extending services - [THRIFT-5019](https://issues.apache.org/jira/browse/THRIFT-5019) - Multiple import same namespace for go included files - [THRIFT-5046](https://issues.apache.org/jira/browse/THRIFT-5046) - Custom tags remove db and json tags - [THRIFT-5069](https://issues.apache.org/jira/browse/THRIFT-5069) - Add TSerializerPool and TDeserializerPool, which are thread-safe versions of TSerializer and TDeserializer. - [THRIFT-5092](https://issues.apache.org/jira/browse/THRIFT-5092) - Panic on nil buffer writes - [THRIFT-5152](https://issues.apache.org/jira/browse/THRIFT-5152) - Separate timeout in TSocket - [THRIFT-5164](https://issues.apache.org/jira/browse/THRIFT-5164) - Go middleware support - [THRIFT-5214](https://issues.apache.org/jira/browse/THRIFT-5214) - go: Implement connection check in TSocket - [THRIFT-5233](https://issues.apache.org/jira/browse/THRIFT-5233) - I/O timeout handling in go library - [THRIFT-5240](https://issues.apache.org/jira/browse/THRIFT-5240) - The context passed into server handler implementations will be canceled when we detected that the client closed the connection. - [THRIFT-5257](https://issues.apache.org/jira/browse/THRIFT-5257) - Go THeader implementation doesn't handle endOfFrame correctly - [THRIFT-5270](https://issues.apache.org/jira/browse/THRIFT-5270) - Go library unit test is broken in go 1.15 - [THRIFT-5278](https://issues.apache.org/jira/browse/THRIFT-5278) - Expose API to use THeader+TCompactProtocol in go library client code - [THRIFT-5279](https://issues.apache.org/jira/browse/THRIFT-5279) - Cleanups/small optimizations for go's serializer/deserializer code - [THRIFT-5294](https://issues.apache.org/jira/browse/THRIFT-5294) - Go: TSimpleJSONProtocol could panic on WriteMessageEnd without matching WriteMessageBegin - [THRIFT-5322](https://issues.apache.org/jira/browse/THRIFT-5322) - Add support to TConfiguration, and also fix a bug that could cause excessive memory usage when reading malformed messages from TCompactProtocol. - [THRIFT-5338](https://issues.apache.org/jira/browse/THRIFT-5338) - Proposal: Raise minimal supported Go version with upcoming 0.14.0 release ### Haskell - [THRIFT-5072](https://issues.apache.org/jira/browse/THRIFT-5072) - Haskell generator fails to distinguish between multiple enum types with conflicting enum identifiers - [THRIFT-4959](https://issues.apache.org/jira/browse/THRIFT-4959) - cabal.exe: --enable-tests was specified, but tests can't be enabled in a remote package - [THRIFT-5211](https://issues.apache.org/jira/browse/THRIFT-5211) - Handle incomplete reads correctly ### Java - [THRIFT-4252](https://issues.apache.org/jira/browse/THRIFT-4252) - Cannot shutdown Java server when clients are still connected - [THRIFT-4889](https://issues.apache.org/jira/browse/THRIFT-4889) - Add SASL support for non-blocking server - [THRIFT-4937](https://issues.apache.org/jira/browse/THRIFT-4937) - Apache HttpCore 4.4.1 reached EoS - [THRIFT-4949](https://issues.apache.org/jira/browse/THRIFT-4949) - improve HTTP/1 server test case - [THRIFT-5008](https://issues.apache.org/jira/browse/THRIFT-5008) - Add a logger line in case of failing to dispose sasl - [THRIFT-5013](https://issues.apache.org/jira/browse/THRIFT-5013) - Use Java Objects RequireNonNull - [THRIFT-5016](https://issues.apache.org/jira/browse/THRIFT-5016) - Do Not Check 'other' For Null in Equals - [THRIFT-5022](https://issues.apache.org/jira/browse/THRIFT-5022) - TIOStreamTransport.isOpen returns true for one-sided transports (see THRIFT-2530). - [THRIFT-5031](https://issues.apache.org/jira/browse/THRIFT-5031) - Fix javadoc of TIOStreamTransport - [THRIFT-5115](https://issues.apache.org/jira/browse/THRIFT-5115) - PR #2022 Updated gradle to 6.2 broke CI - [THRIFT-5190](https://issues.apache.org/jira/browse/THRIFT-5190) - StringUtils haven't take `(offset + length) > bytes.length` into account - [THRIFT-5197](https://issues.apache.org/jira/browse/THRIFT-5197) - TSSLTransportFactory Do Not Wrap NOT_OPEN Exception Type for Client - [THRIFT-5201](https://issues.apache.org/jira/browse/THRIFT-5201) - Use Apache Parent Pom for Thrift Maven Plugin - [THRIFT-5202](https://issues.apache.org/jira/browse/THRIFT-5202) - TNonblockingMultiFetchClient Use SLF4J Parameterized Logging - [THRIFT-5203](https://issues.apache.org/jira/browse/THRIFT-5203) - Remove Unused toString Method in TSerializer - [THRIFT-5237](https://issues.apache.org/jira/browse/THRIFT-5237) - Implement MAX_MESSAGE_SIZE and consolidate limits into a TConfiguration class - [THRIFT-5247](https://issues.apache.org/jira/browse/THRIFT-5247) - Avoiding meaningless System.copy - [THRIFT-5274](https://issues.apache.org/jira/browse/THRIFT-5274) - Thrift 0.13.0 does not work with JDK8 - [THRIFT-5287](https://issues.apache.org/jira/browse/THRIFT-5287) - Log When Client Connections are Dropped - [THRIFT-5288](https://issues.apache.org/jira/browse/THRIFT-5288) - Move Support for ByteBuffer into TTransport ### JavaScript - [THRIFT-5234](https://issues.apache.org/jira/browse/THRIFT-5234) - Fix a number of js/ts generation issues ### Lua - [THRIFT-5106](https://issues.apache.org/jira/browse/THRIFT-5106) - Fix various Lua library and compiler issues - [THRIFT-5260](https://issues.apache.org/jira/browse/THRIFT-5260) - Fix the thrift compiler generate problematic lua code for the oneway method - [THRIFT-4992](https://issues.apache.org/jira/browse/THRIFT-4992) - thrift lua TcompactProtocol bug fix #1881 - [THRIFT-5262](https://issues.apache.org/jira/browse/THRIFT-5262) - Fix a encoding struct bug in the compact protocol implementation to lua - [THRIFT-5282](https://issues.apache.org/jira/browse/THRIFT-5282) - Add IPv6 client support to Lua library - [THRIFT-5286](https://issues.apache.org/jira/browse/THRIFT-5286) - Fix Lua library readBool() in TCompactProtocol - [THRIFT-5325](https://issues.apache.org/jira/browse/THRIFT-5325) - Fix Lua library writeStructEnd() in TCompactProtocol ### Markdown - [THRIFT-5289](https://issues.apache.org/jira/browse/THRIFT-5289) - Add markdown compiler ### netstd - [THRIFT-5032](https://issues.apache.org/jira/browse/THRIFT-5032) - Allows PascalCase properties for netstd - [THRIFT-5091](https://issues.apache.org/jira/browse/THRIFT-5091) - Netstd generator produces uncompileable code for struct names ending with "_result" or "_args" - [THRIFT-5095](https://issues.apache.org/jira/browse/THRIFT-5095) - ToString() should print entire structure, not just the top-level data - [THRIFT-5198](https://issues.apache.org/jira/browse/THRIFT-5198) - Fix certain Visual Studio hints in generated netstd code - [THRIFT-5216](https://issues.apache.org/jira/browse/THRIFT-5216) - generate DeepCopy methods - [THRIFT-5220](https://issues.apache.org/jira/browse/THRIFT-5220) - DeepCopy() extension methods not generated when the IDL contains no service - [THRIFT-5238](https://issues.apache.org/jira/browse/THRIFT-5238) - GetHashCode can throw NullReferenceException - [THRIFT-5253](https://issues.apache.org/jira/browse/THRIFT-5253) - using Result in result name generates wrong IAsync interface - [THRIFT-5254](https://issues.apache.org/jira/browse/THRIFT-5254) - Member name cannot be Isset (unless it is an "required" member) - [THRIFT-5316](https://issues.apache.org/jira/browse/THRIFT-5316) - Netstd compiler generates wrong ToString() method: .ToString(sb) - [THRIFT-5317](https://issues.apache.org/jira/browse/THRIFT-5317) - netstd compiler does not escape keywords - [THRIFT-5320](https://issues.apache.org/jira/browse/THRIFT-5320) - Usage of "Task" as IDL identifier generates uncompileable code - [THRIFT-4990](https://issues.apache.org/jira/browse/THRIFT-4990) - Upgrade to .NET Core 3.1 (LTS) - [THRIFT-5010](https://issues.apache.org/jira/browse/THRIFT-5010) - BinaryPrimitives.Read/WriteInt32BigEndian should be used to convert to/from network byte order - [THRIFT-5020](https://issues.apache.org/jira/browse/THRIFT-5020) - Refactoring & minor fixes for netstd library - [THRIFT-5021](https://issues.apache.org/jira/browse/THRIFT-5021) - Implement MAX_MESSAGE_SIZE and consolidate limits into a TConfiguration class - [THRIFT-5026](https://issues.apache.org/jira/browse/THRIFT-5026) - TestClient/Server ignores first cmdline argument - [THRIFT-5027](https://issues.apache.org/jira/browse/THRIFT-5027) - Implement remaining read bytes checks - [THRIFT-5053](https://issues.apache.org/jira/browse/THRIFT-5053) - Fix the netstd tutorial console logging and README - [THRIFT-5083](https://issues.apache.org/jira/browse/THRIFT-5083) - NetStd JSON Protocol left in incorrect state - [THRIFT-5133](https://issues.apache.org/jira/browse/THRIFT-5133) - TCompactProtocol string allocation improvement - [THRIFT-5172](https://issues.apache.org/jira/browse/THRIFT-5172) - NetStd TBaseClient open output transport multiple times - [THRIFT-5210](https://issues.apache.org/jira/browse/THRIFT-5210) - further performance optimizations - [THRIFT-5239](https://issues.apache.org/jira/browse/THRIFT-5239) - THttpTransport should support passing in an HttpClient - [THRIFT-5252](https://issues.apache.org/jira/browse/THRIFT-5252) - Make CreateHttpClientHandler() method virtual - [THRIFT-5275](https://issues.apache.org/jira/browse/THRIFT-5275) - Compilation error with Thrift when used in .Net Framework 4.6.1 or above - [THRIFT-5343](https://issues.apache.org/jira/browse/THRIFT-5343) - TTlsSocketTransport does not resolve IPv4 addresses or validate hostnames correctly ### Node.js - [THRIFT-3356](https://issues.apache.org/jira/browse/THRIFT-3356) - TypeError: 'undefined' is not a function (evaluating 'Error.captureStackTrace(this, this.constructor)') - [THRIFT-4994](https://issues.apache.org/jira/browse/THRIFT-4994) - TWebSocketTransport false scope in forEach in browser - [THRIFT-5003](https://issues.apache.org/jira/browse/THRIFT-5003) - Websocket Connection in Browsers with nodejs code - [THRIFT-5116](https://issues.apache.org/jira/browse/THRIFT-5116) - Ubuntu xenial NodeJS 6.x is too old, 10.x required - [THRIFT-5163](https://issues.apache.org/jira/browse/THRIFT-5163) - adds Q to exports for browserify ### Perl - [THRIFT-5050](https://issues.apache.org/jira/browse/THRIFT-5050) - Fix MemoryBuffer.pm to raise a proper exception if no data is available - [THRIFT-5066](https://issues.apache.org/jira/browse/THRIFT-5066) - Implement testBinary invocation in TestClient.pl ### PHP - [THRIFT-4942](https://issues.apache.org/jira/browse/THRIFT-4942) - Set PHP struct generated field values as private with getters and setters - [THRIFT-5082](https://issues.apache.org/jira/browse/THRIFT-5082) - Add a Class reference for PHP enum $_TSPEC - [THRIFT-5103](https://issues.apache.org/jira/browse/THRIFT-5103) - PHP 7.4 THttpClient deprecated error - [THRIFT-5130](https://issues.apache.org/jira/browse/THRIFT-5130) - Use Apcu instead of APC - [THRIFT-5132](https://issues.apache.org/jira/browse/THRIFT-5132) - Warning in TSocket when using ssl connection - [THRIFT-5199](https://issues.apache.org/jira/browse/THRIFT-5199) - Infinite loop in PHP TSocket::write when peer closes connection - [THRIFT-5336](https://issues.apache.org/jira/browse/THRIFT-5336) - Add possibility to setup connection timeout in TCurlClient ### Python - [THRIFT-2087](https://issues.apache.org/jira/browse/THRIFT-2087) - unicode decode errors - [THRIFT-4002](https://issues.apache.org/jira/browse/THRIFT-4002) - Thrift exceptions are not hashable in Python 3 - [THRIFT-5107](https://issues.apache.org/jira/browse/THRIFT-5107) - Travis build fails with missing Python 3.3 or newer? - [THRIFT-5165](https://issues.apache.org/jira/browse/THRIFT-5165) - Python THttpClient saves cookie when Set-Cookie response header is present - [THRIFT-5186](https://issues.apache.org/jira/browse/THRIFT-5186) - AI_ADDRCONFIG: Thrift libraries crash with localhost-only network. - [THRIFT-5248](https://issues.apache.org/jira/browse/THRIFT-5248) - Python: Make TSocket.isOpen check if the other end is still connected - [THRIFT-5303](https://issues.apache.org/jira/browse/THRIFT-5303) - Unicode decode errors in _fast_decode - [THRIFT-5331](https://issues.apache.org/jira/browse/THRIFT-5331) - Python: allow THeaderProtocol to choose which subprotocol to use for outbound connections ### Ruby - [THRIFT-5281](https://issues.apache.org/jira/browse/THRIFT-5281) - Some warning messages need to be fixed - [THRIFT-4707](https://issues.apache.org/jira/browse/THRIFT-4707) - Enable maintainers to upload newer versions of Ruby Gem of Thrift - [THRIFT-5061](https://issues.apache.org/jira/browse/THRIFT-5061) - Pin Ruby's rack version to 2.0.8 - [THRIFT-5100](https://issues.apache.org/jira/browse/THRIFT-5100) - Gem::InstallError: byebug requires Ruby version >= 2.4.0. - [THRIFT-5266](https://issues.apache.org/jira/browse/THRIFT-5266) - release ruby library thrift 0.13.0 ### Rust - [THRIFT-4764](https://issues.apache.org/jira/browse/THRIFT-4764) - Rust frontend emits deprecated clippy suppression attributes - [THRIFT-5071](https://issues.apache.org/jira/browse/THRIFT-5071) - Rust: rust tutorial can not be compiled with rust edition 2018 - [THRIFT-5158](https://issues.apache.org/jira/browse/THRIFT-5158) - Update Rust Compiler to generate 2018 edition code only - [THRIFT-5307](https://issues.apache.org/jira/browse/THRIFT-5307) - Rust generated code should compile cleanly with clippy - [THRIFT-4915](https://issues.apache.org/jira/browse/THRIFT-4915) - Deserializing double into OrderedFloat always returns zero when using TCompactProtocol - [THRIFT-4995](https://issues.apache.org/jira/browse/THRIFT-4995) - [Rust] Use `ToSocketAddrs` for expressing network addresses - [THRIFT-5042](https://issues.apache.org/jira/browse/THRIFT-5042) - Fix failing cargo tests - [THRIFT-5043](https://issues.apache.org/jira/browse/THRIFT-5043) - Make TBufferChannel clonable - [THRIFT-5111](https://issues.apache.org/jira/browse/THRIFT-5111) - CI fails with error[E0721]: `await` is a keyword in the 2018 edition - [THRIFT-5131](https://issues.apache.org/jira/browse/THRIFT-5131) - i64 maxint decoding panics with integer-encoding >= 1.1.0 - [THRIFT-5306](https://issues.apache.org/jira/browse/THRIFT-5306) - Rust library, tutorial, test, cross-test code should not throw any clippy errors ### Swift - [THRIFT-4989](https://issues.apache.org/jira/browse/THRIFT-4989) - Run time exception when using TCompactProtocol - [THRIFT-5128](https://issues.apache.org/jira/browse/THRIFT-5128) - Swift TFramedTransport does not work using present code - [THRIFT-5138](https://issues.apache.org/jira/browse/THRIFT-5138) - Swift generator does not escape keywords properly - [THRIFT-5155](https://issues.apache.org/jira/browse/THRIFT-5155) - Swift 5.1 support - [THRIFT-5070](https://issues.apache.org/jira/browse/THRIFT-5070) - Swift: Hashable.hashValue is deprecated as a protocol requirement - [THRIFT-5084](https://issues.apache.org/jira/browse/THRIFT-5084) - Swift: Server-side support for Multiplexing Services - [THRIFT-5121](https://issues.apache.org/jira/browse/THRIFT-5121) - Logic bug in TMultiplexedProcessor – Swift - [THRIFT-5125](https://issues.apache.org/jira/browse/THRIFT-5125) - Swift server does not work using present code. - [THRIFT-5129](https://issues.apache.org/jira/browse/THRIFT-5129) - Swift TSocketTransport cannot be used to connect to client - [THRIFT-5150](https://issues.apache.org/jira/browse/THRIFT-5150) - TSet does not compile with Swift 5.2 ### Test Suite - [THRIFT-4974](https://issues.apache.org/jira/browse/THRIFT-4974) - Add cross test for Python's Unix domain socket transport - [THRIFT-5145](https://issues.apache.org/jira/browse/THRIFT-5145) - Streamline --pipe and --named-pipe options in the code base - [THRIFT-5171](https://issues.apache.org/jira/browse/THRIFT-5171) - Fix maven-ant-tasks to use HTTPS instead of HTTP ### TypeScript) - Library - [THRIFT-5003](https://issues.apache.org/jira/browse/THRIFT-5003) - Websocket Connection in Browsers with nodejs code ### Tutorial - [THRIFT-4972](https://issues.apache.org/jira/browse/THRIFT-4972) - Add Makefile.am to the Perl tutorial - [THRIFT-4975](https://issues.apache.org/jira/browse/THRIFT-4975) - Add Makefile.am to the PHP tutorial - [THRIFT-5051](https://issues.apache.org/jira/browse/THRIFT-5051) - Fix Python tutorials to address THRIFT-4002 - [THRIFT-5052](https://issues.apache.org/jira/browse/THRIFT-5052) - Make the Go tutorial executable to the end - [THRIFT-5122](https://issues.apache.org/jira/browse/THRIFT-5122) - Fix memory leak in c_glib tutorial server ## 0.13.0 ### New Languages - (none) ### Deprecated Languages - [THRIFT-4723](https://issues.apache.org/jira/browse/THRIFT-4723) - CSharp and Netcore targets are deprecated and will be removed with the next release) - use NetStd instead. ### Removed Languages - [THRIFT-4719](https://issues.apache.org/jira/browse/THRIFT-4719) - Cocoa language was removed) - use swift instead. ### Breaking Changes - [THRIFT-4743](https://issues.apache.org/jira/browse/THRIFT-4743) - compiler: removed the plug-in mechanism - [THRIFT-4720](https://issues.apache.org/jira/browse/THRIFT-4720) - cpp: C++03/C++98 support has been removed; also removed boost as a runtime dependency - [THRIFT-4730](https://issues.apache.org/jira/browse/THRIFT-4730) - cpp: BoostThreadFactory, PosixThreadFactory, StdThreadFactory removed - [THRIFT-4732](https://issues.apache.org/jira/browse/THRIFT-4732) - cpp: CMake build changed to use BUILD_SHARED_LIBS - [THRIFT-4735](https://issues.apache.org/jira/browse/THRIFT-4735) - cpp: Removed Qt4 support - [THRIFT-4740](https://issues.apache.org/jira/browse/THRIFT-4740) - cpp: Use std::chrono::duration for timeouts - [THRIFT-4762](https://issues.apache.org/jira/browse/THRIFT-4762) - cpp: TTransport::getOrigin() is now const - [THRIFT-4702](https://issues.apache.org/jira/browse/THRIFT-4702) - java: class org.apache.thrift.AutoExpandingBuffer is no longer public - [THRIFT-4709](https://issues.apache.org/jira/browse/THRIFT-4709) - java: changes to UTF-8 handling require JDK 1.7 at a minimum - [THRIFT-4712](https://issues.apache.org/jira/browse/THRIFT-4712) - java: class org.apache.thrift.ShortStack is no longer public - [THRIFT-4725](https://issues.apache.org/jira/browse/THRIFT-4725) - java: change return type signature of 'process' methods - [THRIFT-4805](https://issues.apache.org/jira/browse/THRIFT-4805) - java: replaced TSaslTransportException with TTransportException - [THRIFT-2530](https://issues.apache.org/jira/browse/THRIFT-2530) - java: TIOStreamTransport's "isOpen" now returns false after "close" is called - [THRIFT-4675](https://issues.apache.org/jira/browse/THRIFT-4675) - js: now uses node-int64 for 64 bit integer constants - [THRIFT-4841](https://issues.apache.org/jira/browse/THRIFT-4841) - delphi: old THTTPTransport is now TMsxmlHTTPTransport - [THRIFT-4536](https://issues.apache.org/jira/browse/THRIFT-4536) - rust: convert from try-from crate to rust stable (1.34+), re-export ordered-float ### Known Issues (Blocker or Critical) - [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++: library don't work with HTTP (csharp server, cpp client; need cross test enhancement) ### As3 - [THRIFT-4784](https://issues.apache.org/jira/browse/THRIFT-4784) - Thrift should throw when skipping over unexpected data ### Build Process - [THRIFT-2333](https://issues.apache.org/jira/browse/THRIFT-2333) - RPMBUILD: Abort build if user did not disable ruby but ruby build will fail later on - [THRIFT-4689](https://issues.apache.org/jira/browse/THRIFT-4689) - Pull changes from 0.12.0 release branch into master - [THRIFT-4690](https://issues.apache.org/jira/browse/THRIFT-4690) - Update dlang deimos for OpenSSL 1.1 (use 1.1.0h tagged release instead of master) - [THRIFT-4694](https://issues.apache.org/jira/browse/THRIFT-4694) - Upgrade Java to Java 1.8 - [THRIFT-4716](https://issues.apache.org/jira/browse/THRIFT-4716) - Create a version alignment tool to make releases easier - [THRIFT-4760](https://issues.apache.org/jira/browse/THRIFT-4760) - Install pkgconfig when using cmake - [THRIFT-4769](https://issues.apache.org/jira/browse/THRIFT-4769) - Change NuGet package to use netstd artifact - [THRIFT-4811](https://issues.apache.org/jira/browse/THRIFT-4811) - Add cmake config module - [THRIFT-4855](https://issues.apache.org/jira/browse/THRIFT-4855) - go CI fails with "cannot find package "golang.org/x/tools/go/packages" in any of ..." - [THRIFT-4864](https://issues.apache.org/jira/browse/THRIFT-4864) - CI fails at netstd - [THRIFT-4874](https://issues.apache.org/jira/browse/THRIFT-4874) - Thrift 0.12.0 Source Distribution (.tar.gz) Contains Hardlinks) - Extract Fails - [THRIFT-4896](https://issues.apache.org/jira/browse/THRIFT-4896) - cpp and c_glib include paths are added to source files when building - [THRIFT-4966](https://issues.apache.org/jira/browse/THRIFT-4966) - Git ignore files generated by the build ### C glib - [THRIFT-4842](https://issues.apache.org/jira/browse/THRIFT-4842) - Multiplexed protocol has a memory leak in set c_glib - [THRIFT-4878](https://issues.apache.org/jira/browse/THRIFT-4878) - c_glib ThriftSocket support for unix domain sockets - [THRIFT-4950](https://issues.apache.org/jira/browse/THRIFT-4950) - fix bind print error and Macro call errors thrift_server_socket ### C# - [THRIFT-3587](https://issues.apache.org/jira/browse/THRIFT-3587) - C# TTLSSocket does not use timeout for opening the socket - [THRIFT-4024](https://issues.apache.org/jira/browse/THRIFT-4024) - Skip() should throw on unknown data types - [THRIFT-4684](https://issues.apache.org/jira/browse/THRIFT-4684) - Missing namespace and un-used private fields in WCF fault classes when enable WCF in C# code generation - [THRIFT-4715](https://issues.apache.org/jira/browse/THRIFT-4715) - C# union "data" should be strongly-typed - [THRIFT-4723](https://issues.apache.org/jira/browse/THRIFT-4723) - Consolidate C# and netcore into new netstd language target (and finally deprecate both C# and netcore bindings) - [THRIFT-4741](https://issues.apache.org/jira/browse/THRIFT-4741) - Missing "inner" argument from one CTOR - [THRIFT-4769](https://issues.apache.org/jira/browse/THRIFT-4769) - Change NuGet package to use netstd artifact - [THRIFT-4859](https://issues.apache.org/jira/browse/THRIFT-4859) - Enables changing 'UserAgent' - [THRIFT-4907](https://issues.apache.org/jira/browse/THRIFT-4907) - strong named assemblies wanted ### C++ - [THRIFT-4384](https://issues.apache.org/jira/browse/THRIFT-4384) - Using a concurrent client with cpp async is not safe. - [THRIFT-4441](https://issues.apache.org/jira/browse/THRIFT-4441) - C++: support building lib without Boost - [THRIFT-4487](https://issues.apache.org/jira/browse/THRIFT-4487) - gettimeofday: windows implementation not quoting source, applying license to foreign code - [THRIFT-4593](https://issues.apache.org/jira/browse/THRIFT-4593) - Unit Tests failing on Alpine Linux due to non-portable mutex initializers - [THRIFT-4678](https://issues.apache.org/jira/browse/THRIFT-4678) - add noexcept cpp generator option - [THRIFT-4720](https://issues.apache.org/jira/browse/THRIFT-4720) - Drop support for C++03/C++98 and begin refactoring - [THRIFT-4730](https://issues.apache.org/jira/browse/THRIFT-4730) - Remove pthread and boost::thread library support and use std::thread for C++11 - [THRIFT-4735](https://issues.apache.org/jira/browse/THRIFT-4735) - Remove C++ Qt4 support (leave Qt5) - Qt4 LTS ended in 2014 - [THRIFT-4739](https://issues.apache.org/jira/browse/THRIFT-4739) - Good old concurrency_test failing on windows builds again with some regularity - [THRIFT-4740](https://issues.apache.org/jira/browse/THRIFT-4740) - Use std::chrono for timeout and remove old structures. - [THRIFT-4762](https://issues.apache.org/jira/browse/THRIFT-4762) - C++: Applied some C++11 refactorings to the runtime library and compiler - [THRIFT-4776](https://issues.apache.org/jira/browse/THRIFT-4776) - Modernize c++11 code by clang-tidy - [THRIFT-4830](https://issues.apache.org/jira/browse/THRIFT-4830) - Add to_string function for enum in C++ file generate - [THRIFT-4861](https://issues.apache.org/jira/browse/THRIFT-4861) - Fix use of deprecated boost endian header; move to minimum boost 1.56.0 - [THRIFT-4936](https://issues.apache.org/jira/browse/THRIFT-4936) - add depth limit type exception description - [THRIFT-4962](https://issues.apache.org/jira/browse/THRIFT-4962) - Deadlock in TimerManager::stop ### cocoa - [THRIFT-4719](https://issues.apache.org/jira/browse/THRIFT-4719) - Remove cocoa language support ## Compiler (General) - [THRIFT-4743](https://issues.apache.org/jira/browse/THRIFT-4743) - Remove the compiler plug-in mode ### contributed - [THRIFT-4897](https://issues.apache.org/jira/browse/THRIFT-4897) - UT of thrift-maven-plugin failed ## D language - [THRIFT-4690](https://issues.apache.org/jira/browse/THRIFT-4690) - Update dlang deimos for OpenSSL 1.1 (use 1.1.0h tagged release instead of master) - [THRIFT-4724](https://issues.apache.org/jira/browse/THRIFT-4724) - dlang dub.json dependency for openssl is too restrictive - [THRIFT-4918](https://issues.apache.org/jira/browse/THRIFT-4918) - dlang name conflict ### dart - [THRIFT-4654](https://issues.apache.org/jira/browse/THRIFT-4654) - Thrift Dart port is not compatible with Dart 2 ### Delphi - [THRIFT-4024](https://issues.apache.org/jira/browse/THRIFT-4024) - Skip() should throw on unknown data types - [THRIFT-4841](https://issues.apache.org/jira/browse/THRIFT-4841) - THTTPTransport relies on activeX component - [THRIFT-4843](https://issues.apache.org/jira/browse/THRIFT-4843) - http:// and https:// schemes are switched in test client - [THRIFT-4862](https://issues.apache.org/jira/browse/THRIFT-4862) - better ToString() support for enums and container types - [THRIFT-4863](https://issues.apache.org/jira/browse/THRIFT-4863) - better indication of WinHTTP errors - [THRIFT-4881](https://issues.apache.org/jira/browse/THRIFT-4881) - Allow TLS1.1 and TLS1.2 over WinHTTP even when not configured as systemwide default - [THRIFT-4882](https://issues.apache.org/jira/browse/THRIFT-4882) - Autodetect proxy settings with WinHTTP - [THRIFT-4884](https://issues.apache.org/jira/browse/THRIFT-4884) - Add serialisation performance test for Delphi - [THRIFT-4886](https://issues.apache.org/jira/browse/THRIFT-4886) - More detailed error information for WinHTTP transport - [THRIFT-4894](https://issues.apache.org/jira/browse/THRIFT-4894) - Enable automatic content encoding handling for gzip,deflate in the WinHTTP client - [THRIFT-4939](https://issues.apache.org/jira/browse/THRIFT-4939) - TThriftListImpl.Sort() does not use comparer - [THRIFT-4944](https://issues.apache.org/jira/browse/THRIFT-4944) - Field IDs > 255 fail with compact protocol ### Documentation - [THRIFT-4697](https://issues.apache.org/jira/browse/THRIFT-4697) - Create updated release procedures - [THRIFT-4808](https://issues.apache.org/jira/browse/THRIFT-4808) - Update LANGUAGES.md on master to reflect master - [THRIFT-4933](https://issues.apache.org/jira/browse/THRIFT-4933) - Incorrect description in the 0.12.0 version of the documentation ### Erlang - [THRIFT-4583](https://issues.apache.org/jira/browse/THRIFT-4583) - Support rebar3 for erlang builds - [THRIFT-4744](https://issues.apache.org/jira/browse/THRIFT-4744) - Erlang help intendation not aligned ### Go - [THRIFT-4024](https://issues.apache.org/jira/browse/THRIFT-4024) - Skip() should throw on unknown data types - [THRIFT-4612](https://issues.apache.org/jira/browse/THRIFT-4612) - Add THeader for Go - [THRIFT-4747](https://issues.apache.org/jira/browse/THRIFT-4747) - The 'omitempty' tag should not be appended to optional fields that have a default value - [THRIFT-4797](https://issues.apache.org/jira/browse/THRIFT-4797) - Generated Go code produces name collisions on imports - [THRIFT-4908](https://issues.apache.org/jira/browse/THRIFT-4908) - reader&writer in golang's TBinaryProtocol is not necessary and misleading ### haskell - [THRIFT-4834](https://issues.apache.org/jira/browse/THRIFT-4834) - CI error at Haskell: Failed to load interface for `Network' - [THRIFT-4955](https://issues.apache.org/jira/browse/THRIFT-4955) - Haskell test broken due to extension to CompactProtoTestStruct - [THRIFT-4956](https://issues.apache.org/jira/browse/THRIFT-4956) - DebugProtoTest_Main.hs: Invalid ThriftType 128 ### haxe - [THRIFT-4024](https://issues.apache.org/jira/browse/THRIFT-4024) - Skip() should throw on unknown data types - [THRIFT-4812](https://issues.apache.org/jira/browse/THRIFT-4812) - haxelib readme still points to old ASF git repo ### HTML - [THRIFT-4763](https://issues.apache.org/jira/browse/THRIFT-4763) - HTML compiler produces invalid HTML document ### Java - [THRIFT-2530](https://issues.apache.org/jira/browse/THRIFT-2530) - TIOStreamTransport's isOpen() always be true even if close() was called. - [THRIFT-4368](https://issues.apache.org/jira/browse/THRIFT-4368) - Guaranteed NPE in TBaseAsyncProcessor.java - [THRIFT-4469](https://issues.apache.org/jira/browse/THRIFT-4469) - isServing is not thread safe - [THRIFT-4481](https://issues.apache.org/jira/browse/THRIFT-4481) - TBinaryProtocol.writeMessageEnd isn't throwable exception - [THRIFT-4695](https://issues.apache.org/jira/browse/THRIFT-4695) - Pre-Size Java Collections in Union - [THRIFT-4696](https://issues.apache.org/jira/browse/THRIFT-4696) - NonBlocking Server: Use case-switch Statement Instead of if-else Clauses - [THRIFT-4702](https://issues.apache.org/jira/browse/THRIFT-4702) - Improve AutoExpandingBuffer - [THRIFT-4704](https://issues.apache.org/jira/browse/THRIFT-4704) - Streamline TDeserializer Implementation - [THRIFT-4709](https://issues.apache.org/jira/browse/THRIFT-4709) - Use StandardCharset UTF-8 - [THRIFT-4711](https://issues.apache.org/jira/browse/THRIFT-4711) - Improve Immutable None Type Instantiation - [THRIFT-4712](https://issues.apache.org/jira/browse/THRIFT-4712) - Improve Performance of ShortStack - [THRIFT-4713](https://issues.apache.org/jira/browse/THRIFT-4713) - Review of TBaseHelper.java - [THRIFT-4714](https://issues.apache.org/jira/browse/THRIFT-4714) - Java TFramedTransport calls write twice for each flush - [THRIFT-4725](https://issues.apache.org/jira/browse/THRIFT-4725) - Change Return Type Signature of Process Methods - [THRIFT-4726](https://issues.apache.org/jira/browse/THRIFT-4726) - Remove SLF4J Logging Guards - [THRIFT-4748](https://issues.apache.org/jira/browse/THRIFT-4748) - Add Jitpack support - [THRIFT-4766](https://issues.apache.org/jira/browse/THRIFT-4766) - JDK9+ fails on missing annotations - [THRIFT-4773](https://issues.apache.org/jira/browse/THRIFT-4773) - TSaslTransport should relay underlying TTransportException to TSaslTransportException - [THRIFT-4805](https://issues.apache.org/jira/browse/THRIFT-4805) - Suppress excessive logging of SASL TTransportExceptions in case of END_OF_FILE - [THRIFT-4849](https://issues.apache.org/jira/browse/THRIFT-4849) - Do not Ignore InterruptedException - [THRIFT-4851](https://issues.apache.org/jira/browse/THRIFT-4851) - Remove All Calls To printStackTrace - [THRIFT-4857](https://issues.apache.org/jira/browse/THRIFT-4857) - Java field hash code implementation inconsistent with equals. - [THRIFT-4858](https://issues.apache.org/jira/browse/THRIFT-4858) - Java TThreadPoolServer: confusing error message on closed socket - [THRIFT-4865](https://issues.apache.org/jira/browse/THRIFT-4865) - warning: [deprecation] UTF_8 in Charsets has been deprecated - [THRIFT-4899](https://issues.apache.org/jira/browse/THRIFT-4899) - Generated TypeScript declarations incorrectly references types when there is more than 1 include - [THRIFT-4945](https://issues.apache.org/jira/browse/THRIFT-4945) - Log output mode is not standardized - [THRIFT-4957](https://issues.apache.org/jira/browse/THRIFT-4957) - testSanePartsOfCompactProtoTestStruct FAILED ### JavaScript - [THRIFT-4675](https://issues.apache.org/jira/browse/THRIFT-4675) - JS code generators not handling int64 type properly for constants and for TypeScript type mappings - [THRIFT-4728](https://issues.apache.org/jira/browse/THRIFT-4728) - Cleanup for the double rendering test in JS - [THRIFT-4737](https://issues.apache.org/jira/browse/THRIFT-4737) - thrift.js does not use customHeaders in jqRequest - [THRIFT-4745](https://issues.apache.org/jira/browse/THRIFT-4745) - warning C4305: 'initializing' : truncation from '"__int64' to 'long' - [THRIFT-4757](https://issues.apache.org/jira/browse/THRIFT-4757) - grunt-shell-spawn drags in sync-exec which has a security notice ### netcore - [THRIFT-4024](https://issues.apache.org/jira/browse/THRIFT-4024) - Skip() should throw on unknown data types - [THRIFT-4722](https://issues.apache.org/jira/browse/THRIFT-4722) - Netcore union "data" should be strongly-typed - [THRIFT-4723](https://issues.apache.org/jira/browse/THRIFT-4723) - Consolidate C# and netcore into new netstd language target (and finally deprecate both C# and netcore bindings) - [THRIFT-4742](https://issues.apache.org/jira/browse/THRIFT-4742) - Typo "cannot read from null input stream" on write - [THRIFT-4769](https://issues.apache.org/jira/browse/THRIFT-4769) - Change NuGet package to use netstd artifact - [THRIFT-4919](https://issues.apache.org/jira/browse/THRIFT-4919) - THttpTransport.cs (netstd) and THttpClientTransport (netcore) have bad timeout code ### netstd - [THRIFT-4768](https://issues.apache.org/jira/browse/THRIFT-4768) - Remove "nullable" option from the code base (netstd ONLY) - [THRIFT-4772](https://issues.apache.org/jira/browse/THRIFT-4772) - fully enable server-side usage of framed/buffered transports - [THRIFT-4813](https://issues.apache.org/jira/browse/THRIFT-4813) - NamedPipes may not work in all cases - [THRIFT-4816](https://issues.apache.org/jira/browse/THRIFT-4816) - JSONTransports Context.WriteAsync/ReadAsync are badly named - [THRIFT-4817](https://issues.apache.org/jira/browse/THRIFT-4817) - Add string CTOR to TTlsSocketTransport - [THRIFT-4818](https://issues.apache.org/jira/browse/THRIFT-4818) - Test client should use cancellation token - [THRIFT-4821](https://issues.apache.org/jira/browse/THRIFT-4821) - Normalize TServerSocketTransport constructors in netstd - [THRIFT-4822](https://issues.apache.org/jira/browse/THRIFT-4822) - Refactor bool CTOR flags into enum type - [THRIFT-4824](https://issues.apache.org/jira/browse/THRIFT-4824) - Logger deprecation warnings in tutorial - [THRIFT-4825](https://issues.apache.org/jira/browse/THRIFT-4825) - Align TTlsServerSocketTransport constructors with TServerSocketTransport) - Breaking Change - [THRIFT-4829](https://issues.apache.org/jira/browse/THRIFT-4829) - HTTP server transport lacks TransportFactory arguments - [THRIFT-4831](https://issues.apache.org/jira/browse/THRIFT-4831) - interface ITProtocolFactory should be class TProtocolFactory again - [THRIFT-4832](https://issues.apache.org/jira/browse/THRIFT-4832) - superfluous backing field causes CS0169 "field never used" - [THRIFT-4839](https://issues.apache.org/jira/browse/THRIFT-4839) - Remove embedded buffering/framed options from TCP transports - [THRIFT-4840](https://issues.apache.org/jira/browse/THRIFT-4840) - Update the README in the netstd tutorial to include references to the new buffering arguments - [THRIFT-4848](https://issues.apache.org/jira/browse/THRIFT-4848) - Add ability to set Content-Type,Accept headers in HTTP client - [THRIFT-4853](https://issues.apache.org/jira/browse/THRIFT-4853) - TServerFramedTransport is now obsolete and can be removed - [THRIFT-4854](https://issues.apache.org/jira/browse/THRIFT-4854) - oneway calls do not work over HTTP - [THRIFT-4860](https://issues.apache.org/jira/browse/THRIFT-4860) - Allow changing "User-Agent" - [THRIFT-4879](https://issues.apache.org/jira/browse/THRIFT-4879) - general performance improvements for netstd library - [THRIFT-4891](https://issues.apache.org/jira/browse/THRIFT-4891) - Align HTTP test client with all other variants - [THRIFT-4893](https://issues.apache.org/jira/browse/THRIFT-4893) - Enable automatic content encoding handling for gzip,deflate in the HTTP client - [THRIFT-4898](https://issues.apache.org/jira/browse/THRIFT-4898) - Pipe write operations across a network are limited to 65,535 bytes per write. - [THRIFT-4919](https://issues.apache.org/jira/browse/THRIFT-4919) - THttpTransport.cs (netstd) and THttpClientTransport (netcore) have bad timeout code ### node.js - [THRIFT-3060](https://issues.apache.org/jira/browse/THRIFT-3060) - Node.js client retry logic doesn't flush offline queue on reconnect - [THRIFT-4675](https://issues.apache.org/jira/browse/THRIFT-4675) - JS code generators not handling int64 type properly for constants and for TypeScript type mappings - [THRIFT-4738](https://issues.apache.org/jira/browse/THRIFT-4738) - Generated typescript type definition files are incorrect - [THRIFT-4771](https://issues.apache.org/jira/browse/THRIFT-4771) - THeader for node.js - [THRIFT-4809](https://issues.apache.org/jira/browse/THRIFT-4809) - Javascript episodic code generation - [THRIFT-4844](https://issues.apache.org/jira/browse/THRIFT-4844) - createConnection ignores connect_timeout option ### perl - [THRIFT-4691](https://issues.apache.org/jira/browse/THRIFT-4691) - The perl CPAN module contains no tests ### PHP - [THRIFT-4751](https://issues.apache.org/jira/browse/THRIFT-4751) - Missing imports in TProtocol (phpdoc related only) - [THRIFT-4794](https://issues.apache.org/jira/browse/THRIFT-4794) - Finish adding json protocol to the php cross test - [THRIFT-4807](https://issues.apache.org/jira/browse/THRIFT-4807) - PHP extension segfaults if reference is used in input - [THRIFT-4845](https://issues.apache.org/jira/browse/THRIFT-4845) - PHP's TCurlClient ignores timeout values smaller that 1 second ### python - [THRIFT-1549](https://issues.apache.org/jira/browse/THRIFT-1549) - Python TSSLSocket: Shutdown cleanly - [THRIFT-4733](https://issues.apache.org/jira/browse/THRIFT-4733) - Address already in use with python unit test - [THRIFT-4767](https://issues.apache.org/jira/browse/THRIFT-4767) - support tcp keepalive in python - [THRIFT-4778](https://issues.apache.org/jira/browse/THRIFT-4778) - Python protocol factories do not derive from TProtocolFactory - [THRIFT-4779](https://issues.apache.org/jira/browse/THRIFT-4779) - Python, Java TMultiplexedProcessor do not raise TProtocolException - [THRIFT-4780](https://issues.apache.org/jira/browse/THRIFT-4780) - TMultiplexedProcessor is not fully tested or implemented in Python - [THRIFT-4783](https://issues.apache.org/jira/browse/THRIFT-4783) - Thrift should throw when skipping over unexpected data - [THRIFT-4798](https://issues.apache.org/jira/browse/THRIFT-4798) - Fix python THttpServer to honor correct oneway reply semantics - [THRIFT-4892](https://issues.apache.org/jira/browse/THRIFT-4892) - SASL data type exception for PLAIN - [THRIFT-4920](https://issues.apache.org/jira/browse/THRIFT-4920) - Binary constants emit non-binary Python literals ### ruby - [THRIFT-4721](https://issues.apache.org/jira/browse/THRIFT-4721) - Installing the ruby gem on systems without make fails in the build_ext task. - [THRIFT-4971](https://issues.apache.org/jira/browse/THRIFT-4971) - Fix lib/rb/spec/union_spec.rb so that CI succeeds ### rust - [THRIFT-4953](https://issues.apache.org/jira/browse/THRIFT-4953) - Unspecified Field Identifier Creates Non Compiling Rust Code - [THRIFT-4960](https://issues.apache.org/jira/browse/THRIFT-4960) - Bare Trait Warnings ### Swift - [THRIFT-4902](https://issues.apache.org/jira/browse/THRIFT-4902) - Swift compatibility with Swift 4.2, 5.0 and 5.1 ### Test suite - [THRIFT-4301](https://issues.apache.org/jira/browse/THRIFT-4301) - configuring --without-python and --without-py3 still invokes py3 tests in make cross - [THRIFT-4405](https://issues.apache.org/jira/browse/THRIFT-4405) - Incorrect handling of sequence numbers that wrap to negative - [THRIFT-4794](https://issues.apache.org/jira/browse/THRIFT-4794) - Finish adding json protocol to the php cross test - [THRIFT-4969](https://issues.apache.org/jira/browse/THRIFT-4969) - PHP test doesn't check the code generation with php:classmap ### Tutorial - [THRIFT-4426](https://issues.apache.org/jira/browse/THRIFT-4426) - repository should not include symbolic links - [THRIFT-4965](https://issues.apache.org/jira/browse/THRIFT-4965) - Perl tutorial server doesn't work due to the lack of use statement - [THRIFT-4967](https://issues.apache.org/jira/browse/THRIFT-4967) - Node.js tutorial server fails if the zip function invoked - [THRIFT-4968](https://issues.apache.org/jira/browse/THRIFT-4968) - Makefile.am in the Ruby tutorial refers to Python directory - [THRIFT-4970](https://issues.apache.org/jira/browse/THRIFT-4970) - PHP tutorial doesn't work with Thrift v0.12.0+ ### Typescript - [THRIFT-4675](https://issues.apache.org/jira/browse/THRIFT-4675) - JS code generators not handling int64 type properly for constants and for TypeScript type mappings ## 0.12.0 Released 2019-JAN-04 ### New Languages - Common LISP (cl) - Swift - Typescript (nodets) ### Deprecated Languages - C++03/C++98 (move to C++11) - Cocoa (move to Swift) ### Breaking Changes (since 0.11.0) - [THRIFT-4529](https://issues.apache.org/jira/browse/THRIFT-4529) - Rust enum variants are now camel-cased instead of uppercased to conform to Rust naming conventions - [THRIFT-4448](https://issues.apache.org/jira/browse/THRIFT-4448) - Support for golang 1.6 and earlier has been dropped. - [THRIFT-4474](https://issues.apache.org/jira/browse/THRIFT-4474) - PHP now uses the PSR-4 loader by default instead of class maps. - [THRIFT-4532](https://issues.apache.org/jira/browse/THRIFT-4532) - method signatures changed in the compiler's t_oop_generator. - [THRIFT-4648](https://issues.apache.org/jira/browse/THRIFT-4648) - The C (GLib) compiler's handling of namespaces has been improved. ### Known Issues (Blocker or Critical) - [THRIFT-4037](https://issues.apache.org/jira/browse/THRIFT-4037) - build: use a single build system for thrift - [THRIFT-4119](https://issues.apache.org/jira/browse/THRIFT-4119) - build: bootstrap.sh is missing from source tarball - [THRIFT-3289](https://issues.apache.org/jira/browse/THRIFT-3289) - csharp: socket exhaustion in csharp implementation - [THRIFT-3029](https://issues.apache.org/jira/browse/THRIFT-3029) - cocoa: Getters for fields defined with uppercase names do not work - [THRIFT-3325](https://issues.apache.org/jira/browse/THRIFT-3325) - cocoa: Extended services aren't subclasses in generated Cocoa - [THRIFT-4116](https://issues.apache.org/jira/browse/THRIFT-4116) - cocoa: Thrift de-capitalizes the name of IsSet property in Cocoa - [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - cpp: the http implementation is not standard; interop with other languages is spotty at best - [THRIFT-4180](https://issues.apache.org/jira/browse/THRIFT-4180) - cpp: Impossible to build Thrift C++ library for Android (NDK) - [THRIFT-4384](https://issues.apache.org/jira/browse/THRIFT-4384) - cpp: Using multiple async services simultaneously is not thread-safe - [THRIFT-3108](https://issues.apache.org/jira/browse/THRIFT-3108) - haskell: Defaulted struct parameters on a service generates invalid Haskell - [THRIFT-3990](https://issues.apache.org/jira/browse/THRIFT-3990) - nodejs: Exception swallowed by deserialization function - [THRIFT-4214](https://issues.apache.org/jira/browse/THRIFT-4214) - nodejs: map key treated as hex value in JavaScript - [THRIFT-4602](https://issues.apache.org/jira/browse/THRIFT-4602) - nodejs: ERROR in ./node_modules/thrift/lib/nodejs/lib/thrift/connection.js Module not found: Error: Can't resolve 'child_process' - [THRIFT-4639](https://issues.apache.org/jira/browse/THRIFT-4639) - nodejs: Sequence numbering for multiplexed protocol broken - [THRIFT-1310](https://issues.apache.org/jira/browse/THRIFT-1310) - php: sequence and reconnection management issues - [THRIFT-1538](https://issues.apache.org/jira/browse/THRIFT-1538) - php: Error during deserialization int64 on 32-bit architecture - [THRIFT-1580](https://issues.apache.org/jira/browse/THRIFT-1580) - php: thrift type i64 java to php serialize/deserealize not working - [THRIFT-1950](https://issues.apache.org/jira/browse/THRIFT-1950) - php: PHP gets stuck in infinite loop - [THRIFT-2954](https://issues.apache.org/jira/browse/THRIFT-2954) - python: sending int or float in a double field breaks the connection - [THRIFT-4080](https://issues.apache.org/jira/browse/THRIFT-4080) - python: unix sockets can get stuck forever - [THRIFT-4281](https://issues.apache.org/jira/browse/THRIFT-4281) - python: generated code is out of order and causes load issues - [THRIFT-4677](https://issues.apache.org/jira/browse/THRIFT-4677) - py3: UnicodeDecideError in Python3 ### Build Process - [THRIFT-4067](https://issues.apache.org/jira/browse/THRIFT-4067) - Windows thrift compiler distributed on the apache web site has runtime dependencies - [THRIFT-4308](https://issues.apache.org/jira/browse/THRIFT-4308) - D language docker images need demios for libevent and openssl fixed to re-enable make cross on dlang - [THRIFT-4579](https://issues.apache.org/jira/browse/THRIFT-4579) - Use Ubuntu Bionic (18.04 LTS) for CI builds instead of Artful (17.10) - [THRIFT-4508](https://issues.apache.org/jira/browse/THRIFT-4508) - Define CI operating system coverage rules for the project and (hopefully) simplify CI a little more - [THRIFT-4397](https://issues.apache.org/jira/browse/THRIFT-4397) - ubuntu install instructions broken on 16.04 - [THRIFT-4545](https://issues.apache.org/jira/browse/THRIFT-4545) - Appveyor builds are failing due to a haskell / cabal update in chocolatey - [THRIFT-4452](https://issues.apache.org/jira/browse/THRIFT-4452) - optimize Dockerfile (only onetime apt-get update) - [THRIFT-4440](https://issues.apache.org/jira/browse/THRIFT-4440) - rm `build/docker/ubuntu-trusty/Dockerfile.orig` - [THRIFT-4352](https://issues.apache.org/jira/browse/THRIFT-4352) - Ubuntu Artful doesn't appear to be compatible with Thrift and Haxe 3.4.2 - [THRIFT-4666](https://issues.apache.org/jira/browse/THRIFT-4666) - DLang Client Pool Test fails sporadically - [THRIFT-4676](https://issues.apache.org/jira/browse/THRIFT-4676) - CL tutorial build fails sporadically - [THRIFT-4456](https://issues.apache.org/jira/browse/THRIFT-4456) - Make haxelib download quiet so it doesn't blow up the build log - [THRIFT-4605](https://issues.apache.org/jira/browse/THRIFT-4605) - bootstrap.sh fails if automake=1.16.1 ### c_glib - [THRIFT-4648](https://issues.apache.org/jira/browse/THRIFT-4648) - The C (GLib) compiler's handling of namespaces has been improved. - [THRIFT-4622](https://issues.apache.org/jira/browse/THRIFT-4622) - glibC compilation issue - [THRIFT-4671](https://issues.apache.org/jira/browse/THRIFT-4671) - c glib is unable to handle client close unexpectedly ### cl (new language support in 0.12.0) - [THRIFT-82](https://issues.apache.org/jira/browse/THRIFT-82) - Common Lisp support ### csharp - [THRIFT-4558](https://issues.apache.org/jira/browse/THRIFT-4558) - reserved Csharp keywords are not escaped in some cases - [THRIFT-4637](https://issues.apache.org/jira/browse/THRIFT-4637) - C# async mode generates incorrect code with inherited services - [THRIFT-4672](https://issues.apache.org/jira/browse/THRIFT-4672) - IAsyncResult style methods not being supported by certain transports leads to issues in mixed ISync/IAsync use cases - [THRIFT-4539](https://issues.apache.org/jira/browse/THRIFT-4539) - Allow TBufferedTransport to be used as base class - [THRIFT-4535](https://issues.apache.org/jira/browse/THRIFT-4535) - XML docs; code cleanup (tabs->spaces; String->string) - [THRIFT-4492](https://issues.apache.org/jira/browse/THRIFT-4492) - protected ExceptionType type member of TApplicationException cannot be accessed - [THRIFT-4446](https://issues.apache.org/jira/browse/THRIFT-4446) - JSONProtocol Base64 Encoding Trims Padding - [THRIFT-4455](https://issues.apache.org/jira/browse/THRIFT-4455) - Missing dispose calls in ThreadedServer & ThreadpoolServer - [THRIFT-4609](https://issues.apache.org/jira/browse/THRIFT-4609) - keep InnerException wherever appropriate - [THRIFT-4673](https://issues.apache.org/jira/browse/THRIFT-4673) - IAsyncResult not supported by layered transports (buffered/framed) ### cpp - [THRIFT-4476](https://issues.apache.org/jira/browse/THRIFT-4476) - Typecasting problem on list items - [THRIFT-4465](https://issues.apache.org/jira/browse/THRIFT-4465) - TNonblockingServer throwing THRIFT LOGGER: TConnection::workSocket(): THRIFT_EAGAIN (unavailable resources) - [THRIFT-4680](https://issues.apache.org/jira/browse/THRIFT-4680) - TBufferTransports.h does not compile under Visual Studio 2017 - [THRIFT-4618](https://issues.apache.org/jira/browse/THRIFT-4618) - TNonblockingServer crash because of limitation of select() - [THRIFT-4620](https://issues.apache.org/jira/browse/THRIFT-4620) - TZlibTransport.cpp doesn't ensure that there is enough space for the zlib flush marker in the buffer. - [THRIFT-4571](https://issues.apache.org/jira/browse/THRIFT-4571) - ZeroMQ contrib library needs a refresh - [THRIFT-4559](https://issues.apache.org/jira/browse/THRIFT-4559) - TSSLServerSocket incorrectly prints errors - [THRIFT-4578](https://issues.apache.org/jira/browse/THRIFT-4578) - Move `TAsyncProtocolProcessor` into main thrift library - [THRIFT-4418](https://issues.apache.org/jira/browse/THRIFT-4418) - evhttp_connection_new is deprecated; use evhttp_connection_base_new ### compiler - [THRIFT-4644](https://issues.apache.org/jira/browse/THRIFT-4644) - Compiler cannot be compiled on macOS(maybe also on other platforms with clang) - [THRIFT-4531](https://issues.apache.org/jira/browse/THRIFT-4531) - Thrift generates wrong Python code for immutable structures with optional members - [THRIFT-4513](https://issues.apache.org/jira/browse/THRIFT-4513) - thrift generated code is not stable for constants - [THRIFT-4532](https://issues.apache.org/jira/browse/THRIFT-4532) - Avoid updating Thrift compiler generated code if the output has not changed - [THRIFT-4400](https://issues.apache.org/jira/browse/THRIFT-4400) - Visual Studio Compiler project should link runtime statically in release builds - [THRIFT-4399](https://issues.apache.org/jira/browse/THRIFT-4399) - plugin.thrift t_const_value is not used as a union in C++ code -- fix this - [THRIFT-4496](https://issues.apache.org/jira/browse/THRIFT-4496) - Dealing with language keywords in Thrift (e.g. service method names) - [THRIFT-4393](https://issues.apache.org/jira/browse/THRIFT-4393) - repeated runs of compiler produce different binary output at plugin interface ### dlang - [THRIFT-4478](https://issues.apache.org/jira/browse/THRIFT-4478) - Thrift will not build with dlang 2.078 or later - [THRIFT-4503](https://issues.apache.org/jira/browse/THRIFT-4503) - dlang servers logError on normal client disconnection - [THRIFT-4308](https://issues.apache.org/jira/browse/THRIFT-4308) - D language docker images need demios for libevent and openssl fixed to re-enable make cross on dlang ### dart - [THRIFT-4646](https://issues.apache.org/jira/browse/THRIFT-4646) - Effective Dart and Exceptions - [THRIFT-4439](https://issues.apache.org/jira/browse/THRIFT-4439) - Shouldn't download dart.deb directly. ### delphi - [THRIFT-4562](https://issues.apache.org/jira/browse/THRIFT-4562) - Calling wrong exception CTOR leads to "call failed: unknown result" instead of the real exception being thrown - [THRIFT-4554](https://issues.apache.org/jira/browse/THRIFT-4554) - uncompileable code with member names that are also types under specific conditions - [THRIFT-4422](https://issues.apache.org/jira/browse/THRIFT-4422) - Add Async implementation via IFuture - [THRIFT-4485](https://issues.apache.org/jira/browse/THRIFT-4485) - Possible invalid ptr AV with overlapped read/write on pipes - [THRIFT-4549](https://issues.apache.org/jira/browse/THRIFT-4549) - Thrift exceptions should derive from TException - [THRIFT-4540](https://issues.apache.org/jira/browse/THRIFT-4540) - buffered transport broken when trying to re-open a formerly closed transport - [THRIFT-4473](https://issues.apache.org/jira/browse/THRIFT-4473) - Move Thrift.Console.pas out of the Library - [THRIFT-4490](https://issues.apache.org/jira/browse/THRIFT-4490) - Allow a default service as fallback for multiplex processors connected by old clients - [THRIFT-4454](https://issues.apache.org/jira/browse/THRIFT-4454) - Large writes/reads may cause range check errors in debug mode - [THRIFT-4461](https://issues.apache.org/jira/browse/THRIFT-4461) - Compiler directive should match Delphi XE4 - [THRIFT-4462](https://issues.apache.org/jira/browse/THRIFT-4462) - First line in Console duplicated - [THRIFT-4642](https://issues.apache.org/jira/browse/THRIFT-4642) - FPU ctrl word settings may cause an unexpected "denormalized" error - [THRIFT-4589](https://issues.apache.org/jira/browse/THRIFT-4589) - HTTP client timeouts are a) incomplete and b) not used at all - [THRIFT-4590](https://issues.apache.org/jira/browse/THRIFT-4590) - running the test client using HTTP transport leads to "CoInitialize not called" ### erlang - [THRIFT-4497](https://issues.apache.org/jira/browse/THRIFT-4497) - Erlang records should use map() for map type - [THRIFT-4495](https://issues.apache.org/jira/browse/THRIFT-4495) - Erlang records should allow 'undefined' for non-required fields - [THRIFT-4580](https://issues.apache.org/jira/browse/THRIFT-4580) - Fix erlang tutorial unpack on Windows - [THRIFT-4582](https://issues.apache.org/jira/browse/THRIFT-4582) - Ubuntu Xenial erlang 18.3 "make check" fails ### golang - [THRIFT-4448](https://issues.apache.org/jira/browse/THRIFT-4448) - Support for golang 1.6 and earlier has been dropped. - [THRIFT-4253](https://issues.apache.org/jira/browse/THRIFT-4253) - Go generator assigns strings to field in const instead of pointers. - [THRIFT-4573](https://issues.apache.org/jira/browse/THRIFT-4573) - Unions Field Count Does Not Consider Binary - [THRIFT-4447](https://issues.apache.org/jira/browse/THRIFT-4447) - Golang: Panic on p.c.Call when using deprecated initializers - [THRIFT-4650](https://issues.apache.org/jira/browse/THRIFT-4650) - Required field incorrectly marked as set when fieldType does not match - [THRIFT-4486](https://issues.apache.org/jira/browse/THRIFT-4486) - Golang: -remote.go client cleanup - [THRIFT-4537](https://issues.apache.org/jira/browse/THRIFT-4537) - TSimpleServer can exit Accept loop with lock still acquired - [THRIFT-4516](https://issues.apache.org/jira/browse/THRIFT-4516) - Add support for go 1.10 - [THRIFT-4421](https://issues.apache.org/jira/browse/THRIFT-4421) - golang tests rely on gomock, which has change behaviour, causing tests to fail - [THRIFT-4626](https://issues.apache.org/jira/browse/THRIFT-4626) - Communication crash when using binary/compact protocol and zlib transport - [THRIFT-4659](https://issues.apache.org/jira/browse/THRIFT-4659) - golang race detected when closing listener socket ### haskell - [THRIFT-4634](https://issues.apache.org/jira/browse/THRIFT-4634) - Haskell builds with older cabal cannot reconcile complex version requirements ### java - [THRIFT-4259](https://issues.apache.org/jira/browse/THRIFT-4259) - Thrift does not compile due to Ant Maven task errors - [THRIFT-1418](https://issues.apache.org/jira/browse/THRIFT-1418) - Compiling Thrift from source: Class org.apache.tools.ant.taskdefs.ConditionTask doesn't support the nested "typefound" element - [THRIFT-4530](https://issues.apache.org/jira/browse/THRIFT-4530) - proposal: add nullability annotations to generated Java code - [THRIFT-4614](https://issues.apache.org/jira/browse/THRIFT-4614) - Generate missing @Nullable annotations for Java iterator getters - [THRIFT-4555](https://issues.apache.org/jira/browse/THRIFT-4555) - Getter of binary field in Java creates unnecessary copy - [THRIFT-3983](https://issues.apache.org/jira/browse/THRIFT-3983) - libthrift is deployed on central with pom packaging instead of jar - [THRIFT-4294](https://issues.apache.org/jira/browse/THRIFT-4294) - Java Configure Fails for Ant >= 1.10 - [THRIFT-4178](https://issues.apache.org/jira/browse/THRIFT-4178) - Java libraries missing from package when using cmake - [THRIFT-4120](https://issues.apache.org/jira/browse/THRIFT-4120) - pom files are not generated or provided in the build - [THRIFT-1507](https://issues.apache.org/jira/browse/THRIFT-1507) - Maven can't download resource from central when behind a proxy and won't use local repository - [THRIFT-4556](https://issues.apache.org/jira/browse/THRIFT-4556) - Optional rethrow of unhandled exceptions in java processor - [THRIFT-4337](https://issues.apache.org/jira/browse/THRIFT-4337) - Able to set keyStore and trustStore as InputStream in the TSSLTransportFactory.TSSLTransportParameters - [THRIFT-4566](https://issues.apache.org/jira/browse/THRIFT-4566) - Pass message of unhandled exception to optional rethrow. - [THRIFT-4506](https://issues.apache.org/jira/browse/THRIFT-4506) - Remove assertion in Java SASL code that would be ignored in release builds - [THRIFT-4470](https://issues.apache.org/jira/browse/THRIFT-4470) - Include popular IDE file templates to gitignore - [THRIFT-4429](https://issues.apache.org/jira/browse/THRIFT-4429) - Make TThreadPoolServer.executorService_ available in inherited classes and refactor methods to be able customization - [THRIFT-3769](https://issues.apache.org/jira/browse/THRIFT-3769) - Fix logic of THRIFT-2268 - [THRIFT-4494](https://issues.apache.org/jira/browse/THRIFT-4494) - Increase Java Socket Buffer Size - [THRIFT-4499](https://issues.apache.org/jira/browse/THRIFT-4499) - Remove Magic Number In TFIleTransport ### js - [THRIFT-4406](https://issues.apache.org/jira/browse/THRIFT-4406) - JavaScript: Use modern Promise implementations - [THRIFT-4625](https://issues.apache.org/jira/browse/THRIFT-4625) - let / const variable decorators for es6 compiler - [THRIFT-4653](https://issues.apache.org/jira/browse/THRIFT-4653) - ES6 Classes - [THRIFT-4592](https://issues.apache.org/jira/browse/THRIFT-4592) - JS: readI32 performance on large arrays is very poor in Chrome - [THRIFT-4509](https://issues.apache.org/jira/browse/THRIFT-4509) - js and nodejs libraries need to be refreshed with current libraries - [THRIFT-4403](https://issues.apache.org/jira/browse/THRIFT-4403) - thrift.js: Incorrect usage of 'this' in TWebSocketTransport.__onOpen - [THRIFT-4436](https://issues.apache.org/jira/browse/THRIFT-4436) - Deserialization of nested list discards content - [THRIFT-4437](https://issues.apache.org/jira/browse/THRIFT-4437) - JS WebSocket client callbacks invoked twice on parallel requests - [THRIFT-4679](https://issues.apache.org/jira/browse/THRIFT-4679) - Duplicate declaration of InputBufferUnderrunError in lib/nodejs/lib/thrift/json_protocol.js - [THRIFT-4551](https://issues.apache.org/jira/browse/THRIFT-4551) - Add prettier for consistent JS code formatting ### lua - [THRIFT-4591](https://issues.apache.org/jira/browse/THRIFT-4591) - lua client uses two write() calls per framed message send - [THRIFT-3863](https://issues.apache.org/jira/browse/THRIFT-3863) - Can't "make install" Lua Library ### netcore - [THRIFT-4524](https://issues.apache.org/jira/browse/THRIFT-4524) - .NET Core Server doesn't close properly when cancelled - [THRIFT-4434](https://issues.apache.org/jira/browse/THRIFT-4434) - Update .NET Core components, add tests for .Net Core library and .Net Core compiler, fix bugs and build process - [THRIFT-4446](https://issues.apache.org/jira/browse/THRIFT-4446) - JSONProtocol Base64 Encoding Trims Padding ### node.js - [THRIFT-4225](https://issues.apache.org/jira/browse/THRIFT-4225) - Error handling malformed arguments leaks memory, corrupts transport buffers causing next RPC to fail - [THRIFT-3950](https://issues.apache.org/jira/browse/THRIFT-3950) - Memory leak while calling oneway method - [THRIFT-3143](https://issues.apache.org/jira/browse/THRIFT-3143) - add typescript directory support - [THRIFT-4564](https://issues.apache.org/jira/browse/THRIFT-4564) - TBufferedTransport can leave corrupt data in the buffer - [THRIFT-4647](https://issues.apache.org/jira/browse/THRIFT-4647) - Node.js Fileserver webroot path - [THRIFT-4489](https://issues.apache.org/jira/browse/THRIFT-4489) - Unix domain socket support for NodeJS client - [THRIFT-4443](https://issues.apache.org/jira/browse/THRIFT-4443) - node.js json_protocol throws error in skip function - [THRIFT-4604](https://issues.apache.org/jira/browse/THRIFT-4604) - NodeJS: Expose Int64 from browser.js for consumption by browser - [THRIFT-4480](https://issues.apache.org/jira/browse/THRIFT-4480) - NodeJS warning on binary_protocol writeMessageEnd when seqid = 0 ### perl - [THRIFT-4382](https://issues.apache.org/jira/browse/THRIFT-4382) - Replace the use of Perl Indirect Object Syntax calls to new() - [THRIFT-4471](https://issues.apache.org/jira/browse/THRIFT-4471) - Thrift CPAN release is missing Makefile.PL and the clients are unable to build the module - [THRIFT-4416](https://issues.apache.org/jira/browse/THRIFT-4416) - Perl CPAN Packaging Improvements ### php - [THRIFT-4474](https://issues.apache.org/jira/browse/THRIFT-4474) - PHP generator use PSR-4 default - [THRIFT-4463](https://issues.apache.org/jira/browse/THRIFT-4463) - PHP generated code match PSR-2 - [THRIFT-4373](https://issues.apache.org/jira/browse/THRIFT-4373) - Extending Thrift class results in "Attempt serialize from non-Thrift object" - [THRIFT-4354](https://issues.apache.org/jira/browse/THRIFT-4354) - TSocket block on read - [THRIFT-4423](https://issues.apache.org/jira/browse/THRIFT-4423) - migrate php library to psr-4 - [THRIFT-4656](https://issues.apache.org/jira/browse/THRIFT-4656) - infinite loop in latest PHP library - [THRIFT-4477](https://issues.apache.org/jira/browse/THRIFT-4477) - TBufferedTransport must have underlying transport - [THRIFT-4475](https://issues.apache.org/jira/browse/THRIFT-4475) - lib/php/test should be checked for PSR-2 - [THRIFT-4498](https://issues.apache.org/jira/browse/THRIFT-4498) - add phpcs back - [THRIFT-4460](https://issues.apache.org/jira/browse/THRIFT-4460) - php library use PSR-2 - [THRIFT-4641](https://issues.apache.org/jira/browse/THRIFT-4641) - TCurlClient doesn't check for HTTP status code - [THRIFT-4645](https://issues.apache.org/jira/browse/THRIFT-4645) - TCurlClient: show actual error message when throwing TTransportException - [THRIFT-4674](https://issues.apache.org/jira/browse/THRIFT-4674) - Add stream context support into PHP/THttpClient - [THRIFT-4459](https://issues.apache.org/jira/browse/THRIFT-4459) - reduce php library directory depth ### python - [THRIFT-4670](https://issues.apache.org/jira/browse/THRIFT-4670) - Twisted, slots, and void method fails with "object has no attribute 'success'" - [THRIFT-4464](https://issues.apache.org/jira/browse/THRIFT-4464) - Potentially server-crashing typo in Python TNonblockingServer - [THRIFT-4548](https://issues.apache.org/jira/browse/THRIFT-4548) - Supporting TBinaryProtocolAccelerated protocol when using TMultiplexedProcessor in Python - [THRIFT-4577](https://issues.apache.org/jira/browse/THRIFT-4577) - Outdated cipher string in python unit test - [THRIFT-4505](https://issues.apache.org/jira/browse/THRIFT-4505) - python build on Vagrant Windows boxes fails - [THRIFT-4621](https://issues.apache.org/jira/browse/THRIFT-4621) - THeader for Python - [THRIFT-4668](https://issues.apache.org/jira/browse/THRIFT-4668) - make socket backlog configurable for python - [THRIFT-4561](https://issues.apache.org/jira/browse/THRIFT-4561) - Python: cleanup socket timeout settings ### ruby - [THRIFT-4289](https://issues.apache.org/jira/browse/THRIFT-4289) - Thrift RSpec test suite fails with Ruby 2.4.x due to Fixnum deprecation - [THRIFT-4342](https://issues.apache.org/jira/browse/THRIFT-4342) - Support ruby rspec 3 - [THRIFT-4525](https://issues.apache.org/jira/browse/THRIFT-4525) - Add ssl socket option to ruby cross tests - [THRIFT-4450](https://issues.apache.org/jira/browse/THRIFT-4450) - Add seek support to TCompactInputProtocol in Rust - [THRIFT-4631](https://issues.apache.org/jira/browse/THRIFT-4631) - Codegen Creates Invalid Ruby for Recursive Structs - [THRIFT-4472](https://issues.apache.org/jira/browse/THRIFT-4472) - Fix the genspec for ruby so it does not complain about an invalid license ### rust - [THRIFT-4662](https://issues.apache.org/jira/browse/THRIFT-4662) - Rust const string calls function at compile time - [THRIFT-4661](https://issues.apache.org/jira/browse/THRIFT-4661) - Rust enum name wrong case in generated structs - [THRIFT-4617](https://issues.apache.org/jira/browse/THRIFT-4617) - Avoid generating conflicting struct names in Rust code - [THRIFT-4529](https://issues.apache.org/jira/browse/THRIFT-4529) - Rust generation should include #![allow(non_snake_case)] or force conform to Rust style guidelines - [THRIFT-4390](https://issues.apache.org/jira/browse/THRIFT-4390) - Rust binary protocol and buffered transport cannot handle writes above 4096 bytes - [THRIFT-4419](https://issues.apache.org/jira/browse/THRIFT-4419) - Rust framed transport cannot handle writes above 4096 bytes - [THRIFT-4658](https://issues.apache.org/jira/browse/THRIFT-4658) - Rust's TBinaryInputProtocol fails when strict is false - [THRIFT-4187](https://issues.apache.org/jira/browse/THRIFT-4187) - Dart -> Rust Framed cross tests fail - [THRIFT-4664](https://issues.apache.org/jira/browse/THRIFT-4664) - Rust cannot create ReadHalf/WriteHalf to implement custom tranports - [THRIFT-4665](https://issues.apache.org/jira/browse/THRIFT-4665) - Keep Rust library up-to-date on crates.io ### swift (new language support in 0.12.0) - [THRIFT-3773](https://issues.apache.org/jira/browse/THRIFT-3773) - Swift Library ### test suite - [THRIFT-4515](https://issues.apache.org/jira/browse/THRIFT-4515) - Gracefully shutdown cross-test servers to fully test teardown - [THRIFT-4085](https://issues.apache.org/jira/browse/THRIFT-4085) - Add .NET Core to the make cross standard test suite - [THRIFT-4358](https://issues.apache.org/jira/browse/THRIFT-4358) - Add unix domain sockets in ruby to cross test) - code exists ### typescript (new language support in 0.12.0) - [THRIFT-3143](https://issues.apache.org/jira/browse/THRIFT-3143) - add typescript directory support ## 0.11.0 Released 2017-DEC-27 ### Sub-task - [THRIFT-2733](https://issues.apache.org/jira/browse/THRIFT-2733) - Erlang coding standards - [THRIFT-2740](https://issues.apache.org/jira/browse/THRIFT-2740) - Perl coding standards - [THRIFT-3610](https://issues.apache.org/jira/browse/THRIFT-3610) - Streamline exception handling in Python server handler - [THRIFT-3686](https://issues.apache.org/jira/browse/THRIFT-3686) - Java processor should report internal error on uncaught exception - [THRIFT-4049](https://issues.apache.org/jira/browse/THRIFT-4049) - Skip() should throw TProtocolException.INVALID_DATA on unknown data types - [THRIFT-4053](https://issues.apache.org/jira/browse/THRIFT-4053) - Skip() should throw TProtocolException.INVALID_DATA on unknown data types - [THRIFT-4136](https://issues.apache.org/jira/browse/THRIFT-4136) - Align is_binary() method with is_string() to simplify those checks - [THRIFT-4137](https://issues.apache.org/jira/browse/THRIFT-4137) - Fix remaining undefined behavior invalid vptr casts in Thrift Compiler - [THRIFT-4138](https://issues.apache.org/jira/browse/THRIFT-4138) - Fix remaining undefined behavior invalid vptr casts in C++ library - [THRIFT-4296](https://issues.apache.org/jira/browse/THRIFT-4296) - Fix Ubuntu Xenial build environment for the python language - [THRIFT-4298](https://issues.apache.org/jira/browse/THRIFT-4298) - Fix Ubuntu Xenial build environment for the go 1.6 language - [THRIFT-4299](https://issues.apache.org/jira/browse/THRIFT-4299) - Fix Ubuntu Xenial build environment for the D language - [THRIFT-4300](https://issues.apache.org/jira/browse/THRIFT-4300) - Fix make cross in Ubuntu Xenial docker environment, once all language support issues are fixed - [THRIFT-4302](https://issues.apache.org/jira/browse/THRIFT-4302) - Fix Ubuntu Xenial make cross testing for lua and php7 - [THRIFT-4398](https://issues.apache.org/jira/browse/THRIFT-4398) - Update EXTRA_DIST for "make dist" ### Bug - [THRIFT-381](https://issues.apache.org/jira/browse/THRIFT-381) - Fail fast if configure detects C++ problems - [THRIFT-1677](https://issues.apache.org/jira/browse/THRIFT-1677) - MinGW support broken - [THRIFT-1805](https://issues.apache.org/jira/browse/THRIFT-1805) - Thrift should not swallow ALL exceptions - [THRIFT-2026](https://issues.apache.org/jira/browse/THRIFT-2026) - Fix TCompactProtocol 64 bit builds - [THRIFT-2642](https://issues.apache.org/jira/browse/THRIFT-2642) - Recursive structs don't work in python - [THRIFT-2889](https://issues.apache.org/jira/browse/THRIFT-2889) - stable release 0.9.2, erlang tutorial broken - [THRIFT-2913](https://issues.apache.org/jira/browse/THRIFT-2913) - Ruby Server Thrift::ThreadPoolServer should serve inside a thread - [THRIFT-2998](https://issues.apache.org/jira/browse/THRIFT-2998) - Node.js: Missing header from http request - [THRIFT-3000](https://issues.apache.org/jira/browse/THRIFT-3000) - .NET implementation has trouble with mixed IP modes - [THRIFT-3281](https://issues.apache.org/jira/browse/THRIFT-3281) - Travis CI build passed but the log says BUILD FAILED - [THRIFT-3358](https://issues.apache.org/jira/browse/THRIFT-3358) - Makefile:1362: *** missing separator. Stop. - [THRIFT-3600](https://issues.apache.org/jira/browse/THRIFT-3600) - Make TTwisted server send exception on unexpected handler error - [THRIFT-3602](https://issues.apache.org/jira/browse/THRIFT-3602) - Make Tornado server send exception on unexpected handler error - [THRIFT-3657](https://issues.apache.org/jira/browse/THRIFT-3657) - D TFileWriterTransport close should use non-priority send - [THRIFT-3700](https://issues.apache.org/jira/browse/THRIFT-3700) - Go Map has wrong default value when optional - [THRIFT-3703](https://issues.apache.org/jira/browse/THRIFT-3703) - Unions Field Count Does Not Consider Map/Set/List Fields - [THRIFT-3730](https://issues.apache.org/jira/browse/THRIFT-3730) - server log error twice - [THRIFT-3778](https://issues.apache.org/jira/browse/THRIFT-3778) - go client can not pass method parameter to server of other language if no field_id is given - [THRIFT-3784](https://issues.apache.org/jira/browse/THRIFT-3784) - thrift-maven-plugin generates invalid include directories for IDL in dependency JARs - [THRIFT-3801](https://issues.apache.org/jira/browse/THRIFT-3801) - Node Thrift client throws exception with multiplexer and responses that are bigger than a single buffer - [THRIFT-3821](https://issues.apache.org/jira/browse/THRIFT-3821) - TMemoryBuffer buffer may overflow when resizing - [THRIFT-3832](https://issues.apache.org/jira/browse/THRIFT-3832) - Thrift version 0.9.3 example on Windows, Visual Studio, linking errors during compiling - [THRIFT-3847](https://issues.apache.org/jira/browse/THRIFT-3847) - thrift/config.h includes a #define for VERSION which will likely conflict with existing user environment or code - [THRIFT-3873](https://issues.apache.org/jira/browse/THRIFT-3873) - Fix various build warnings when using Visual Studio - [THRIFT-3891](https://issues.apache.org/jira/browse/THRIFT-3891) - TNonblockingServer configured with more than one IO threads does not always return from serve() upon stop() - [THRIFT-3892](https://issues.apache.org/jira/browse/THRIFT-3892) - Thrift uses TLS SNI extension provided by OpenSSL library. Older version of OpenSSL(< 0.9.8f) may create problem because they do not support 'SSL_set_tlsext_host_name()'. - [THRIFT-3895](https://issues.apache.org/jira/browse/THRIFT-3895) - Build fails using Java 1.8 with Ant < 1.9 - [THRIFT-3896](https://issues.apache.org/jira/browse/THRIFT-3896) - map data with number string key cannot access that deserialized by php extension - [THRIFT-3938](https://issues.apache.org/jira/browse/THRIFT-3938) - Python TNonblockingServer does not work with SSL - [THRIFT-3944](https://issues.apache.org/jira/browse/THRIFT-3944) - TSSLSocket has dead code in checkHandshake - [THRIFT-3946](https://issues.apache.org/jira/browse/THRIFT-3946) - Java 1.5 compatibility broken for binary fields (java5 option) - [THRIFT-3960](https://issues.apache.org/jira/browse/THRIFT-3960) - Inherited services in Lua generator are not named correctly - [THRIFT-3962](https://issues.apache.org/jira/browse/THRIFT-3962) - Ant build.xml broken on Windows for Java library - [THRIFT-3963](https://issues.apache.org/jira/browse/THRIFT-3963) - Thrift.cabal filename does not match module name - [THRIFT-3967](https://issues.apache.org/jira/browse/THRIFT-3967) - gobject/gparam.h:166:33: warning: enumerator value for ‘G_PARAM_DEPRECATED’ is not an integer constant expression - [THRIFT-3968](https://issues.apache.org/jira/browse/THRIFT-3968) - Deserializing empty string/binary fields - [THRIFT-3974](https://issues.apache.org/jira/browse/THRIFT-3974) - Using clang-3.8 and ThreadSanitizer on the concurrency_test claims bad PThread behavior - [THRIFT-3984](https://issues.apache.org/jira/browse/THRIFT-3984) - PHP7 extension causes segfault - [THRIFT-4008](https://issues.apache.org/jira/browse/THRIFT-4008) - broken ci due to upstream dependency versioning break - [THRIFT-4009](https://issues.apache.org/jira/browse/THRIFT-4009) - Use @implementer instead of implements in TTwisted.py - [THRIFT-4010](https://issues.apache.org/jira/browse/THRIFT-4010) - Q.fcall messing up with *this* pointer inside called function - [THRIFT-4011](https://issues.apache.org/jira/browse/THRIFT-4011) - Sets of Thrift structs generate Go code that can't be serialized to JSON - [THRIFT-4012](https://issues.apache.org/jira/browse/THRIFT-4012) - Python Twisted implementation uses implements, not compatible with Py3 - [THRIFT-4014](https://issues.apache.org/jira/browse/THRIFT-4014) - align C# meta data in AssemblyInfo.cs - [THRIFT-4015](https://issues.apache.org/jira/browse/THRIFT-4015) - Fix wrongly spelled "Thirft"s - [THRIFT-4016](https://issues.apache.org/jira/browse/THRIFT-4016) - testInsanity() impl does not conform to test spec in ThriftTest.thrift - [THRIFT-4023](https://issues.apache.org/jira/browse/THRIFT-4023) - Skip unexpected field types on read/write - [THRIFT-4024](https://issues.apache.org/jira/browse/THRIFT-4024) - Skip() should throw on unknown data types - [THRIFT-4026](https://issues.apache.org/jira/browse/THRIFT-4026) - TSSLSocket doesn't work with Python < 2.7.9 - [THRIFT-4029](https://issues.apache.org/jira/browse/THRIFT-4029) - Accelerated protocols do not build from thrift-py 0.10.0 on PyPI - [THRIFT-4031](https://issues.apache.org/jira/browse/THRIFT-4031) - Go plugin generates invalid code for lists of typedef'ed built-in types - [THRIFT-4033](https://issues.apache.org/jira/browse/THRIFT-4033) - Default build WITH_PLUGIN=ON for all builds results in packaging errors - [THRIFT-4034](https://issues.apache.org/jira/browse/THRIFT-4034) - CMake doesn't work to build compiler on MacOS - [THRIFT-4036](https://issues.apache.org/jira/browse/THRIFT-4036) - Add .NET Core environment/build support to the docker image - [THRIFT-4038](https://issues.apache.org/jira/browse/THRIFT-4038) - socket check: checking an unsigned number against >= 0 never fails - [THRIFT-4042](https://issues.apache.org/jira/browse/THRIFT-4042) - ExtractionError when using accelerated thrift in a multiprocess test - [THRIFT-4043](https://issues.apache.org/jira/browse/THRIFT-4043) - thrift perl debian package is placing files in the wrong place - [THRIFT-4044](https://issues.apache.org/jira/browse/THRIFT-4044) - Build job 17 failing on every pull request; hspec core (haskell) 2.4 issue - [THRIFT-4046](https://issues.apache.org/jira/browse/THRIFT-4046) - MinGW with gcc 6.2 does not compile on Windows - [THRIFT-4060](https://issues.apache.org/jira/browse/THRIFT-4060) - Thrift printTo ostream overload mechanism breaks down when types are nested - [THRIFT-4062](https://issues.apache.org/jira/browse/THRIFT-4062) - Remove debug print from TServiceClient - [THRIFT-4065](https://issues.apache.org/jira/browse/THRIFT-4065) - Document Perl ForkingServer signal restriction imposed by THRIFT-3848 and remove unnecessary code - [THRIFT-4068](https://issues.apache.org/jira/browse/THRIFT-4068) - A code comment in Java ServerSocket is wrong around accept() - [THRIFT-4073](https://issues.apache.org/jira/browse/THRIFT-4073) - enum files are still being generated with unused imports - [THRIFT-4076](https://issues.apache.org/jira/browse/THRIFT-4076) - Appveyor builds failing because ant 1.9.8 was removed from apache servers - [THRIFT-4077](https://issues.apache.org/jira/browse/THRIFT-4077) - AI_ADDRCONFIG redefined after recent change to PlatformSocket header - [THRIFT-4079](https://issues.apache.org/jira/browse/THRIFT-4079) - Generated perl code that returns structures from included thrift files is missing a necessary use clause - [THRIFT-4087](https://issues.apache.org/jira/browse/THRIFT-4087) - Spurious exception destroying TThreadedServer because of incorrect join() call - [THRIFT-4102](https://issues.apache.org/jira/browse/THRIFT-4102) - TBufferedTransport performance issue since 0.10.0 - [THRIFT-4106](https://issues.apache.org/jira/browse/THRIFT-4106) - concurrency_test fails randomly - [THRIFT-4108](https://issues.apache.org/jira/browse/THRIFT-4108) - c_glib thrift ssl has multiple bugs and deprecated functions - [THRIFT-4109](https://issues.apache.org/jira/browse/THRIFT-4109) - Configure Script uses string comparison for versions - [THRIFT-4129](https://issues.apache.org/jira/browse/THRIFT-4129) - C++ TNonblockingServer fd leak when failing to dispatch new connections - [THRIFT-4131](https://issues.apache.org/jira/browse/THRIFT-4131) - Javascript with WebSocket handles oneway methods wrong - [THRIFT-4134](https://issues.apache.org/jira/browse/THRIFT-4134) - Fix remaining undefined behavior invalid vptr casts - [THRIFT-4140](https://issues.apache.org/jira/browse/THRIFT-4140) - Use of non-thread-safe function gmtime() - [THRIFT-4141](https://issues.apache.org/jira/browse/THRIFT-4141) - Installation of haxe in docker files refers to a redirect link and fails - [THRIFT-4147](https://issues.apache.org/jira/browse/THRIFT-4147) - Rust: protocol should accept transports with non-static lifetime - [THRIFT-4148](https://issues.apache.org/jira/browse/THRIFT-4148) - [maven-thrift-plugin] compile error while import a thrift in dependency jar file. - [THRIFT-4149](https://issues.apache.org/jira/browse/THRIFT-4149) - System.out pollutes log files - [THRIFT-4154](https://issues.apache.org/jira/browse/THRIFT-4154) - PHP close() of a TSocket needs to close any type of socket - [THRIFT-4158](https://issues.apache.org/jira/browse/THRIFT-4158) - minor issue in README-MSYS2.md - [THRIFT-4159](https://issues.apache.org/jira/browse/THRIFT-4159) - Building tests fails on MSYS2 (MinGW64) due to a (small?) linker error - [THRIFT-4160](https://issues.apache.org/jira/browse/THRIFT-4160) - TNonblocking server fix use of closed/freed connections - [THRIFT-4161](https://issues.apache.org/jira/browse/THRIFT-4161) - TNonBlocking server using uninitialized event in error paths - [THRIFT-4162](https://issues.apache.org/jira/browse/THRIFT-4162) - TNonBlocking handling of TSockets in error state is incorrect after fd is closed - [THRIFT-4164](https://issues.apache.org/jira/browse/THRIFT-4164) - Core in TSSLSocket cleanupOpenSSL when destroying a mutex used by openssl - [THRIFT-4165](https://issues.apache.org/jira/browse/THRIFT-4165) - C++ build has many warnings under c++03 due to recent changes, cmake needs better platform-independent language level control - [THRIFT-4166](https://issues.apache.org/jira/browse/THRIFT-4166) - Recent fix to remove boost::lexical_cast usage broke VS2010 - [THRIFT-4167](https://issues.apache.org/jira/browse/THRIFT-4167) - Missing compile flag - [THRIFT-4170](https://issues.apache.org/jira/browse/THRIFT-4170) - Support lua 5.1 or earlier properly for object length determination - [THRIFT-4172](https://issues.apache.org/jira/browse/THRIFT-4172) - node.js tutorial client does not import assert, connection issues are not handled properly - [THRIFT-4177](https://issues.apache.org/jira/browse/THRIFT-4177) - Java compiler produces deep copy constructor that could make shallow copy instead - [THRIFT-4184](https://issues.apache.org/jira/browse/THRIFT-4184) - Building on Appveyor: invalid escape sequence \L - [THRIFT-4185](https://issues.apache.org/jira/browse/THRIFT-4185) - fb303 counter encoding fix - [THRIFT-4189](https://issues.apache.org/jira/browse/THRIFT-4189) - Framed/buffered transport Dispose() does not dispose the nested transport - [THRIFT-4193](https://issues.apache.org/jira/browse/THRIFT-4193) - Lower the default maxReadBufferBytes for non-blocking servers - [THRIFT-4195](https://issues.apache.org/jira/browse/THRIFT-4195) - Compilation to GO produces broken code - [THRIFT-4196](https://issues.apache.org/jira/browse/THRIFT-4196) - Cannot generate recursive Rust types - [THRIFT-4204](https://issues.apache.org/jira/browse/THRIFT-4204) - typo in compact spec - [THRIFT-4206](https://issues.apache.org/jira/browse/THRIFT-4206) - Strings in container fields are not decoded properly with py:dynamic and py:utf8strings - [THRIFT-4208](https://issues.apache.org/jira/browse/THRIFT-4208) - C# NamedPipesServer not really working in some scenarios - [THRIFT-4211](https://issues.apache.org/jira/browse/THRIFT-4211) - Fix GError glib management under Thrift - [THRIFT-4212](https://issues.apache.org/jira/browse/THRIFT-4212) - c_glib flush tries to close SSL even if socket is invalid - [THRIFT-4213](https://issues.apache.org/jira/browse/THRIFT-4213) - Travis build fails at curl -sSL https://www.npmjs.com/install.sh | sh - [THRIFT-4215](https://issues.apache.org/jira/browse/THRIFT-4215) - Golang TTransportFactory Pattern Squelches Errors - [THRIFT-4216](https://issues.apache.org/jira/browse/THRIFT-4216) - Golang Http Clients Do Not Respect User Options - [THRIFT-4218](https://issues.apache.org/jira/browse/THRIFT-4218) - Set TCP_NODELAY for PHP client socket - [THRIFT-4219](https://issues.apache.org/jira/browse/THRIFT-4219) - Golang HTTP clients created with Nil buffer - [THRIFT-4231](https://issues.apache.org/jira/browse/THRIFT-4231) - TJSONProtocol throws unexpected non-Thrift-exception on null strings - [THRIFT-4232](https://issues.apache.org/jira/browse/THRIFT-4232) - ./configure does bad ant version check - [THRIFT-4234](https://issues.apache.org/jira/browse/THRIFT-4234) - Travis build fails cross language tests with "Unsupported security protocol type" - [THRIFT-4237](https://issues.apache.org/jira/browse/THRIFT-4237) - Go TServerSocket Race Conditions - [THRIFT-4240](https://issues.apache.org/jira/browse/THRIFT-4240) - Go TSimpleServer does not close properly - [THRIFT-4243](https://issues.apache.org/jira/browse/THRIFT-4243) - Go TSimpleServer race on wait in Stop() method - [THRIFT-4245](https://issues.apache.org/jira/browse/THRIFT-4245) - Golang TFramedTransport's writeBuffer increases if writes to transport failed - [THRIFT-4246](https://issues.apache.org/jira/browse/THRIFT-4246) - Sequence number mismatch on multiplexed clients - [THRIFT-4247](https://issues.apache.org/jira/browse/THRIFT-4247) - Compile fails with openssl 1.1 - [THRIFT-4248](https://issues.apache.org/jira/browse/THRIFT-4248) - Compile fails) - strncpy, memcmp, memset not declared in src/thrift/transport/TSSLSocket.cpp - [THRIFT-4251](https://issues.apache.org/jira/browse/THRIFT-4251) - Java Epoll Selector Bug - [THRIFT-4257](https://issues.apache.org/jira/browse/THRIFT-4257) - Typescript async callbacks do not provide the correct types - [THRIFT-4258](https://issues.apache.org/jira/browse/THRIFT-4258) - Boost/std thread wrapping faultiness - [THRIFT-4260](https://issues.apache.org/jira/browse/THRIFT-4260) - Go context generation issue. Context is parameter in Interface not in implementation - [THRIFT-4261](https://issues.apache.org/jira/browse/THRIFT-4261) - Go context generation issue: breaking change in generated code regarding thrift.TProcessorFunction interface - [THRIFT-4262](https://issues.apache.org/jira/browse/THRIFT-4262) - Invalid binding to InterlockedCompareExchange64() with 64-bit targets - [THRIFT-4263](https://issues.apache.org/jira/browse/THRIFT-4263) - Fix use after free bug for thrown exceptions - [THRIFT-4266](https://issues.apache.org/jira/browse/THRIFT-4266) - Erlang library throws during skipping fields of composite type (maps, lists, structs, sets) - [THRIFT-4268](https://issues.apache.org/jira/browse/THRIFT-4268) - Erlang library emits debugging output in transport layer - [THRIFT-4273](https://issues.apache.org/jira/browse/THRIFT-4273) - erlang:now/0: Deprecated BIF. - [THRIFT-4274](https://issues.apache.org/jira/browse/THRIFT-4274) - Python feature tests for SSL/TLS failing - [THRIFT-4279](https://issues.apache.org/jira/browse/THRIFT-4279) - Wrong path in include directive in generated Thrift sources - [THRIFT-4283](https://issues.apache.org/jira/browse/THRIFT-4283) - TNamedPipeServer race condition in interrupt - [THRIFT-4284](https://issues.apache.org/jira/browse/THRIFT-4284) - File contains a NBSP: lib/nodejs/lib/thrift/web_server.js - [THRIFT-4290](https://issues.apache.org/jira/browse/THRIFT-4290) - C# nullable option generates invalid code for non-required enum field with default value - [THRIFT-4292](https://issues.apache.org/jira/browse/THRIFT-4292) - TimerManager::remove() is not implemented - [THRIFT-4307](https://issues.apache.org/jira/browse/THRIFT-4307) - Make ssl-open timeout effective in golang client - [THRIFT-4312](https://issues.apache.org/jira/browse/THRIFT-4312) - Erlang client cannot connect to Python server: exception error: econnrefused - [THRIFT-4313](https://issues.apache.org/jira/browse/THRIFT-4313) - Program code of the Erlang tutorial files contain syntax errors - [THRIFT-4316](https://issues.apache.org/jira/browse/THRIFT-4316) - TByteBuffer.java will read too much data if a previous read returns fewer bytes than requested - [THRIFT-4319](https://issues.apache.org/jira/browse/THRIFT-4319) - command line switch for "evhttp" incorrectly resolved to anon pipes - [THRIFT-4323](https://issues.apache.org/jira/browse/THRIFT-4323) - range check errors or NPE in edge cases - [THRIFT-4324](https://issues.apache.org/jira/browse/THRIFT-4324) - field names can conflict with local vars in generated code - [THRIFT-4328](https://issues.apache.org/jira/browse/THRIFT-4328) - Travis CI builds are timing out (job 1) and haxe builds are failing since 9/11 - [THRIFT-4329](https://issues.apache.org/jira/browse/THRIFT-4329) - c_glib Doesn't have a multiplexed processor - [THRIFT-4331](https://issues.apache.org/jira/browse/THRIFT-4331) - C++: TSSLSockets bug in handling huge messages, bug in handling polling - [THRIFT-4332](https://issues.apache.org/jira/browse/THRIFT-4332) - Binary protocol has memory leaks - [THRIFT-4334](https://issues.apache.org/jira/browse/THRIFT-4334) - Perl indentation incorrect when defaulting field attribute to a struct - [THRIFT-4339](https://issues.apache.org/jira/browse/THRIFT-4339) - Thrift Framed Transport in Erlang crashes server when client disconnects - [THRIFT-4340](https://issues.apache.org/jira/browse/THRIFT-4340) - Erlang fix a crash on client close - [THRIFT-4355](https://issues.apache.org/jira/browse/THRIFT-4355) - Javascript indentation incorrect when defaulting field attribute to a struct - [THRIFT-4356](https://issues.apache.org/jira/browse/THRIFT-4356) - thrift_protocol call Transport cause Segmentation fault - [THRIFT-4359](https://issues.apache.org/jira/browse/THRIFT-4359) - Haxe compiler looks like it is producing incorrect code for map or set key that is binary type - [THRIFT-4362](https://issues.apache.org/jira/browse/THRIFT-4362) - Missing size-check can lead to huge memory allocation - [THRIFT-4364](https://issues.apache.org/jira/browse/THRIFT-4364) - Website contributing guide erroneously recommends submitting patches in JIRA - [THRIFT-4365](https://issues.apache.org/jira/browse/THRIFT-4365) - Perl generated code uses indirect object syntax, which occasionally causes compilation errors. - [THRIFT-4367](https://issues.apache.org/jira/browse/THRIFT-4367) - python TProcessor.process is missing "self" - [THRIFT-4370](https://issues.apache.org/jira/browse/THRIFT-4370) - Ubuntu Artful cppcheck and flake8 are more stringent and causing SCA build job failures - [THRIFT-4372](https://issues.apache.org/jira/browse/THRIFT-4372) - Pipe write operations across a network are limited to 65,535 bytes per write. - [THRIFT-4374](https://issues.apache.org/jira/browse/THRIFT-4374) - cannot load thrift_protocol due to undefined symbol: _ZTVN10__cxxabiv120__si_class_type_infoE - [THRIFT-4375](https://issues.apache.org/jira/browse/THRIFT-4375) - TMemory throw bad_alloc due to counter overflow - [THRIFT-4376](https://issues.apache.org/jira/browse/THRIFT-4376) - Coverity high impact issue resolution - [THRIFT-4377](https://issues.apache.org/jira/browse/THRIFT-4377) - haxe. socket handles leak in TSimpleServer - [THRIFT-4381](https://issues.apache.org/jira/browse/THRIFT-4381) - Wrong isset bitfield value after transmission - [THRIFT-4385](https://issues.apache.org/jira/browse/THRIFT-4385) - Go remote client -u flag is broken - [THRIFT-4392](https://issues.apache.org/jira/browse/THRIFT-4392) - compiler/..../plugin.thrift structs mis-ordered blows up ocaml generator - [THRIFT-4395](https://issues.apache.org/jira/browse/THRIFT-4395) - Unable to build in the ubuntu-xenial docker image: clap 2.28 requires Rust 1.20 - [THRIFT-4396](https://issues.apache.org/jira/browse/THRIFT-4396) - inconsistent (or plain wrong) version numbers in master/trunk ### Documentation - [THRIFT-4157](https://issues.apache.org/jira/browse/THRIFT-4157) - outdated readme about Haxe installation on Linux ### Improvement - [THRIFT-105](https://issues.apache.org/jira/browse/THRIFT-105) - make a thrift_spec for a structures with negative tags - [THRIFT-281](https://issues.apache.org/jira/browse/THRIFT-281) - Cocoa library code needs comments, badly - [THRIFT-775](https://issues.apache.org/jira/browse/THRIFT-775) - performance improvements for Perl - [THRIFT-2221](https://issues.apache.org/jira/browse/THRIFT-2221) - Generate c++ code with std::shared_ptr instead of boost::shared_ptr. - [THRIFT-2364](https://issues.apache.org/jira/browse/THRIFT-2364) - OCaml: Use Oasis exclusively for build process - [THRIFT-2504](https://issues.apache.org/jira/browse/THRIFT-2504) - TMultiplexedProcessor should allow registering default processor called if no service name is present - [THRIFT-3207](https://issues.apache.org/jira/browse/THRIFT-3207) - Enable build with OpenSSL 1.1.0 series - [THRIFT-3272](https://issues.apache.org/jira/browse/THRIFT-3272) - Perl SSL Authentication Support - [THRIFT-3357](https://issues.apache.org/jira/browse/THRIFT-3357) - Generate EnumSet/EnumMap where elements/keys are enums - [THRIFT-3369](https://issues.apache.org/jira/browse/THRIFT-3369) - Implement SSL/TLS support on C with c_glib - [THRIFT-3467](https://issues.apache.org/jira/browse/THRIFT-3467) - Go Maps for Thrift Sets Should Have Values of Type struct{} - [THRIFT-3580](https://issues.apache.org/jira/browse/THRIFT-3580) - THeader for Haskell - [THRIFT-3627](https://issues.apache.org/jira/browse/THRIFT-3627) - Missing basic code style consistency of JavaScript. - [THRIFT-3706](https://issues.apache.org/jira/browse/THRIFT-3706) - There's no support for Multiplexed protocol on c_glib library - [THRIFT-3766](https://issues.apache.org/jira/browse/THRIFT-3766) - Add getUnderlyingTransport() to TZlibTransport - [THRIFT-3776](https://issues.apache.org/jira/browse/THRIFT-3776) - Go code from multiple thrift files with the same namespace - [THRIFT-3823](https://issues.apache.org/jira/browse/THRIFT-3823) - Escape documentation while generating non escaped documetation - [THRIFT-3854](https://issues.apache.org/jira/browse/THRIFT-3854) - allow users to clear read buffers - [THRIFT-3859](https://issues.apache.org/jira/browse/THRIFT-3859) - Unix Domain Socket Support in Objective-C - [THRIFT-3921](https://issues.apache.org/jira/browse/THRIFT-3921) - C++ code should print enums as strings - [THRIFT-3926](https://issues.apache.org/jira/browse/THRIFT-3926) - There should be an error emitted when http status code is not 200 - [THRIFT-4007](https://issues.apache.org/jira/browse/THRIFT-4007) - Micro-optimization of TTransport.py - [THRIFT-4040](https://issues.apache.org/jira/browse/THRIFT-4040) - Add real cause of TNonblockingServerSocket error to exception - [THRIFT-4064](https://issues.apache.org/jira/browse/THRIFT-4064) - Update node library dependencies - [THRIFT-4069](https://issues.apache.org/jira/browse/THRIFT-4069) - All perl packages should have proper namespace, version syntax, and use proper thrift exceptions - [THRIFT-4071](https://issues.apache.org/jira/browse/THRIFT-4071) - Consolidate the Travis CI jobs where possible to put less stress on the Apache Foundation's allocation of CI build slaves - [THRIFT-4072](https://issues.apache.org/jira/browse/THRIFT-4072) - Add the possibility to send custom headers in TCurlClient - [THRIFT-4075](https://issues.apache.org/jira/browse/THRIFT-4075) - Better MinGW support for headers-only boost (without thread library) - [THRIFT-4081](https://issues.apache.org/jira/browse/THRIFT-4081) - Provide a MinGW 64-bit Appveyor CI build for better pull request validation - [THRIFT-4084](https://issues.apache.org/jira/browse/THRIFT-4084) - Improve SSL security in thrift by adding a make cross client that checks to make sure SSLv3 protocol cannot be negotiated - [THRIFT-4095](https://issues.apache.org/jira/browse/THRIFT-4095) - Add multiplexed protocol to Travis CI for make cross - [THRIFT-4099](https://issues.apache.org/jira/browse/THRIFT-4099) - Auto-derive Hash for generated Rust structs - [THRIFT-4110](https://issues.apache.org/jira/browse/THRIFT-4110) - The debian build files do not produce a "-dbg" package for debug symbols of libthrift0 - [THRIFT-4114](https://issues.apache.org/jira/browse/THRIFT-4114) - Space after '///' in doc comments - [THRIFT-4126](https://issues.apache.org/jira/browse/THRIFT-4126) - Validate objects in php extension - [THRIFT-4130](https://issues.apache.org/jira/browse/THRIFT-4130) - Ensure Apache Http connection is released back to pool after use - [THRIFT-4151](https://issues.apache.org/jira/browse/THRIFT-4151) - Thrift Mutex Contention Profiling (pthreads) should be disabled by default - [THRIFT-4176](https://issues.apache.org/jira/browse/THRIFT-4176) - Implement a threaded and threadpool server type for Rust - [THRIFT-4183](https://issues.apache.org/jira/browse/THRIFT-4183) - Named pipe client blocks forever on Open() when there is no server at the other end - [THRIFT-4190](https://issues.apache.org/jira/browse/THRIFT-4190) - improve C# TThreadPoolServer defaults - [THRIFT-4197](https://issues.apache.org/jira/browse/THRIFT-4197) - Implement transparent gzip compression for HTTP transport - [THRIFT-4198](https://issues.apache.org/jira/browse/THRIFT-4198) - Ruby should log Thrift internal errors to global logger - [THRIFT-4203](https://issues.apache.org/jira/browse/THRIFT-4203) - thrift server stop gracefully - [THRIFT-4205](https://issues.apache.org/jira/browse/THRIFT-4205) - c_glib is not linking against glib + gobject - [THRIFT-4209](https://issues.apache.org/jira/browse/THRIFT-4209) - warning CS0414 in T[TLS]ServerSocket.cs - [THRIFT-4210](https://issues.apache.org/jira/browse/THRIFT-4210) - include Thrift.45.csproj into CI runs - [THRIFT-4217](https://issues.apache.org/jira/browse/THRIFT-4217) - HttpClient should support gzip and deflate - [THRIFT-4222](https://issues.apache.org/jira/browse/THRIFT-4222) - Support Unix Domain Sockets in Golang TServerSocket - [THRIFT-4233](https://issues.apache.org/jira/browse/THRIFT-4233) - Make THsHaServer.invoker available (get method only) in inherited classes - [THRIFT-4236](https://issues.apache.org/jira/browse/THRIFT-4236) - Support context in go generated code. - [THRIFT-4238](https://issues.apache.org/jira/browse/THRIFT-4238) - JSON generator: make annotation-aware - [THRIFT-4269](https://issues.apache.org/jira/browse/THRIFT-4269) - Don't append '.' to Erlang namespace if it ends in '_'. - [THRIFT-4270](https://issues.apache.org/jira/browse/THRIFT-4270) - Generate Erlang mapping functions for const maps and lists - [THRIFT-4275](https://issues.apache.org/jira/browse/THRIFT-4275) - Add support for zope.interface only, apart from twisted support. - [THRIFT-4285](https://issues.apache.org/jira/browse/THRIFT-4285) - Pull generated send/recv into library to allow behaviour to be customised - [THRIFT-4287](https://issues.apache.org/jira/browse/THRIFT-4287) - Add c++ compiler "no_skeleton" flag option - [THRIFT-4288](https://issues.apache.org/jira/browse/THRIFT-4288) - Implement logging levels properly for node.js - [THRIFT-4295](https://issues.apache.org/jira/browse/THRIFT-4295) - Refresh the Docker image file suite for Ubuntu, Debian, and CentOS - [THRIFT-4305](https://issues.apache.org/jira/browse/THRIFT-4305) - Emit ddoc for generated items - [THRIFT-4306](https://issues.apache.org/jira/browse/THRIFT-4306) - Thrift imports not replicated to D service output - [THRIFT-4315](https://issues.apache.org/jira/browse/THRIFT-4315) - Add default message for TApplicationException - [THRIFT-4318](https://issues.apache.org/jira/browse/THRIFT-4318) - Delphi performance improvements - [THRIFT-4325](https://issues.apache.org/jira/browse/THRIFT-4325) - Simplify automake cross compilation by relying on one global THRIFT compiler path - [THRIFT-4327](https://issues.apache.org/jira/browse/THRIFT-4327) - Improve TimerManager API to allow removing specific task - [THRIFT-4330](https://issues.apache.org/jira/browse/THRIFT-4330) - Allow unused crates in Rust files - [THRIFT-4333](https://issues.apache.org/jira/browse/THRIFT-4333) - Erlang tutorial examples are using a different port (9999) - [THRIFT-4343](https://issues.apache.org/jira/browse/THRIFT-4343) - Change CI builds to use node.js 8.x LTS once available - [THRIFT-4345](https://issues.apache.org/jira/browse/THRIFT-4345) - Create a docker build environment that uses the minimum supported language levels - [THRIFT-4346](https://issues.apache.org/jira/browse/THRIFT-4346) - Allow Zlib transport factory to wrap other transports - [THRIFT-4348](https://issues.apache.org/jira/browse/THRIFT-4348) - Perl HTTP Client custom HTTP headers - [THRIFT-4350](https://issues.apache.org/jira/browse/THRIFT-4350) - Update netcore build for dotnet 2.0 sdk and make cross validation - [THRIFT-4351](https://issues.apache.org/jira/browse/THRIFT-4351) - Use Travis CI Build Stages to optimize the CI build - [THRIFT-4353](https://issues.apache.org/jira/browse/THRIFT-4353) - cannot read via thrift_protocol at server side - [THRIFT-4378](https://issues.apache.org/jira/browse/THRIFT-4378) - add set stopTimeoutUnit method to TThreadPoolServer ### New Feature - [THRIFT-750](https://issues.apache.org/jira/browse/THRIFT-750) - C++ Compiler Virtual Function Option - [THRIFT-2945](https://issues.apache.org/jira/browse/THRIFT-2945) - Implement support for Rust language - [THRIFT-3857](https://issues.apache.org/jira/browse/THRIFT-3857) - thrift js:node compiler support an object as parameter not an instance of struct - [THRIFT-3933](https://issues.apache.org/jira/browse/THRIFT-3933) - Port official C# .NET library for Thrift to C# .NET Core library - [THRIFT-4039](https://issues.apache.org/jira/browse/THRIFT-4039) - Update of Apache Thrift .Net Core lib - [THRIFT-4113](https://issues.apache.org/jira/browse/THRIFT-4113) - Provide a buffer transport for reading/writing in memory byte stream ### Question - [THRIFT-2956](https://issues.apache.org/jira/browse/THRIFT-2956) - autoconf) - possibly undefined macro) - AC_PROG_BISON - [THRIFT-4223](https://issues.apache.org/jira/browse/THRIFT-4223) - Add support to the isServing() method for the C++ library ### Task - [THRIFT-3622](https://issues.apache.org/jira/browse/THRIFT-3622) - Fix deprecated uses of std::auto_ptr - [THRIFT-4028](https://issues.apache.org/jira/browse/THRIFT-4028) - Please remove System.out.format from the source code - [THRIFT-4186](https://issues.apache.org/jira/browse/THRIFT-4186) - Build and test rust client in Travis ### Test - [THRIFT-4264](https://issues.apache.org/jira/browse/THRIFT-4264) - PHP) - Support both shared & static linking of sockets library ### Wish - [THRIFT-4344](https://issues.apache.org/jira/browse/THRIFT-4344) - Define and maintain the minimum language level for all languages in one place ## 0.10.0 ### Bug - [THRIFT-1840](https://issues.apache.org/jira/browse/THRIFT-1840) - Thrift Generated Code Causes Global Variable Leaks - [THRIFT-1828](https://issues.apache.org/jira/browse/THRIFT-1828) - moc_TQTcpServer.cpp was removed from source tree but is in thrift-0.9.0.tar.gz - [THRIFT-1790](https://issues.apache.org/jira/browse/THRIFT-1790) - cocoa: Duplicate interface definition error - [THRIFT-1776](https://issues.apache.org/jira/browse/THRIFT-1776) - TPipeServer should implement "listen", so that TServerEventHandler preServe will work right - [THRIFT-1351](https://issues.apache.org/jira/browse/THRIFT-1351) - Compiler does not care about binary strings - [THRIFT-1229](https://issues.apache.org/jira/browse/THRIFT-1229) - Python fastbinary.c can not handle unicode as generated python code - [THRIFT-749](https://issues.apache.org/jira/browse/THRIFT-749) - C++ TBufferedTransports do not flush their buffers on delete - [THRIFT-747](https://issues.apache.org/jira/browse/THRIFT-747) - C++ TSocket->close calls shutdown breaking forked parent process - [THRIFT-732](https://issues.apache.org/jira/browse/THRIFT-732) - server exits abnormally when client calls send_xxx function without calling recv_xxx function - [THRIFT-3942](https://issues.apache.org/jira/browse/THRIFT-3942) - TSSLSocket does not honor send and receive timeouts - [THRIFT-3941](https://issues.apache.org/jira/browse/THRIFT-3941) - WinXP version of thrift_poll() relies on undefined behavior by passing a destructed variable to select() - [THRIFT-3940](https://issues.apache.org/jira/browse/THRIFT-3940) - Visual Studio project file for compiler is broken - [THRIFT-3943](https://issues.apache.org/jira/browse/THRIFT-3943) - Coverity Scan identified some high severity defects - [THRIFT-3929](https://issues.apache.org/jira/browse/THRIFT-3929) - PHP "nsglobal" Option Results in Syntax Error in Generated Code (Trailing Backslash) - [THRIFT-3936](https://issues.apache.org/jira/browse/THRIFT-3936) - Cannot compile 0.10.0 development tip with VS2013 and earlier (snprintf, uint32_t) - [THRIFT-3935](https://issues.apache.org/jira/browse/THRIFT-3935) - Incorrect skipping of map and set - [THRIFT-3920](https://issues.apache.org/jira/browse/THRIFT-3920) - Ruby: Ensuring that HTTP failures will clear the http transport outbuf var - [THRIFT-3919](https://issues.apache.org/jira/browse/THRIFT-3919) - C# TTLSServerSocket does not use clientTimeout - [THRIFT-3917](https://issues.apache.org/jira/browse/THRIFT-3917) - Check backports.ssl_match_hostname module version - [THRIFT-3909](https://issues.apache.org/jira/browse/THRIFT-3909) - Fix c_glib static lib CMake build - [THRIFT-3904](https://issues.apache.org/jira/browse/THRIFT-3904) - Typo in node tutorial leads to wrong transport being used - [THRIFT-3848](https://issues.apache.org/jira/browse/THRIFT-3848) - As an implementer of a perl socket server, I do not want to have to remember to ignore SIGCHLD for it to work properly - [THRIFT-3844](https://issues.apache.org/jira/browse/THRIFT-3844) - thrift_protocol cannot compile in 7.0.7 - [THRIFT-3843](https://issues.apache.org/jira/browse/THRIFT-3843) - integer issues with Haxe PHP targets cause ZigZag encoding to fail - [THRIFT-3842](https://issues.apache.org/jira/browse/THRIFT-3842) - Dart generates incorrect code for a const struct - [THRIFT-3841](https://issues.apache.org/jira/browse/THRIFT-3841) - dart compact protocol incorrectly serializes/deserialized doubles - [THRIFT-3708](https://issues.apache.org/jira/browse/THRIFT-3708) - NameError: global name 'TProtocol' is not defined - [THRIFT-3704](https://issues.apache.org/jira/browse/THRIFT-3704) - "TConnectedClient died: Could not refill buffer" message shown when using HTTP Server - [THRIFT-3678](https://issues.apache.org/jira/browse/THRIFT-3678) - Fix javadoc errors on JDK 8 - [THRIFT-3014](https://issues.apache.org/jira/browse/THRIFT-3014) - AppVeyor support - [THRIFT-2994](https://issues.apache.org/jira/browse/THRIFT-2994) - Node.js TJSONProtocol cannot be used for object serialization. - [THRIFT-2974](https://issues.apache.org/jira/browse/THRIFT-2974) - writeToParcel throws NPE for optional enum fields - [THRIFT-2948](https://issues.apache.org/jira/browse/THRIFT-2948) - Python TJSONProtocol doesn't handle structs with binary fields containing invalid unicode. - [THRIFT-2845](https://issues.apache.org/jira/browse/THRIFT-2845) - ChildService.Plo: No such file or directory - [THRIFT-3276](https://issues.apache.org/jira/browse/THRIFT-3276) - Binary data does not decode correctly using the TJSONProtocol when the base64 encoded data is padded. - [THRIFT-3253](https://issues.apache.org/jira/browse/THRIFT-3253) - Using latest version of D gives deprecation notices - [THRIFT-2883](https://issues.apache.org/jira/browse/THRIFT-2883) - TTwisted.py, during ConnectionLost processing: exceptions.RuntimeError: dictionary changed size during iteration - [THRIFT-2019](https://issues.apache.org/jira/browse/THRIFT-2019) - Writing on a disconnected socket on Mac causes SIG PIPE - [THRIFT-2020](https://issues.apache.org/jira/browse/THRIFT-2020) - Thrift library has some empty files that haven't really been deleted - [THRIFT-2049](https://issues.apache.org/jira/browse/THRIFT-2049) - Go compiler doesn't build on native Windows - [THRIFT-2024](https://issues.apache.org/jira/browse/THRIFT-2024) - TServer.cpp warns on 64-bit platforms about truncating an rlim_t into an int - [THRIFT-2023](https://issues.apache.org/jira/browse/THRIFT-2023) - gettimeofday implementation on Windows errors when no time zone is passed in. - [THRIFT-2022](https://issues.apache.org/jira/browse/THRIFT-2022) - CoB and dense code generation still uses TR1 bind, even though that doesn't work with clang - [THRIFT-2027](https://issues.apache.org/jira/browse/THRIFT-2027) - Minor 64-bit and NOMINMAX issues in C++ library - [THRIFT-2156](https://issues.apache.org/jira/browse/THRIFT-2156) - TServerSocket::listen() is throwing exceptions with misleading information - [THRIFT-2154](https://issues.apache.org/jira/browse/THRIFT-2154) - Missing #deepCopy should return T - [THRIFT-3157](https://issues.apache.org/jira/browse/THRIFT-3157) - TBase signature should be TBase, F extends TFieldIdEnum> - [THRIFT-3156](https://issues.apache.org/jira/browse/THRIFT-3156) - Node TLS: server executes processing logic two full times - [THRIFT-3154](https://issues.apache.org/jira/browse/THRIFT-3154) - tutorial/py.tornado throw EOF exception - [THRIFT-3063](https://issues.apache.org/jira/browse/THRIFT-3063) - C++ build -Wunused-parameter warnings on processor_test, TransportTest - [THRIFT-3056](https://issues.apache.org/jira/browse/THRIFT-3056) - Add string/collection length limits for Python protocol readers - [THRIFT-3237](https://issues.apache.org/jira/browse/THRIFT-3237) - Fix TNamedPipeServer::createNamedPipe memory leak - [THRIFT-3233](https://issues.apache.org/jira/browse/THRIFT-3233) - Fix C++ ThreadManager::Impl::removeWorker worker join - [THRIFT-3232](https://issues.apache.org/jira/browse/THRIFT-3232) - Cannot deserialize json messages created with fieldNamesAsString - [THRIFT-3206](https://issues.apache.org/jira/browse/THRIFT-3206) - Fix Visual Studio build failure due 'pthread_self': identifier not found - [THRIFT-3200](https://issues.apache.org/jira/browse/THRIFT-3200) - JS and nodejs do not encode JSON protocol binary fields as base64 - [THRIFT-3199](https://issues.apache.org/jira/browse/THRIFT-3199) - Exception field has basic metadata - [THRIFT-3182](https://issues.apache.org/jira/browse/THRIFT-3182) - TFramedTransport is in an invalid state after frame size exception - [THRIFT-2536](https://issues.apache.org/jira/browse/THRIFT-2536) - new TSocket, uninitialised value reported by valgrind - [THRIFT-2527](https://issues.apache.org/jira/browse/THRIFT-2527) - Apache Thrift IDL Compiler code generated for Node.js should be jshint clean - [THRIFT-2519](https://issues.apache.org/jira/browse/THRIFT-2519) - "processor" class is not being generated - [THRIFT-2431](https://issues.apache.org/jira/browse/THRIFT-2431) - TFileTransportTest fails with "check delta < XXX failed" - [THRIFT-2708](https://issues.apache.org/jira/browse/THRIFT-2708) - Erlang library does not support "oneway" message type - [THRIFT-3377](https://issues.apache.org/jira/browse/THRIFT-3377) - Deep copy is actually shallow when using typedef members - [THRIFT-3376](https://issues.apache.org/jira/browse/THRIFT-3376) - C# and Python JSON protocol double values lose precision - [THRIFT-3373](https://issues.apache.org/jira/browse/THRIFT-3373) - Various fixes for cross test servers and clients - [THRIFT-3370](https://issues.apache.org/jira/browse/THRIFT-3370) - errno extern variable redefined. Not compiling for Android - [THRIFT-3379](https://issues.apache.org/jira/browse/THRIFT-3379) - Potential out of range panic in Go JSON protocols - [THRIFT-3371](https://issues.apache.org/jira/browse/THRIFT-3371) - Abstract namespace Unix domain sockets broken in C++ - [THRIFT-3380](https://issues.apache.org/jira/browse/THRIFT-3380) - nodejs: 0.9.2 -> 0.9.3 upgrade breaks Protocol and Transport requires - [THRIFT-3367](https://issues.apache.org/jira/browse/THRIFT-3367) - Fix bad links to coding_standards.md #634 - [THRIFT-3401](https://issues.apache.org/jira/browse/THRIFT-3401) - Nested collections emit Objective-C code that cannot compile - [THRIFT-3403](https://issues.apache.org/jira/browse/THRIFT-3403) - JSON String reader doesn't recognize UTF-16 surrogate pairs - [THRIFT-3362](https://issues.apache.org/jira/browse/THRIFT-3362) - make check fails for C++ at the SecurityTest - [THRIFT-3395](https://issues.apache.org/jira/browse/THRIFT-3395) - Cocoa compiler produces corrupt code when boxing enums inside map. - [THRIFT-3394](https://issues.apache.org/jira/browse/THRIFT-3394) - compiler generates uncompilable code - [THRIFT-3388](https://issues.apache.org/jira/browse/THRIFT-3388) - hash doesn't work on set/list - [THRIFT-3391](https://issues.apache.org/jira/browse/THRIFT-3391) - Wrong bool formatting in test server - [THRIFT-3390](https://issues.apache.org/jira/browse/THRIFT-3390) - TTornado server doesn't handle closed connections properly - [THRIFT-3382](https://issues.apache.org/jira/browse/THRIFT-3382) - TBase class for C++ Library - [THRIFT-3392](https://issues.apache.org/jira/browse/THRIFT-3392) - Java TZlibTransport does not close its wrapper streams upon close() - [THRIFT-3383](https://issues.apache.org/jira/browse/THRIFT-3383) - i64 related warnings - [THRIFT-3386](https://issues.apache.org/jira/browse/THRIFT-3386) - misc. warnings with make check - [THRIFT-3385](https://issues.apache.org/jira/browse/THRIFT-3385) - warning: format ‘%lu’ expects ‘long unsigned int’, but has type ‘std::basic_string::size_type {aka unsigned int} - [THRIFT-3355](https://issues.apache.org/jira/browse/THRIFT-3355) - npm WARN package.json thrift@1.0.0-dev No license field. - [THRIFT-3360](https://issues.apache.org/jira/browse/THRIFT-3360) - Improve cross test servers and clients further - [THRIFT-3359](https://issues.apache.org/jira/browse/THRIFT-3359) - Binary field incompatibilities - [THRIFT-3354](https://issues.apache.org/jira/browse/THRIFT-3354) - Fix word-extraction substr bug in initialism code - [THRIFT-3350](https://issues.apache.org/jira/browse/THRIFT-3350) - Python JSON protocol does not encode binary as Base64 - [THRIFT-3577](https://issues.apache.org/jira/browse/THRIFT-3577) - assertion failed at line 512 of testcontainertest.c - [THRIFT-3576](https://issues.apache.org/jira/browse/THRIFT-3576) - Boost test --log_format arg does not accept lowercase - [THRIFT-3575](https://issues.apache.org/jira/browse/THRIFT-3575) - Go compiler tries to use unexported library methods when using read_write_private - [THRIFT-3574](https://issues.apache.org/jira/browse/THRIFT-3574) - Cocoa generator makes uncompilable imports - [THRIFT-3570](https://issues.apache.org/jira/browse/THRIFT-3570) - Remove duplicate instances that are added by upstream - [THRIFT-3571](https://issues.apache.org/jira/browse/THRIFT-3571) - Make feature test result browsable - [THRIFT-3569](https://issues.apache.org/jira/browse/THRIFT-3569) - c_glib protocols do not check number of bytes read by transport - [THRIFT-3568](https://issues.apache.org/jira/browse/THRIFT-3568) - THeader server crashes on readSlow - [THRIFT-3567](https://issues.apache.org/jira/browse/THRIFT-3567) - GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed - [THRIFT-3566](https://issues.apache.org/jira/browse/THRIFT-3566) - C++/Qt: TQTcpServerTest::test_communicate() is never executed - [THRIFT-3564](https://issues.apache.org/jira/browse/THRIFT-3564) - C++/Qt: potential core dump in TQTcpServer in case an exception occurs in TAsyncProcessor::process() - [THRIFT-3558](https://issues.apache.org/jira/browse/THRIFT-3558) - typos in c_glib tests - [THRIFT-3559](https://issues.apache.org/jira/browse/THRIFT-3559) - Fix awkward extra semi-colons with Cocoa container literals - [THRIFT-3555](https://issues.apache.org/jira/browse/THRIFT-3555) - 'configure' script does not honor --with-openssl= for libcrypto for BN_init - [THRIFT-3554](https://issues.apache.org/jira/browse/THRIFT-3554) - Constant decls may lead to "Error: internal error: prepare_member_name_mapping() already active for different struct" - [THRIFT-3552](https://issues.apache.org/jira/browse/THRIFT-3552) - glib_c Memory Leak - [THRIFT-3551](https://issues.apache.org/jira/browse/THRIFT-3551) - Thrift perl library missing package declaration - [THRIFT-3549](https://issues.apache.org/jira/browse/THRIFT-3549) - Exceptions are not properly stringified in Perl library - [THRIFT-3546](https://issues.apache.org/jira/browse/THRIFT-3546) - NodeJS code should not be namespaced (and is currently not strict-mode compliant) - [THRIFT-3545](https://issues.apache.org/jira/browse/THRIFT-3545) - Container type literals do not compile - [THRIFT-3538](https://issues.apache.org/jira/browse/THRIFT-3538) - Remove UnboundMethodType in TProtocolDecorator - [THRIFT-3536](https://issues.apache.org/jira/browse/THRIFT-3536) - Error 'char' does not contain a definition for 'IsLowSurrogate' for WP7 target - [THRIFT-3534](https://issues.apache.org/jira/browse/THRIFT-3534) - Link error when building with Qt5 - [THRIFT-3533](https://issues.apache.org/jira/browse/THRIFT-3533) - Can not send nil pointer as service method argument - [THRIFT-3507](https://issues.apache.org/jira/browse/THRIFT-3507) - THttpClient does not use proxy from http_proxy, https_proxy environment variables - [THRIFT-3502](https://issues.apache.org/jira/browse/THRIFT-3502) - C++ TServerSocket passes small buffer to getsockname - [THRIFT-3501](https://issues.apache.org/jira/browse/THRIFT-3501) - Forward slash in comment causes compiler error - [THRIFT-3498](https://issues.apache.org/jira/browse/THRIFT-3498) - C++ library assumes optional function pthread_attr_setschedpolicy is available - [THRIFT-3497](https://issues.apache.org/jira/browse/THRIFT-3497) - Build fails with "invalid use of incomplete type" - [THRIFT-3496](https://issues.apache.org/jira/browse/THRIFT-3496) - C++: Cob style client fails when sending a consecutive request - [THRIFT-3493](https://issues.apache.org/jira/browse/THRIFT-3493) - libthrift does not compile on windows using visual studio - [THRIFT-3488](https://issues.apache.org/jira/browse/THRIFT-3488) - warning: unused variable 'program' - [THRIFT-3489](https://issues.apache.org/jira/browse/THRIFT-3489) - warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings] - [THRIFT-3487](https://issues.apache.org/jira/browse/THRIFT-3487) - Full support for newer Delphi versions - [THRIFT-3528](https://issues.apache.org/jira/browse/THRIFT-3528) - Fix warnings in thrift.ll - [THRIFT-3527](https://issues.apache.org/jira/browse/THRIFT-3527) - -gen py:dynamic,utf8strings ignores utf8strings option - [THRIFT-3526](https://issues.apache.org/jira/browse/THRIFT-3526) - Code generated by py:utf8strings does not work for Python3 - [THRIFT-3524](https://issues.apache.org/jira/browse/THRIFT-3524) - dcc32 warning "W1000 Symbol 'IsLowSurrogate' is deprecated: 'Use TCharHelper'" in Thrift.Protocol.JSON.pas - [THRIFT-3525](https://issues.apache.org/jira/browse/THRIFT-3525) - py:dynamic fails to handle binary list/set/map element - [THRIFT-3521](https://issues.apache.org/jira/browse/THRIFT-3521) - TSimpleJSONProtocolTest is not deterministic (fails when run on JDK 8) - [THRIFT-3520](https://issues.apache.org/jira/browse/THRIFT-3520) - Dart TSocket onError stream should be typed as Object - [THRIFT-3519](https://issues.apache.org/jira/browse/THRIFT-3519) - fastbinary does not work with -gen py:utf8strings - [THRIFT-3518](https://issues.apache.org/jira/browse/THRIFT-3518) - TConcurrentClientSyncInfo files were missing for Visual Studio - [THRIFT-3512](https://issues.apache.org/jira/browse/THRIFT-3512) - c_glib: Build fails due to missing features.h - [THRIFT-3483](https://issues.apache.org/jira/browse/THRIFT-3483) - Incorrect empty binary handling introduced by THRIFT-3359 - [THRIFT-3479](https://issues.apache.org/jira/browse/THRIFT-3479) - Oneway calls should not return exceptions to clients - [THRIFT-3478](https://issues.apache.org/jira/browse/THRIFT-3478) - Restore dropped method to THsHaServer.java - [THRIFT-3477](https://issues.apache.org/jira/browse/THRIFT-3477) - Parser fails on enum item that starts with 'E' letter and continues with number - [THRIFT-3476](https://issues.apache.org/jira/browse/THRIFT-3476) - Missing include in ./src/thrift/protocol/TJSONProtocol.cpp - [THRIFT-3474](https://issues.apache.org/jira/browse/THRIFT-3474) - Docker: thrift-compiler - [THRIFT-3473](https://issues.apache.org/jira/browse/THRIFT-3473) - When "optional' is used with a struct member, C++ server seems to not return it correctly - [THRIFT-3468](https://issues.apache.org/jira/browse/THRIFT-3468) - Dart TSocketTransport onError handler is too restrictive - [THRIFT-3451](https://issues.apache.org/jira/browse/THRIFT-3451) - thrift_protocol PHP extension missing config.m4 file - [THRIFT-3456](https://issues.apache.org/jira/browse/THRIFT-3456) - rounding issue in static assert - [THRIFT-3455](https://issues.apache.org/jira/browse/THRIFT-3455) - struct write method's return value is incorrect - [THRIFT-3454](https://issues.apache.org/jira/browse/THRIFT-3454) - Python Tornado tutorial is broken - [THRIFT-3463](https://issues.apache.org/jira/browse/THRIFT-3463) - Java can't be disabled in CMake build - [THRIFT-3450](https://issues.apache.org/jira/browse/THRIFT-3450) - NPE when using SSL - [THRIFT-3449](https://issues.apache.org/jira/browse/THRIFT-3449) - TBaseAsyncProcessor fb.responseReady() never called for oneway functions - [THRIFT-3471](https://issues.apache.org/jira/browse/THRIFT-3471) - Dart generator does not handle uppercase argument names - [THRIFT-3470](https://issues.apache.org/jira/browse/THRIFT-3470) - Sporadic timeouts with pipes - [THRIFT-3465](https://issues.apache.org/jira/browse/THRIFT-3465) - Go Code With Complex Const Initializer Compilation Depends On Struct Order - [THRIFT-3464](https://issues.apache.org/jira/browse/THRIFT-3464) - Fix several defects in c_glib code generator - [THRIFT-3462](https://issues.apache.org/jira/browse/THRIFT-3462) - Cocoa generates Incorrect #import header names - [THRIFT-3453](https://issues.apache.org/jira/browse/THRIFT-3453) - remove rat_exclude - [THRIFT-3418](https://issues.apache.org/jira/browse/THRIFT-3418) - Use of ciphers in ssl.wrap_socket() breaks python 2.6 compatibility - [THRIFT-3417](https://issues.apache.org/jira/browse/THRIFT-3417) - "namespace xsd" is not really working - [THRIFT-3413](https://issues.apache.org/jira/browse/THRIFT-3413) - Thrift code generation bug in Go when extending service - [THRIFT-3420](https://issues.apache.org/jira/browse/THRIFT-3420) - C++: TSSLSockets are not interruptable - [THRIFT-3415](https://issues.apache.org/jira/browse/THRIFT-3415) - include unistd.h conditionally - [THRIFT-3414](https://issues.apache.org/jira/browse/THRIFT-3414) - #include in THeaderTransport.h breaks windows build - [THRIFT-3411](https://issues.apache.org/jira/browse/THRIFT-3411) - Go generates remotes with wrong package qualifiers when including - [THRIFT-3430](https://issues.apache.org/jira/browse/THRIFT-3430) - Go THttpClient does not read HTTP response body to completion when closing - [THRIFT-3423](https://issues.apache.org/jira/browse/THRIFT-3423) - First call to thrift_transport:read_exact fails to dispatch correct function - [THRIFT-3422](https://issues.apache.org/jira/browse/THRIFT-3422) - Go TServerSocket doesn't close on Interrupt - [THRIFT-3421](https://issues.apache.org/jira/browse/THRIFT-3421) - rebar as dependency instead of bundling (was: rebar fails if PWD contains Unicode) - [THRIFT-3428](https://issues.apache.org/jira/browse/THRIFT-3428) - Go test fails when running make check - [THRIFT-3445](https://issues.apache.org/jira/browse/THRIFT-3445) - Throwable messages are hidden from JVM stack trace output - [THRIFT-3443](https://issues.apache.org/jira/browse/THRIFT-3443) - Thrift include can generate uncompilable code - [THRIFT-3444](https://issues.apache.org/jira/browse/THRIFT-3444) - Large 64 bit Integer does not preserve value through Node.js JSONProtocol - [THRIFT-3436](https://issues.apache.org/jira/browse/THRIFT-3436) - misc. cross test issues with UTF-8 path names - [THRIFT-3435](https://issues.apache.org/jira/browse/THRIFT-3435) - Put generated Java code for fullcamel tests in a separate package/namespace - [THRIFT-3433](https://issues.apache.org/jira/browse/THRIFT-3433) - Doubles aren't interpreted correctly - [THRIFT-3437](https://issues.apache.org/jira/browse/THRIFT-3437) - Mingw-w64 build fail - [THRIFT-3434](https://issues.apache.org/jira/browse/THRIFT-3434) - Dart generator produces empty name in pubspec.yaml for includes without namespaces - [THRIFT-3408](https://issues.apache.org/jira/browse/THRIFT-3408) - JSON generator emits incorrect types - [THRIFT-3406](https://issues.apache.org/jira/browse/THRIFT-3406) - Cocoa client should not schedule streams on main runloop - [THRIFT-3404](https://issues.apache.org/jira/browse/THRIFT-3404) - JSON String reader doesn't recognize UTF-16 surrogate pair - [THRIFT-3636](https://issues.apache.org/jira/browse/THRIFT-3636) - Double precision is not fully preserved in C++ TJSONProtocol - [THRIFT-3632](https://issues.apache.org/jira/browse/THRIFT-3632) - c_glib testserialization fails with glib assertion - [THRIFT-3619](https://issues.apache.org/jira/browse/THRIFT-3619) - Using Thrift 0.9.3 with googletest on Linux gcc 4.9 / C++11 - [THRIFT-3617](https://issues.apache.org/jira/browse/THRIFT-3617) - CMake does not build gv/xml generators - [THRIFT-3615](https://issues.apache.org/jira/browse/THRIFT-3615) - Fix Python SSL client resource leak on connection failure - [THRIFT-3616](https://issues.apache.org/jira/browse/THRIFT-3616) - lib/py/test/test_sslsocket.py is flaky - [THRIFT-3643](https://issues.apache.org/jira/browse/THRIFT-3643) - Perl SSL server crushes if a client disconnect without handshake - [THRIFT-3639](https://issues.apache.org/jira/browse/THRIFT-3639) - C# Thrift library forces TLS 1.0, thwarting TLS 1.2 usage - [THRIFT-3633](https://issues.apache.org/jira/browse/THRIFT-3633) - Travis "C C++) - GCC" build was using clang - [THRIFT-3634](https://issues.apache.org/jira/browse/THRIFT-3634) - Fix Python TSocket resource leak on connection failure - [THRIFT-3630](https://issues.apache.org/jira/browse/THRIFT-3630) - Debian/Ubuntu install docs need an update - [THRIFT-3629](https://issues.apache.org/jira/browse/THRIFT-3629) - Parser sets exitcode on errors, but generator does not - [THRIFT-3608](https://issues.apache.org/jira/browse/THRIFT-3608) - lib/cpp/test/SecurityTest is flaky in jenkins Thrift-precommit build. - [THRIFT-3601](https://issues.apache.org/jira/browse/THRIFT-3601) - Better conformance to PEP8 for generated code - [THRIFT-3599](https://issues.apache.org/jira/browse/THRIFT-3599) - Validate client IP address against cert's SubjectAltName - [THRIFT-3598](https://issues.apache.org/jira/browse/THRIFT-3598) - TBufferedTransport doesn't instantiate client connection - [THRIFT-3597](https://issues.apache.org/jira/browse/THRIFT-3597) - `make check` hangs in go tests - [THRIFT-3589](https://issues.apache.org/jira/browse/THRIFT-3589) - Dart generator uses wrong name in constructor for uppercase arguments with defaults - [THRIFT-3588](https://issues.apache.org/jira/browse/THRIFT-3588) - Using TypeScript with --noImplicitAny fails - [THRIFT-3584](https://issues.apache.org/jira/browse/THRIFT-3584) - boolean false value cannot be transferred - [THRIFT-3578](https://issues.apache.org/jira/browse/THRIFT-3578) - Make THeaderTransport detect TCompact framed and unframed - [THRIFT-3323](https://issues.apache.org/jira/browse/THRIFT-3323) - Python library does not handle escaped forward slash ("/") in JSON - [THRIFT-3322](https://issues.apache.org/jira/browse/THRIFT-3322) - CMake generated "make check" failes on python_test - [THRIFT-3321](https://issues.apache.org/jira/browse/THRIFT-3321) - Thrift can't be added as a subdirectory of another CMake-based project - [THRIFT-3314](https://issues.apache.org/jira/browse/THRIFT-3314) - Dots in file names of includes causes dots in javascript variable names - [THRIFT-3307](https://issues.apache.org/jira/browse/THRIFT-3307) - Segfault in Ruby serializer - [THRIFT-3309](https://issues.apache.org/jira/browse/THRIFT-3309) - Missing TConstant.php in /lib/php/Makefile.am - [THRIFT-3810](https://issues.apache.org/jira/browse/THRIFT-3810) - unresolved external symbol public: virtual void __cdecl apache::thrift::server::TServerFramework::serve(void) - [THRIFT-3736](https://issues.apache.org/jira/browse/THRIFT-3736) - C++ library build fails if OpenSSL does not surrpot SSLv3 - [THRIFT-3878](https://issues.apache.org/jira/browse/THRIFT-3878) - Compile error in TSSLSocket.cpp with new OpenSSL [CRYPTO_num_locks] - [THRIFT-3949](https://issues.apache.org/jira/browse/THRIFT-3949) - missing make dist entry for compiler/cpp/test - [THRIFT-449](https://issues.apache.org/jira/browse/THRIFT-449) - The wire format of the JSON Protocol may not always be valid JSON if it contains non-UTF8 encoded strings - [THRIFT-162](https://issues.apache.org/jira/browse/THRIFT-162) - Thrift structures are unhashable, preventing them from being used as set elements - [THRIFT-3961](https://issues.apache.org/jira/browse/THRIFT-3961) - TConnectedClient does not terminate the connection to the client if an exception while processing the received message occures. - [THRIFT-3881](https://issues.apache.org/jira/browse/THRIFT-3881) - Travis CI builds are failing due to docker failures (three retries, and gives up) - [THRIFT-3937](https://issues.apache.org/jira/browse/THRIFT-3937) - Cannot compile 0.10.0 development tip with gcc-4.6.x - [THRIFT-3964](https://issues.apache.org/jira/browse/THRIFT-3964) - Unsupported mechanism type ????? due to dependency on default OS-dependent charset - [THRIFT-3038](https://issues.apache.org/jira/browse/THRIFT-3038) - Use of volatile in cpp library - [THRIFT-3301](https://issues.apache.org/jira/browse/THRIFT-3301) - Java generated code uses imports that can lead to class name collisions with IDL defined types - [THRIFT-3348](https://issues.apache.org/jira/browse/THRIFT-3348) - PHP TCompactProtocol bool&int64 readvalue bug - [THRIFT-3955](https://issues.apache.org/jira/browse/THRIFT-3955) - TThreadedServer Memory Leak - [THRIFT-3829](https://issues.apache.org/jira/browse/THRIFT-3829) - Thrift does not install Python Libraries if Twisted is not installed - [THRIFT-3932](https://issues.apache.org/jira/browse/THRIFT-3932) - C++ ThreadManager has a rare termination race - [THRIFT-3828](https://issues.apache.org/jira/browse/THRIFT-3828) - cmake fails when Boost_INCLUDE_DIRS (and other variables passed to include_directories()) is empty - [THRIFT-3958](https://issues.apache.org/jira/browse/THRIFT-3958) - CMake WITH_MT option for windows static runtime linking does not support the cmake build type RelWithDebInfo - [THRIFT-3957](https://issues.apache.org/jira/browse/THRIFT-3957) - TConnectedClient does not disconnect from clients when their timeout is reached. - [THRIFT-3953](https://issues.apache.org/jira/browse/THRIFT-3953) - TSSLSocket::close should handle exceptions from waitForEvent because it is called by the destructor. - [THRIFT-3977](https://issues.apache.org/jira/browse/THRIFT-3977) - PHP extension creates undefined values when deserializing sets - [THRIFT-3947](https://issues.apache.org/jira/browse/THRIFT-3947) - sockaddr type isn't always large enough for the return of getsockname - [THRIFT-2755](https://issues.apache.org/jira/browse/THRIFT-2755) - ThreadSanitizer reports data race in ThreadManager::Impl::addWorker - [THRIFT-3948](https://issues.apache.org/jira/browse/THRIFT-3948) - errno is not the correct method of getting the error in windows - [THRIFT-4008](https://issues.apache.org/jira/browse/THRIFT-4008) - broken ci due to upstream dependency versioning break - [THRIFT-3999](https://issues.apache.org/jira/browse/THRIFT-3999) - Fix Debian & Ubuntu package dependencies - [THRIFT-3886](https://issues.apache.org/jira/browse/THRIFT-3886) - PHP cross test client returns 0 even when failing - [THRIFT-3997](https://issues.apache.org/jira/browse/THRIFT-3997) - building thrift libs does not support new openssl ### Documentation - [THRIFT-3867](https://issues.apache.org/jira/browse/THRIFT-3867) - Specify BinaryProtocol and CompactProtocol ### Epic - [THRIFT-3049](https://issues.apache.org/jira/browse/THRIFT-3049) - As an iOS developer, I want a generator and library that produces Swift code - [THRIFT-2336](https://issues.apache.org/jira/browse/THRIFT-2336) - UTF-8 sent by PHP as JSON is not understood by TJsonProtocol ### Improvement - [THRIFT-1867](https://issues.apache.org/jira/browse/THRIFT-1867) - Python client/server should support client-side certificates. - [THRIFT-1313](https://issues.apache.org/jira/browse/THRIFT-1313) - c_glib compact support - [THRIFT-1385](https://issues.apache.org/jira/browse/THRIFT-1385) - make install doesn't install java library in the setted folder - [THRIFT-1437](https://issues.apache.org/jira/browse/THRIFT-1437) - Update RPM spec - [THRIFT-847](https://issues.apache.org/jira/browse/THRIFT-847) - Test Framework harmonization across all languages - [THRIFT-819](https://issues.apache.org/jira/browse/THRIFT-819) - add Enumeration for protocol, transport and server types - [THRIFT-3927](https://issues.apache.org/jira/browse/THRIFT-3927) - Emit an error instead of throw an error in the async callback - [THRIFT-3931](https://issues.apache.org/jira/browse/THRIFT-3931) - TSimpleServer: If process request encounter UNKNOWN_METHOD, don't close transport. - [THRIFT-3934](https://issues.apache.org/jira/browse/THRIFT-3934) - Automatically resolve OpenSSL binary version on Windows CI - [THRIFT-3918](https://issues.apache.org/jira/browse/THRIFT-3918) - Run subset of make cross - [THRIFT-3908](https://issues.apache.org/jira/browse/THRIFT-3908) - Remove redundant dependencies from Dockerfile - [THRIFT-3907](https://issues.apache.org/jira/browse/THRIFT-3907) - Skip Docker image build on CI when unchanged - [THRIFT-3868](https://issues.apache.org/jira/browse/THRIFT-3868) - Java struct equals should do identity check before field comparison - [THRIFT-3849](https://issues.apache.org/jira/browse/THRIFT-3849) - Port Go serializer and deserializer to dart - [THRIFT-2989](https://issues.apache.org/jira/browse/THRIFT-2989) - Complete CMake build for Apache Thrift - [THRIFT-2980](https://issues.apache.org/jira/browse/THRIFT-2980) - ThriftMemoryBuffer doesn't have a constructor option to take an existing buffer - [THRIFT-2856](https://issues.apache.org/jira/browse/THRIFT-2856) - refactor erlang basic transports and unify interfaces - [THRIFT-2877](https://issues.apache.org/jira/browse/THRIFT-2877) - Optimize generated hashCode - [THRIFT-2869](https://issues.apache.org/jira/browse/THRIFT-2869) - JSON: run schema validation from tests - [THRIFT-3112](https://issues.apache.org/jira/browse/THRIFT-3112) - [Java] AsyncMethodCallback should be typed in generated AsyncIface - [THRIFT-3263](https://issues.apache.org/jira/browse/THRIFT-3263) - PHP jsonSerialize() should cast scalar types - [THRIFT-2905](https://issues.apache.org/jira/browse/THRIFT-2905) - Cocoa compiler should have option to produce "modern" Objective-C - [THRIFT-2821](https://issues.apache.org/jira/browse/THRIFT-2821) - Enable the use of custom HTTP-Header in the Transport - [THRIFT-2093](https://issues.apache.org/jira/browse/THRIFT-2093) - added the ability to set compression level in C++ zlib transport - [THRIFT-2089](https://issues.apache.org/jira/browse/THRIFT-2089) - Compiler ignores duplicate typenames - [THRIFT-2056](https://issues.apache.org/jira/browse/THRIFT-2056) - Moved all #include config.h statements to #include - [THRIFT-2031](https://issues.apache.org/jira/browse/THRIFT-2031) - Make SO_KEEPALIVE configurable for C++ lib - [THRIFT-2021](https://issues.apache.org/jira/browse/THRIFT-2021) - Improve large binary protocol string performance - [THRIFT-2028](https://issues.apache.org/jira/browse/THRIFT-2028) - Cleanup threading headers / libraries - [THRIFT-2014](https://issues.apache.org/jira/browse/THRIFT-2014) - Change C++ lib includes to use style throughout - [THRIFT-2312](https://issues.apache.org/jira/browse/THRIFT-2312) - travis.yml: build everything - [THRIFT-1915](https://issues.apache.org/jira/browse/THRIFT-1915) - Multiplexing Services - [THRIFT-1736](https://issues.apache.org/jira/browse/THRIFT-1736) - Visual Studio top level project files within msvc - [THRIFT-1735](https://issues.apache.org/jira/browse/THRIFT-1735) - integrate tutorial into regular build - [THRIFT-1533](https://issues.apache.org/jira/browse/THRIFT-1533) - Make TTransport should be Closeable - [THRIFT-35](https://issues.apache.org/jira/browse/THRIFT-35) - Move language tests into their appropriate library directory - [THRIFT-1079](https://issues.apache.org/jira/browse/THRIFT-1079) - Support i64 in AS3 - [THRIFT-1108](https://issues.apache.org/jira/browse/THRIFT-1108) - SSL support for the Ruby library - [THRIFT-3856](https://issues.apache.org/jira/browse/THRIFT-3856) - update debian package deependencies - [THRIFT-3833](https://issues.apache.org/jira/browse/THRIFT-3833) - haxe http server implementation (by embeding into php web server) - [THRIFT-3839](https://issues.apache.org/jira/browse/THRIFT-3839) - Performance issue with big message deserialization using php extension - [THRIFT-3820](https://issues.apache.org/jira/browse/THRIFT-3820) - Erlang: Detect OTP >= 18 to use new time correction - [THRIFT-3816](https://issues.apache.org/jira/browse/THRIFT-3816) - Reduce docker build duration on Travis-CI - [THRIFT-3815](https://issues.apache.org/jira/browse/THRIFT-3815) - Put appveyor dependency versions to one place - [THRIFT-3788](https://issues.apache.org/jira/browse/THRIFT-3788) - Compatibility improvements and Win64 support - [THRIFT-3792](https://issues.apache.org/jira/browse/THRIFT-3792) - Timeouts for anonymous pipes should be configurable - [THRIFT-3794](https://issues.apache.org/jira/browse/THRIFT-3794) - Split Delphi application, protocol and transport exception subtypes into separate exceptions - [THRIFT-3774](https://issues.apache.org/jira/browse/THRIFT-3774) - The generated code should have exception_names meta info - [THRIFT-3762](https://issues.apache.org/jira/browse/THRIFT-3762) - Fix build warnings for deprecated Thrift "byte" fields - [THRIFT-3756](https://issues.apache.org/jira/browse/THRIFT-3756) - Improve requiredness documentation - [THRIFT-3761](https://issues.apache.org/jira/browse/THRIFT-3761) - Add debian package for Python3 - [THRIFT-3742](https://issues.apache.org/jira/browse/THRIFT-3742) - haxe php cli support - [THRIFT-3733](https://issues.apache.org/jira/browse/THRIFT-3733) - Socket timeout improvements - [THRIFT-3728](https://issues.apache.org/jira/browse/THRIFT-3728) - http transport for thrift-lua - [THRIFT-3905](https://issues.apache.org/jira/browse/THRIFT-3905) - Dart compiler does not initialize bool, int, and double properties - [THRIFT-3911](https://issues.apache.org/jira/browse/THRIFT-3911) - Loosen Ruby dev dependency version requirements - [THRIFT-3906](https://issues.apache.org/jira/browse/THRIFT-3906) - Run C# tests with make check - [THRIFT-3900](https://issues.apache.org/jira/browse/THRIFT-3900) - Add Python SSL flags - [THRIFT-3897](https://issues.apache.org/jira/browse/THRIFT-3897) - Provide meaningful exception type based on WebExceptionStatus in case of timeout - [THRIFT-3808](https://issues.apache.org/jira/browse/THRIFT-3808) - Missing `DOUBLE` in thrift type enumeration - [THRIFT-3803](https://issues.apache.org/jira/browse/THRIFT-3803) - Remove "file" attribute from XML generator - [THRIFT-3660](https://issues.apache.org/jira/browse/THRIFT-3660) - Add V4 mapped address to test client cert's altname - [THRIFT-3661](https://issues.apache.org/jira/browse/THRIFT-3661) - Use https to download meck in erlang test build - [THRIFT-3659](https://issues.apache.org/jira/browse/THRIFT-3659) - Check configure result of CMake on CI - [THRIFT-3667](https://issues.apache.org/jira/browse/THRIFT-3667) - Add TLS SNI support to clients - [THRIFT-3651](https://issues.apache.org/jira/browse/THRIFT-3651) - Make backports.match_hostname and ipaddress optional - [THRIFT-3666](https://issues.apache.org/jira/browse/THRIFT-3666) - Build D tutorial as part of Autotools build - [THRIFT-3665](https://issues.apache.org/jira/browse/THRIFT-3665) - Add D libevent and OpenSSL to docker images - [THRIFT-3664](https://issues.apache.org/jira/browse/THRIFT-3664) - Remove md5.c - [THRIFT-3662](https://issues.apache.org/jira/browse/THRIFT-3662) - Add Haskell to debian docker image - [THRIFT-3711](https://issues.apache.org/jira/browse/THRIFT-3711) - Add D to cross language test - [THRIFT-3691](https://issues.apache.org/jira/browse/THRIFT-3691) - Run flake8 Python style check on Travis-CI - [THRIFT-3692](https://issues.apache.org/jira/browse/THRIFT-3692) - (Re)enable Appveyor C++ and Python build - [THRIFT-3677](https://issues.apache.org/jira/browse/THRIFT-3677) - Improve CMake Java build - [THRIFT-3679](https://issues.apache.org/jira/browse/THRIFT-3679) - Add stdout log to testBinary in Java test server - [THRIFT-3718](https://issues.apache.org/jira/browse/THRIFT-3718) - Reduce size of docker image for build environment - [THRIFT-3698](https://issues.apache.org/jira/browse/THRIFT-3698) - [Travis-CI] Introduce retry to apt commands - [THRIFT-3127](https://issues.apache.org/jira/browse/THRIFT-3127) - switch -recurse to --recurse and reserve -r - [THRIFT-3087](https://issues.apache.org/jira/browse/THRIFT-3087) - Pass on errors like "connection closed" - [THRIFT-3240](https://issues.apache.org/jira/browse/THRIFT-3240) - Thrift Python client should support subjectAltName and wildcard certs in TSSLSocket - [THRIFT-3213](https://issues.apache.org/jira/browse/THRIFT-3213) - make cross should indicate when it skips a known failing test - [THRIFT-3208](https://issues.apache.org/jira/browse/THRIFT-3208) - Fix Visual Studio solution build failure due to missing source - [THRIFT-3186](https://issues.apache.org/jira/browse/THRIFT-3186) - Add TServerHTTP to Go library - [THRIFT-2342](https://issues.apache.org/jira/browse/THRIFT-2342) - Add __FILE__ and __LINE__ to Thrift C++ excpetions - [THRIFT-3372](https://issues.apache.org/jira/browse/THRIFT-3372) - Add dart generator to Visual Studio project - [THRIFT-3366](https://issues.apache.org/jira/browse/THRIFT-3366) - ThriftTest to implement standard return values - [THRIFT-3402](https://issues.apache.org/jira/browse/THRIFT-3402) - Provide a perl Unix Socket implementation - [THRIFT-3361](https://issues.apache.org/jira/browse/THRIFT-3361) - Improve C# library - [THRIFT-3393](https://issues.apache.org/jira/browse/THRIFT-3393) - Introduce i8 to provide consistent set of Thrift IDL integer types - [THRIFT-3339](https://issues.apache.org/jira/browse/THRIFT-3339) - Support for database/sql - [THRIFT-3565](https://issues.apache.org/jira/browse/THRIFT-3565) - C++: T[Async]Processor::getEventHandler() should be declared as const member functions - [THRIFT-3563](https://issues.apache.org/jira/browse/THRIFT-3563) - C++/Qt: removed usage of macro QT_PREPEND_NAMESPACE as it isn't consequently used for all references to Qt types. - [THRIFT-3562](https://issues.apache.org/jira/browse/THRIFT-3562) - Removed unused TAsyncProcessor::getAsyncServer() - [THRIFT-3561](https://issues.apache.org/jira/browse/THRIFT-3561) - C++/Qt: make use of Q_DISABLE_COPY() to get rid of copy ctor and assignment operator - [THRIFT-3556](https://issues.apache.org/jira/browse/THRIFT-3556) - c_glib file descriptor transport - [THRIFT-3544](https://issues.apache.org/jira/browse/THRIFT-3544) - Make cross test fail when server process died unexpectedly - [THRIFT-3540](https://issues.apache.org/jira/browse/THRIFT-3540) - Make python tutorial more in line with PEP8 - [THRIFT-3535](https://issues.apache.org/jira/browse/THRIFT-3535) - Dart generator argument to produce a file structure usable in parent library - [THRIFT-3505](https://issues.apache.org/jira/browse/THRIFT-3505) - Enhance Python TSSLSocket - [THRIFT-3506](https://issues.apache.org/jira/browse/THRIFT-3506) - Eliminate old style classes from library code - [THRIFT-3503](https://issues.apache.org/jira/browse/THRIFT-3503) - Enable py:utf8string by default - [THRIFT-3499](https://issues.apache.org/jira/browse/THRIFT-3499) - Add package_prefix to python generator - [THRIFT-3495](https://issues.apache.org/jira/browse/THRIFT-3495) - Minor enhancements and fixes for cross test - [THRIFT-3486](https://issues.apache.org/jira/browse/THRIFT-3486) - Java generated `getFieldValue` is incompatible with `setFieldValue` for binary values. - [THRIFT-3484](https://issues.apache.org/jira/browse/THRIFT-3484) - Consolidate temporary buffers in Java's TCompactProtocol - [THRIFT-3516](https://issues.apache.org/jira/browse/THRIFT-3516) - Add feature test for THeader TBinaryProtocol interop - [THRIFT-3515](https://issues.apache.org/jira/browse/THRIFT-3515) - Python 2.6 compatibility and test on CI - [THRIFT-3514](https://issues.apache.org/jira/browse/THRIFT-3514) - PHP 7 compatible version of binary protocol - [THRIFT-3469](https://issues.apache.org/jira/browse/THRIFT-3469) - Docker: Debian support - [THRIFT-3416](https://issues.apache.org/jira/browse/THRIFT-3416) - Retire old "xxx_namespace" declarations from the IDL - [THRIFT-3426](https://issues.apache.org/jira/browse/THRIFT-3426) - Align autogen comment in XSD - [THRIFT-3424](https://issues.apache.org/jira/browse/THRIFT-3424) - Add CMake android build option - [THRIFT-3439](https://issues.apache.org/jira/browse/THRIFT-3439) - Run make cross using Python3 when available - [THRIFT-3440](https://issues.apache.org/jira/browse/THRIFT-3440) - Python make check takes too much time - [THRIFT-3441](https://issues.apache.org/jira/browse/THRIFT-3441) - Stabilize Travis-CI builds - [THRIFT-3431](https://issues.apache.org/jira/browse/THRIFT-3431) - Avoid "schemes" HashMap lookups during struct reads/writes - [THRIFT-3432](https://issues.apache.org/jira/browse/THRIFT-3432) - Add a TByteBuffer transport to the Java library - [THRIFT-3438](https://issues.apache.org/jira/browse/THRIFT-3438) - Enable py:new_style by default - [THRIFT-3405](https://issues.apache.org/jira/browse/THRIFT-3405) - Go THttpClient misuses http.Client objects - [THRIFT-3614](https://issues.apache.org/jira/browse/THRIFT-3614) - Improve logging of test_sslsocket.py - [THRIFT-3647](https://issues.apache.org/jira/browse/THRIFT-3647) - Fix php extension build warnings - [THRIFT-3642](https://issues.apache.org/jira/browse/THRIFT-3642) - Speed up cross test runner - [THRIFT-3637](https://issues.apache.org/jira/browse/THRIFT-3637) - Implement compact protocol for dart - [THRIFT-3613](https://issues.apache.org/jira/browse/THRIFT-3613) - Port Python C extension to Python 3 - [THRIFT-3612](https://issues.apache.org/jira/browse/THRIFT-3612) - Add Python C extension for compact protocol - [THRIFT-3611](https://issues.apache.org/jira/browse/THRIFT-3611) - Add --regex filter to cross test runner - [THRIFT-3631](https://issues.apache.org/jira/browse/THRIFT-3631) - JSON protocol implementation for Lua - [THRIFT-3609](https://issues.apache.org/jira/browse/THRIFT-3609) - Remove or replace TestPortFixture.h - [THRIFT-3605](https://issues.apache.org/jira/browse/THRIFT-3605) - Have the compiler complain about invalid arguments and options - [THRIFT-3596](https://issues.apache.org/jira/browse/THRIFT-3596) - Better conformance to PEP8 - [THRIFT-3585](https://issues.apache.org/jira/browse/THRIFT-3585) - Compact protocol implementation for Lua - [THRIFT-3582](https://issues.apache.org/jira/browse/THRIFT-3582) - Erlang libraries should have service metadata - [THRIFT-3579](https://issues.apache.org/jira/browse/THRIFT-3579) - Introduce retry to make cross - [THRIFT-3306](https://issues.apache.org/jira/browse/THRIFT-3306) - Java: TBinaryProtocol: Use 1 temp buffer instead of allocating 8 - [THRIFT-3910](https://issues.apache.org/jira/browse/THRIFT-3910) - Do not invoke pip as part of build process - [THRIFT-1857](https://issues.apache.org/jira/browse/THRIFT-1857) - Python 3.X Support - [THRIFT-1944](https://issues.apache.org/jira/browse/THRIFT-1944) - Binding to zero port - [THRIFT-3954](https://issues.apache.org/jira/browse/THRIFT-3954) - Enable the usage of structs called "Object" in Java - [THRIFT-3981](https://issues.apache.org/jira/browse/THRIFT-3981) - Enable analyzer strong mode in Dart library - [THRIFT-3998](https://issues.apache.org/jira/browse/THRIFT-3998) - Document ability to add custom tags to thrift structs - [THRIFT-4006](https://issues.apache.org/jira/browse/THRIFT-4006) - Add a removeEventListener method on TSocket ### New Feature - [THRIFT-640](https://issues.apache.org/jira/browse/THRIFT-640) - Support deprecation - [THRIFT-948](https://issues.apache.org/jira/browse/THRIFT-948) - SSL socket support for PHP - [THRIFT-764](https://issues.apache.org/jira/browse/THRIFT-764) - add Support for Vala language - [THRIFT-3046](https://issues.apache.org/jira/browse/THRIFT-3046) - Allow PSR4 class loading for generated classes (PHP) - [THRIFT-2113](https://issues.apache.org/jira/browse/THRIFT-2113) - Erlang SSL Socket Support - [THRIFT-1482](https://issues.apache.org/jira/browse/THRIFT-1482) - Unix domain socket support under PHP - [THRIFT-519](https://issues.apache.org/jira/browse/THRIFT-519) - Support collections of types without having to explicitly define it - [THRIFT-468](https://issues.apache.org/jira/browse/THRIFT-468) - Rack Middleware Application for Rails - [THRIFT-1708](https://issues.apache.org/jira/browse/THRIFT-1708) - Add event handlers for processor events - [THRIFT-3834](https://issues.apache.org/jira/browse/THRIFT-3834) - Erlang namespacing and exception metadata - [THRIFT-2510](https://issues.apache.org/jira/browse/THRIFT-2510) - Implement TNonblockingServer's ability to listen on unix domain sockets - [THRIFT-3397](https://issues.apache.org/jira/browse/THRIFT-3397) - Implement TProcessorFactory in C# to enable per-client processors - [THRIFT-3523](https://issues.apache.org/jira/browse/THRIFT-3523) - XML Generator - [THRIFT-3510](https://issues.apache.org/jira/browse/THRIFT-3510) - Add HttpTaskAsyncHandler implementation - [THRIFT-3318](https://issues.apache.org/jira/browse/THRIFT-3318) - PHP: SimpleJSONProtocol Implementation - [THRIFT-3299](https://issues.apache.org/jira/browse/THRIFT-3299) - Dart language bindings in Thrift - [THRIFT-2835](https://issues.apache.org/jira/browse/THRIFT-2835) - Add possibility to distribute generators separately from thrift core, and load them dynamically - [THRIFT-184](https://issues.apache.org/jira/browse/THRIFT-184) - Add OSGi Manifest headers to the libthrift java library to be able to use Thrift in the OSGi runtime - [THRIFT-141](https://issues.apache.org/jira/browse/THRIFT-141) - If a required field is not present on serialization, throw an exception - [THRIFT-1891](https://issues.apache.org/jira/browse/THRIFT-1891) - Add Windows ALPC transport which is right counterpart of Unix domain sockets ### Question - [THRIFT-1808](https://issues.apache.org/jira/browse/THRIFT-1808) - The Thrift struct should be considered self-contained? - [THRIFT-2895](https://issues.apache.org/jira/browse/THRIFT-2895) - Tutorial cpp - [THRIFT-3860](https://issues.apache.org/jira/browse/THRIFT-3860) - Elephant-bird application Test fails for Thrift - [THRIFT-3811](https://issues.apache.org/jira/browse/THRIFT-3811) - HTTPS Support for C++ applications - [THRIFT-3509](https://issues.apache.org/jira/browse/THRIFT-3509) - "make check" error ### Story - [THRIFT-3452](https://issues.apache.org/jira/browse/THRIFT-3452) - .travis.yml: Migrating from legacy to container-based infrastructure ### Sub-task - [THRIFT-1811](https://issues.apache.org/jira/browse/THRIFT-1811) - ruby tutorial as part of the regular build - [THRIFT-2779](https://issues.apache.org/jira/browse/THRIFT-2779) - PHP TJSONProtocol encode unicode into UCS-4LE which can't be parsed by other language bindings - [THRIFT-2110](https://issues.apache.org/jira/browse/THRIFT-2110) - Erlang: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-3852](https://issues.apache.org/jira/browse/THRIFT-3852) - A Travis-CI job fails with "write error" - [THRIFT-3740](https://issues.apache.org/jira/browse/THRIFT-3740) - Fix haxelib.json classpath - [THRIFT-3653](https://issues.apache.org/jira/browse/THRIFT-3653) - incorrect union serialization - [THRIFT-3652](https://issues.apache.org/jira/browse/THRIFT-3652) - incorrect serialization of optionals - [THRIFT-3655](https://issues.apache.org/jira/browse/THRIFT-3655) - incorrect union serialization - [THRIFT-3654](https://issues.apache.org/jira/browse/THRIFT-3654) - incorrect serialization of optionals - [THRIFT-3656](https://issues.apache.org/jira/browse/THRIFT-3656) - incorrect serialization of optionals - [THRIFT-3699](https://issues.apache.org/jira/browse/THRIFT-3699) - Fix integer limit symbol includes in Python C extension - [THRIFT-3693](https://issues.apache.org/jira/browse/THRIFT-3693) - Fix include issue in C++ TSSLSocketInterruptTest on Windows - [THRIFT-3694](https://issues.apache.org/jira/browse/THRIFT-3694) - [Windows] Disable tests of a few servers that are not supported - [THRIFT-3696](https://issues.apache.org/jira/browse/THRIFT-3696) - Install pip to CentOS Docker images to fix Python builds - [THRIFT-3638](https://issues.apache.org/jira/browse/THRIFT-3638) - Fix haxelib.json - [THRIFT-3251](https://issues.apache.org/jira/browse/THRIFT-3251) - Add http transport for server to Go lib - [THRIFT-2424](https://issues.apache.org/jira/browse/THRIFT-2424) - Recursive Types - [THRIFT-2423](https://issues.apache.org/jira/browse/THRIFT-2423) - THeader - [THRIFT-2413](https://issues.apache.org/jira/browse/THRIFT-2413) - Python: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-2409](https://issues.apache.org/jira/browse/THRIFT-2409) - Java: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-2412](https://issues.apache.org/jira/browse/THRIFT-2412) - D: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-2411](https://issues.apache.org/jira/browse/THRIFT-2411) - C++: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-2410](https://issues.apache.org/jira/browse/THRIFT-2410) - JavaMe: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-2668](https://issues.apache.org/jira/browse/THRIFT-2668) - TestSuite: detailed result on passed tests by feature - [THRIFT-2659](https://issues.apache.org/jira/browse/THRIFT-2659) - python Test Server fails when throwing TException - [THRIFT-3398](https://issues.apache.org/jira/browse/THRIFT-3398) - Add CMake build for Haskell library and tests - [THRIFT-3396](https://issues.apache.org/jira/browse/THRIFT-3396) - DART: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-3364](https://issues.apache.org/jira/browse/THRIFT-3364) - Fix ruby binary field encoding in TJSONProtocol - [THRIFT-3381](https://issues.apache.org/jira/browse/THRIFT-3381) - Fix for misc. codegen issues with THRIFT-2905 - [THRIFT-3573](https://issues.apache.org/jira/browse/THRIFT-3573) - No rule to make target `../../../test/c_glib/src/.deps/testthrifttest-thrift_test_handler.Po'. - [THRIFT-3572](https://issues.apache.org/jira/browse/THRIFT-3572) - "Unable to determine the behavior of a signed right shift" - [THRIFT-3542](https://issues.apache.org/jira/browse/THRIFT-3542) - Add length limit support to Java test server - [THRIFT-3537](https://issues.apache.org/jira/browse/THRIFT-3537) - Remove the (now obsolete) csharp:asyncctp flag - [THRIFT-3532](https://issues.apache.org/jira/browse/THRIFT-3532) - Add configurable string and container read size limit to Python protocols - [THRIFT-3531](https://issues.apache.org/jira/browse/THRIFT-3531) - Create cross lang feature test for string and container read length limit - [THRIFT-3482](https://issues.apache.org/jira/browse/THRIFT-3482) - Haskell JSON protocol does not encode binary field as Base64 - [THRIFT-3425](https://issues.apache.org/jira/browse/THRIFT-3425) - Minor fixes + simplification for CentOS Dockerfile - [THRIFT-3442](https://issues.apache.org/jira/browse/THRIFT-3442) - Run CMake tests on Appveyor - [THRIFT-3409](https://issues.apache.org/jira/browse/THRIFT-3409) - NodeJS binary field issues - [THRIFT-3621](https://issues.apache.org/jira/browse/THRIFT-3621) - Fix lib/cpp/test/SecurityTest.cpp to use ephemeral ports - [THRIFT-3628](https://issues.apache.org/jira/browse/THRIFT-3628) - Fix lib/cpp/test/TServerIntegrationTest.cpp to use ephemeral ports - [THRIFT-3625](https://issues.apache.org/jira/browse/THRIFT-3625) - Kill unused #include "TestPortFixture.h" in lib/cpp/test/TServerTransportTest.cpp. - [THRIFT-3646](https://issues.apache.org/jira/browse/THRIFT-3646) - Fix Python extension build warnings - [THRIFT-3626](https://issues.apache.org/jira/browse/THRIFT-3626) - Fix lib/cpp/test/TSocketInterruptTest.cpp to use ephemeral ports. - [THRIFT-3624](https://issues.apache.org/jira/browse/THRIFT-3624) - Fix lib/cpp/test/TServerSocketTest.cpp to use ephemeral ports - [THRIFT-3623](https://issues.apache.org/jira/browse/THRIFT-3623) - Fix Fix cpp/lib/test/TSSLSocketInterruptTest.cpp to use ephemeral ports - [THRIFT-3592](https://issues.apache.org/jira/browse/THRIFT-3592) - Add basic test client - [THRIFT-3980](https://issues.apache.org/jira/browse/THRIFT-3980) - add TExtendedBinaryProtocol.java ### Task - [THRIFT-1801](https://issues.apache.org/jira/browse/THRIFT-1801) - Sync up TApplicationException codes across languages and thrift implementations - [THRIFT-1259](https://issues.apache.org/jira/browse/THRIFT-1259) - Automate versioning ### Test - [THRIFT-3400](https://issues.apache.org/jira/browse/THRIFT-3400) - Add Erlang to cross test - [THRIFT-3504](https://issues.apache.org/jira/browse/THRIFT-3504) - Fix FastbinaryTest.py ### Wish - [THRIFT-3923](https://issues.apache.org/jira/browse/THRIFT-3923) - Maybe remove Aereo from the "Powered by" list - [THRIFT-2149](https://issues.apache.org/jira/browse/THRIFT-2149) - Add an option to disable the generation of default operators ## 0.9.3.1 Released March 13, 2019 to backport a CVE fix to the popular 0.9.3 release. ### Bug - [THRIFT-4506](https://issues.apache.org/jira/browse/THRIFT-4506) - CVE-2018-1320 for Java SASL backported from 0.12.0 ## 0.9.3 ### Bug - [THRIFT-2441](https://issues.apache.org/jira/browse/THRIFT-2441) - Cannot shutdown TThreadedServer when clients are still connected - [THRIFT-2465](https://issues.apache.org/jira/browse/THRIFT-2465) - TBinaryProtocolT breaks if copied/moved - [THRIFT-2474](https://issues.apache.org/jira/browse/THRIFT-2474) - thrift.h causes a compile failure - [THRIFT-2540](https://issues.apache.org/jira/browse/THRIFT-2540) - Running configure from outside the source directory fails - [THRIFT-2598](https://issues.apache.org/jira/browse/THRIFT-2598) - Add check for minimum Go version to configure.ac - [THRIFT-2647](https://issues.apache.org/jira/browse/THRIFT-2647) - compiler-hs: don't decapitalize field names, do decapitalize argument bindings - [THRIFT-2773](https://issues.apache.org/jira/browse/THRIFT-2773) - Generated Java code for 'oneway' methods is incorrect. - [THRIFT-2789](https://issues.apache.org/jira/browse/THRIFT-2789) - TNonblockingServer leaks socket FD's under load - [THRIFT-2682](https://issues.apache.org/jira/browse/THRIFT-2682) - TThreadedServer leaks per-thread memory - [THRIFT-2674](https://issues.apache.org/jira/browse/THRIFT-2674) - JavaScript: declare Accept: and Content-Type: in request - [THRIFT-3078](https://issues.apache.org/jira/browse/THRIFT-3078) - TNonblockingServerSocket's logger is not named after TNonblockingServerSocket - [THRIFT-3077](https://issues.apache.org/jira/browse/THRIFT-3077) - C++ TFileTransport ignores return code from ftruncate - [THRIFT-3067](https://issues.apache.org/jira/browse/THRIFT-3067) - C++ cppcheck performance related warnings - [THRIFT-3066](https://issues.apache.org/jira/browse/THRIFT-3066) - C++ TDenseProtocol assert modifies instead of checks - [THRIFT-3071](https://issues.apache.org/jira/browse/THRIFT-3071) - bootstrap.sh on Ubuntu 12.04 (Precise) automake error - [THRIFT-3069](https://issues.apache.org/jira/browse/THRIFT-3069) - C++ TServerSocket leaks socket on fcntl get or set flags error - [THRIFT-3079](https://issues.apache.org/jira/browse/THRIFT-3079) - TNonblockingServerSocket's logger is not named after TNonblockingServerSocket - [THRIFT-3080](https://issues.apache.org/jira/browse/THRIFT-3080) - C++ TNonblockingServer connection leak while accept huge number connections. - [THRIFT-3086](https://issues.apache.org/jira/browse/THRIFT-3086) - C++ Valgrind Error Cleanup - [THRIFT-3085](https://issues.apache.org/jira/browse/THRIFT-3085) - thrift_reconnecting_client never try to reconnect - [THRIFT-3123](https://issues.apache.org/jira/browse/THRIFT-3123) - Missing include in compiler/cpp/src/main.h breaks build in some environments - [THRIFT-3125](https://issues.apache.org/jira/browse/THRIFT-3125) - Fix the list of exported headers in automake input - [THRIFT-3126](https://issues.apache.org/jira/browse/THRIFT-3126) - PHP JSON serializer converts empty or int-indexed maps to lists - [THRIFT-3132](https://issues.apache.org/jira/browse/THRIFT-3132) - Properly format date in Java @Generated annotations - [THRIFT-3137](https://issues.apache.org/jira/browse/THRIFT-3137) - Travis build hangs after failure - [THRIFT-3138](https://issues.apache.org/jira/browse/THRIFT-3138) - "make check" parallel execution is underministic - [THRIFT-3139](https://issues.apache.org/jira/browse/THRIFT-3139) - JS library test is flaky - [THRIFT-3140](https://issues.apache.org/jira/browse/THRIFT-3140) - ConcurrentModificationException is thrown by JavaScript test server - [THRIFT-3124](https://issues.apache.org/jira/browse/THRIFT-3124) - Some signed/unsigned warnings while building compiler - [THRIFT-3128](https://issues.apache.org/jira/browse/THRIFT-3128) - Go generated code produces name collisions between services - [THRIFT-3146](https://issues.apache.org/jira/browse/THRIFT-3146) - Graphviz generates function name collisions between services - [THRIFT-3147](https://issues.apache.org/jira/browse/THRIFT-3147) - Segfault while receiving data - [THRIFT-3148](https://issues.apache.org/jira/browse/THRIFT-3148) - Markdown links to coding_standards are dead - [THRIFT-3090](https://issues.apache.org/jira/browse/THRIFT-3090) - cmake build is broken on MacOSX - [THRIFT-3097](https://issues.apache.org/jira/browse/THRIFT-3097) - cmake targets unconditionally depend on optional libraries - [THRIFT-3094](https://issues.apache.org/jira/browse/THRIFT-3094) - master as of 2015-APR-13 fails -DBOOST_THREADS cmake build - [THRIFT-3099](https://issues.apache.org/jira/browse/THRIFT-3099) - cmake build is broken on FreeBSD - [THRIFT-3089](https://issues.apache.org/jira/browse/THRIFT-3089) - Assigning default ENUM values results in non-compilable java code if java namespace is not defined - [THRIFT-3093](https://issues.apache.org/jira/browse/THRIFT-3093) - mingw compile fixes for c++ library 0.9.2 - [THRIFT-3098](https://issues.apache.org/jira/browse/THRIFT-3098) - Thrift does not pretty print binary typedefs the way it does binary fields - [THRIFT-3091](https://issues.apache.org/jira/browse/THRIFT-3091) - c_glib service method should return result from handler method - [THRIFT-3088](https://issues.apache.org/jira/browse/THRIFT-3088) - TThreadPoolServer with Sasl auth may leak CLOSE_WAIT socket - [THRIFT-3109](https://issues.apache.org/jira/browse/THRIFT-3109) - Cross test log file cannot be browsed when served in HTTP server - [THRIFT-3113](https://issues.apache.org/jira/browse/THRIFT-3113) - m4 C++11 macro issue - [THRIFT-3105](https://issues.apache.org/jira/browse/THRIFT-3105) - C++ libthriftnb library on Windows build failure - [THRIFT-3115](https://issues.apache.org/jira/browse/THRIFT-3115) - Uncompileable code due to name collision with predefined used types - [THRIFT-3117](https://issues.apache.org/jira/browse/THRIFT-3117) - Java TSSLTransportFactory can't load certificates within JAR archive - [THRIFT-3102](https://issues.apache.org/jira/browse/THRIFT-3102) - could not make check for Go Library - [THRIFT-3120](https://issues.apache.org/jira/browse/THRIFT-3120) - Minor spelling errors and an outdated URL - [THRIFT-3121](https://issues.apache.org/jira/browse/THRIFT-3121) - Librt does not exist on OS X - [THRIFT-3152](https://issues.apache.org/jira/browse/THRIFT-3152) - Compiler error on Mac OSX (missing #include ) - [THRIFT-3162](https://issues.apache.org/jira/browse/THRIFT-3162) - make fails for dmd 2.067 - [THRIFT-3164](https://issues.apache.org/jira/browse/THRIFT-3164) - Thrift C++ library SSL socket by default allows for unsecure SSLv3 negotiation - [THRIFT-3168](https://issues.apache.org/jira/browse/THRIFT-3168) - Fix Maven POM - [THRIFT-3170](https://issues.apache.org/jira/browse/THRIFT-3170) - Initialism code in the Go compiler causes chaos - [THRIFT-3169](https://issues.apache.org/jira/browse/THRIFT-3169) - Do not export thrift.TestStruct and thrift.TestEnum in thrift Go library - [THRIFT-3191](https://issues.apache.org/jira/browse/THRIFT-3191) - Perl compiler does not add support for unexpected exception handling - [THRIFT-3178](https://issues.apache.org/jira/browse/THRIFT-3178) - glib C does not compile - [THRIFT-3189](https://issues.apache.org/jira/browse/THRIFT-3189) - Perl ServerSocket should allow a specific interface to be listened to - [THRIFT-3252](https://issues.apache.org/jira/browse/THRIFT-3252) - Missing TConcurrentClientSyncInfo.h in cpp Makefile, so doesn't install - [THRIFT-3255](https://issues.apache.org/jira/browse/THRIFT-3255) - Thrift generator doesn't exclude 'package' keyword for thrift property names breaking java builds - [THRIFT-3260](https://issues.apache.org/jira/browse/THRIFT-3260) - multiple warnings in c_glib tutorial - [THRIFT-3256](https://issues.apache.org/jira/browse/THRIFT-3256) - Some D test timings are too aggressive for slow machines - [THRIFT-3257](https://issues.apache.org/jira/browse/THRIFT-3257) - warning: extra tokens at end of #endif directive - [THRIFT-3184](https://issues.apache.org/jira/browse/THRIFT-3184) - Thrift Go leaves file descriptors open - [THRIFT-3203](https://issues.apache.org/jira/browse/THRIFT-3203) - DOAP) - please fix "Ocaml" => "OCaml" - [THRIFT-3210](https://issues.apache.org/jira/browse/THRIFT-3210) - (uncompileable) code generated for server events while are events not enabled - [THRIFT-3215](https://issues.apache.org/jira/browse/THRIFT-3215) - TJSONProtocol '(c++) uses "throw new" to throw exceptions instead of "throw" - [THRIFT-3202](https://issues.apache.org/jira/browse/THRIFT-3202) - Allow HSHAServer to configure min and max worker threads separately. - [THRIFT-3205](https://issues.apache.org/jira/browse/THRIFT-3205) - TCompactProtocol return a wrong error when the io.EOF happens - [THRIFT-3209](https://issues.apache.org/jira/browse/THRIFT-3209) - LGPL mentioned in license file - [THRIFT-3197](https://issues.apache.org/jira/browse/THRIFT-3197) - keepAliveTime is hard coded as 60 sec in TThreadPoolServer - [THRIFT-3196](https://issues.apache.org/jira/browse/THRIFT-3196) - Misspelling in lua TBinaryProtocol (stirctWrite => strictWrite) - [THRIFT-3198](https://issues.apache.org/jira/browse/THRIFT-3198) - Allow construction of TTransportFactory with a specified maxLength - [THRIFT-3192](https://issues.apache.org/jira/browse/THRIFT-3192) - Go import paths changed in 1.4, and expired June 1 - [THRIFT-3271](https://issues.apache.org/jira/browse/THRIFT-3271) - Could not find or load main class configtest_ax_javac_and_java on some non-english systems - [THRIFT-3273](https://issues.apache.org/jira/browse/THRIFT-3273) - c_glib: Generated code tries to convert between function and void pointers - [THRIFT-3264](https://issues.apache.org/jira/browse/THRIFT-3264) - Fix Erlang 16 namespaced types - [THRIFT-3270](https://issues.apache.org/jira/browse/THRIFT-3270) - reusing TNonblockingServer::TConnection cause dirty TSocket - [THRIFT-3267](https://issues.apache.org/jira/browse/THRIFT-3267) - c_glib: "Critical" failure during unit tests - [THRIFT-3277](https://issues.apache.org/jira/browse/THRIFT-3277) - THttpClient leaks connections if it's used for multiple requests - [THRIFT-3278](https://issues.apache.org/jira/browse/THRIFT-3278) - NodeJS: Fix exception stack traces and names - [THRIFT-3279](https://issues.apache.org/jira/browse/THRIFT-3279) - Fix a bug in retry_max_delay (NodeJS) - [THRIFT-3280](https://issues.apache.org/jira/browse/THRIFT-3280) - Initialize retry variables on construction - [THRIFT-3283](https://issues.apache.org/jira/browse/THRIFT-3283) - c_glib: Tutorial server always exits with warning - [THRIFT-3284](https://issues.apache.org/jira/browse/THRIFT-3284) - c_glib: Empty service produces unused-variable warning - [THRIFT-1925](https://issues.apache.org/jira/browse/THRIFT-1925) - c_glib generated code does not compile - [THRIFT-1849](https://issues.apache.org/jira/browse/THRIFT-1849) - after transport->open() opens isOpen returns true and next open() goes thru when it shall not - [THRIFT-1866](https://issues.apache.org/jira/browse/THRIFT-1866) - java compiler generates non-compiling code with const's defined in a thrift when name includes non-identifier chars - [THRIFT-1938](https://issues.apache.org/jira/browse/THRIFT-1938) - FunctionRunner.h -- uses wrong path for Thread.h when installed - [THRIFT-1844](https://issues.apache.org/jira/browse/THRIFT-1844) - Password string not cleared - [THRIFT-2004](https://issues.apache.org/jira/browse/THRIFT-2004) - Thrift::Union violates :== method contract and crashes - [THRIFT-2073](https://issues.apache.org/jira/browse/THRIFT-2073) - Thrift C++ THttpClient error: cannot refill buffer - [THRIFT-2127](https://issues.apache.org/jira/browse/THRIFT-2127) - Autoconf scripting does not properly account for cross-compile - [THRIFT-2180](https://issues.apache.org/jira/browse/THRIFT-2180) - Integer types issues in Cocoa lib on ARM64 - [THRIFT-2189](https://issues.apache.org/jira/browse/THRIFT-2189) - Go needs "isset" to fully support "union" type (and optionals) - [THRIFT-2192](https://issues.apache.org/jira/browse/THRIFT-2192) - autotools on Redhat based systems - [THRIFT-2546](https://issues.apache.org/jira/browse/THRIFT-2546) - cross language tests fails at 'TestMultiException' when using nodejs server - [THRIFT-2547](https://issues.apache.org/jira/browse/THRIFT-2547) - nodejs servers and clients fails to connect with cpp using compact protocol - [THRIFT-2548](https://issues.apache.org/jira/browse/THRIFT-2548) - Nodejs servers and clients does not work properly with -ssl - [THRIFT-1471](https://issues.apache.org/jira/browse/THRIFT-1471) - toString() does not print ByteBuffer values when nested in a List - [THRIFT-1201](https://issues.apache.org/jira/browse/THRIFT-1201) - getaddrinfo resource leak - [THRIFT-615](https://issues.apache.org/jira/browse/THRIFT-615) - TThreadPoolServer doesn't call task_done after pulling tasks from it's clients queue - [THRIFT-162](https://issues.apache.org/jira/browse/THRIFT-162) - Thrift structures are unhashable, preventing them from being used as set elements - [THRIFT-810](https://issues.apache.org/jira/browse/THRIFT-810) - Crashed client on TSocket::close under loads - [THRIFT-557](https://issues.apache.org/jira/browse/THRIFT-557) - charset problem with file Autogenerated by Thrift - [THRIFT-233](https://issues.apache.org/jira/browse/THRIFT-233) - IDL doesn't support negative hex literals - [THRIFT-1649](https://issues.apache.org/jira/browse/THRIFT-1649) - contrib/zeromq does not build in 0.8.0 - [THRIFT-1642](https://issues.apache.org/jira/browse/THRIFT-1642) - Miscalculation lead to throw unexpected "TTransportException::TIMED_OUT"(or called "EAGAIN (timed out)") exception - [THRIFT-1587](https://issues.apache.org/jira/browse/THRIFT-1587) - TSocket::setRecvTimeout error - [THRIFT-1248](https://issues.apache.org/jira/browse/THRIFT-1248) - pointer subtraction in TMemoryBuffer relies on undefined behavior - [THRIFT-1774](https://issues.apache.org/jira/browse/THRIFT-1774) - Sasl Transport client would hang when trying to connect non-sasl transport server - [THRIFT-1754](https://issues.apache.org/jira/browse/THRIFT-1754) - RangeError in buffer handling - [THRIFT-1618](https://issues.apache.org/jira/browse/THRIFT-1618) - static structMap in FieldMetaData is not thread safe and can lead to deadlocks - [THRIFT-2335](https://issues.apache.org/jira/browse/THRIFT-2335) - thrift incompatibility with py:tornado as server, java as client - [THRIFT-2803](https://issues.apache.org/jira/browse/THRIFT-2803) - TCP_DEFER_ACCEPT not supported with domain sockets - [THRIFT-2799](https://issues.apache.org/jira/browse/THRIFT-2799) - Build Problem(s): ld: library not found for -l:libboost_unit_test_framework.a - [THRIFT-2801](https://issues.apache.org/jira/browse/THRIFT-2801) - C++ test suite compilation warnings - [THRIFT-2802](https://issues.apache.org/jira/browse/THRIFT-2802) - C++ tutorial compilation warnings - [THRIFT-2795](https://issues.apache.org/jira/browse/THRIFT-2795) - thrift_binary_protocol.c: 'dereferencing type-punned pointer will break strict-aliasing rules' - [THRIFT-2817](https://issues.apache.org/jira/browse/THRIFT-2817) - TSimpleJSONProtocol reads beyond end of message - [THRIFT-2826](https://issues.apache.org/jira/browse/THRIFT-2826) - html:standalone sometimes ignored - [THRIFT-2829](https://issues.apache.org/jira/browse/THRIFT-2829) - Support haxelib installation via github - [THRIFT-2828](https://issues.apache.org/jira/browse/THRIFT-2828) - slightly wrong help screen indent - [THRIFT-2831](https://issues.apache.org/jira/browse/THRIFT-2831) - Removes dead code in web_server.js introduced in THRIFT-2819 - [THRIFT-2823](https://issues.apache.org/jira/browse/THRIFT-2823) - All JS-tests are failing when run with grunt test - [THRIFT-2827](https://issues.apache.org/jira/browse/THRIFT-2827) - Thrift 0.9.2 fails to compile on Yosemite due to tr1/functional include in ProcessorTest.cpp - [THRIFT-2843](https://issues.apache.org/jira/browse/THRIFT-2843) - Automake configure.ac has possible typo related to Java - [THRIFT-2813](https://issues.apache.org/jira/browse/THRIFT-2813) - multiple haxe library fixes/improvements - [THRIFT-2825](https://issues.apache.org/jira/browse/THRIFT-2825) - Supplying unicode to python Thrift client can cause next request arguments to get overwritten - [THRIFT-2840](https://issues.apache.org/jira/browse/THRIFT-2840) - Cabal file points to LICENSE file outside the path of the Haskell project. - [THRIFT-2818](https://issues.apache.org/jira/browse/THRIFT-2818) - Trailing commas in array - [THRIFT-2830](https://issues.apache.org/jira/browse/THRIFT-2830) - Clean up ant warnings in tutorial dir - [THRIFT-2842](https://issues.apache.org/jira/browse/THRIFT-2842) - Erlang thrift client has infinite timeout - [THRIFT-2810](https://issues.apache.org/jira/browse/THRIFT-2810) - Do not leave the underlying ServerSocket open if construction of TServerSocket fails - [THRIFT-2812](https://issues.apache.org/jira/browse/THRIFT-2812) - Go server adding redundant buffering layer - [THRIFT-2839](https://issues.apache.org/jira/browse/THRIFT-2839) - TFramedTransport read bug - [THRIFT-2844](https://issues.apache.org/jira/browse/THRIFT-2844) - Nodejs support broken when running under Browserify - [THRIFT-2814](https://issues.apache.org/jira/browse/THRIFT-2814) - args/result classes not found when no namespace is set - [THRIFT-2847](https://issues.apache.org/jira/browse/THRIFT-2847) - function IfValue() is a duplicate of System.StrUtils.IfThen - [THRIFT-2848](https://issues.apache.org/jira/browse/THRIFT-2848) - certain Delphi tests do not build if TypeRegistry is used - [THRIFT-2854](https://issues.apache.org/jira/browse/THRIFT-2854) - Go Struct writer and reader looses important error information - [THRIFT-2858](https://issues.apache.org/jira/browse/THRIFT-2858) - Enable header field case insensitive match in THttpServer - [THRIFT-2857](https://issues.apache.org/jira/browse/THRIFT-2857) - C# generator creates uncompilable code for struct constants - [THRIFT-2860](https://issues.apache.org/jira/browse/THRIFT-2860) - Delphi server closes connection on unexpected exceptions - [THRIFT-2868](https://issues.apache.org/jira/browse/THRIFT-2868) - Enhance error handling in the Go client - [THRIFT-2879](https://issues.apache.org/jira/browse/THRIFT-2879) - TMemoryBuffer: using lua string in wrong way - [THRIFT-2851](https://issues.apache.org/jira/browse/THRIFT-2851) - Remove strange public Peek() from Go transports - [THRIFT-2852](https://issues.apache.org/jira/browse/THRIFT-2852) - Better Open/IsOpen/Close behavior for StreamTransport. - [THRIFT-2871](https://issues.apache.org/jira/browse/THRIFT-2871) - Missing semicolon in thrift.js - [THRIFT-2872](https://issues.apache.org/jira/browse/THRIFT-2872) - ThreadManager deadlock for task expiration - [THRIFT-2881](https://issues.apache.org/jira/browse/THRIFT-2881) - Handle errors from Accept() correctly - [THRIFT-2849](https://issues.apache.org/jira/browse/THRIFT-2849) - Spell errors reported by codespell tool - [THRIFT-2870](https://issues.apache.org/jira/browse/THRIFT-2870) - C++ TJSONProtocol using locale dependent formatting - [THRIFT-2882](https://issues.apache.org/jira/browse/THRIFT-2882) - Lua Generator: using string.len function to get struct(map,list,set) size - [THRIFT-2864](https://issues.apache.org/jira/browse/THRIFT-2864) - JSON generator missing from Visual Studio build project - [THRIFT-2878](https://issues.apache.org/jira/browse/THRIFT-2878) - Go validation support of required fields - [THRIFT-2873](https://issues.apache.org/jira/browse/THRIFT-2873) - TPipe and TPipeServer don't compile on Windows with UNICODE enabled - [THRIFT-2888](https://issues.apache.org/jira/browse/THRIFT-2888) - import of is missing in JSON generator - [THRIFT-2900](https://issues.apache.org/jira/browse/THRIFT-2900) - Python THttpClient does not reset socket timeout on exception - [THRIFT-2907](https://issues.apache.org/jira/browse/THRIFT-2907) - 'ntohll' macro redefined - [THRIFT-2884](https://issues.apache.org/jira/browse/THRIFT-2884) - Map does not serialize correctly for JSON protocol in Go library - [THRIFT-2887](https://issues.apache.org/jira/browse/THRIFT-2887) - --with-openssl configure flag is ignored - [THRIFT-2894](https://issues.apache.org/jira/browse/THRIFT-2894) - PHP json serializer skips maps with int/bool keys - [THRIFT-2904](https://issues.apache.org/jira/browse/THRIFT-2904) - json_protocol_test.go fails - [THRIFT-2906](https://issues.apache.org/jira/browse/THRIFT-2906) - library not found for -l:libboost_unit_test_framework.a - [THRIFT-2890](https://issues.apache.org/jira/browse/THRIFT-2890) - binary data may lose bytes with JSON transport under specific circumstances - [THRIFT-2891](https://issues.apache.org/jira/browse/THRIFT-2891) - binary data may cause a failure with JSON transport under specific circumstances - [THRIFT-2901](https://issues.apache.org/jira/browse/THRIFT-2901) - Fix for generated TypeScript functions + indentation of JavaScript maps - [THRIFT-2916](https://issues.apache.org/jira/browse/THRIFT-2916) - make check fails for D language - [THRIFT-2918](https://issues.apache.org/jira/browse/THRIFT-2918) - Race condition in Python TProcessPoolServer test - [THRIFT-2920](https://issues.apache.org/jira/browse/THRIFT-2920) - Erlang Thrift test uses wrong IDL file - [THRIFT-2922](https://issues.apache.org/jira/browse/THRIFT-2922) - $TRIAL is used with Python tests but not tested accordingly - [THRIFT-2912](https://issues.apache.org/jira/browse/THRIFT-2912) - Autotool build for C++ Qt library is invalid - [THRIFT-2914](https://issues.apache.org/jira/browse/THRIFT-2914) - explicit dependency to Lua5.2 fails on some systems - [THRIFT-2910](https://issues.apache.org/jira/browse/THRIFT-2910) - libevent is not really optional - [THRIFT-2911](https://issues.apache.org/jira/browse/THRIFT-2911) - fix c++ version zeromq transport, the old version cannot work - [THRIFT-2915](https://issues.apache.org/jira/browse/THRIFT-2915) - Lua generator missing from Visual Studio build project - [THRIFT-2917](https://issues.apache.org/jira/browse/THRIFT-2917) - "make clean" breaks test/c_glib - [THRIFT-2919](https://issues.apache.org/jira/browse/THRIFT-2919) - Haxe test server timeout too large - [THRIFT-2923](https://issues.apache.org/jira/browse/THRIFT-2923) - JavaScript client assumes a message being written - [THRIFT-2924](https://issues.apache.org/jira/browse/THRIFT-2924) - TNonblockingServer crashes when user-provided event_base is used - [THRIFT-2925](https://issues.apache.org/jira/browse/THRIFT-2925) - CMake build does not work with OpenSSL nor anything installed in non-system location - [THRIFT-2931](https://issues.apache.org/jira/browse/THRIFT-2931) - Access to undeclared static property: Thrift\Protocol\TProtocol::$TBINARYPROTOCOLACCELERATED - [THRIFT-2893](https://issues.apache.org/jira/browse/THRIFT-2893) - CMake build fails with boost thread or std thread - [THRIFT-2902](https://issues.apache.org/jira/browse/THRIFT-2902) - Generated c_glib code does not compile with clang - [THRIFT-2903](https://issues.apache.org/jira/browse/THRIFT-2903) - Qt4 library built with CMake does not work - [THRIFT-2942](https://issues.apache.org/jira/browse/THRIFT-2942) - CSharp generate invalid code for property named read or write - [THRIFT-2932](https://issues.apache.org/jira/browse/THRIFT-2932) - Node.js Thrift connection libraries throw Exceptions into event emitter - [THRIFT-2933](https://issues.apache.org/jira/browse/THRIFT-2933) - v0.9.2: doubles encoded in node with compact protocol cannot be decoded by python - [THRIFT-2934](https://issues.apache.org/jira/browse/THRIFT-2934) - createServer signature mismatch - [THRIFT-2981](https://issues.apache.org/jira/browse/THRIFT-2981) - IDL with no namespace produces unparsable PHP - [THRIFT-2999](https://issues.apache.org/jira/browse/THRIFT-2999) - Addition of .gitattributes text auto in THRIFT-2724 causes modified files on checkout - [THRIFT-2949](https://issues.apache.org/jira/browse/THRIFT-2949) - typo in compiler/cpp/README.md - [THRIFT-2957](https://issues.apache.org/jira/browse/THRIFT-2957) - warning: source file %s is in a subdirectory, but option 'subdir-objects' is disabled - [THRIFT-2953](https://issues.apache.org/jira/browse/THRIFT-2953) - TNamedPipeServerTransport is not Stop()able - [THRIFT-2962](https://issues.apache.org/jira/browse/THRIFT-2962) - Docker Thrift env for development and testing - [THRIFT-2971](https://issues.apache.org/jira/browse/THRIFT-2971) - C++ test and tutorial parallel build is unstable - [THRIFT-2972](https://issues.apache.org/jira/browse/THRIFT-2972) - Missing backslash in lib/cpp/test/Makefile.am - [THRIFT-2951](https://issues.apache.org/jira/browse/THRIFT-2951) - Fix Erlang name conflict test - [THRIFT-2955](https://issues.apache.org/jira/browse/THRIFT-2955) - Using list of typedefs does not compile on Go - [THRIFT-2960](https://issues.apache.org/jira/browse/THRIFT-2960) - namespace regression for Ruby - [THRIFT-2959](https://issues.apache.org/jira/browse/THRIFT-2959) - nodejs: fix binary unit tests - [THRIFT-2966](https://issues.apache.org/jira/browse/THRIFT-2966) - nodejs: Fix bad references to TProtocolException and TProtocolExceptionType - [THRIFT-2970](https://issues.apache.org/jira/browse/THRIFT-2970) - grunt-jsdoc fails due to dependency issues - [THRIFT-3001](https://issues.apache.org/jira/browse/THRIFT-3001) - C# Equals fails for binary fields (byte[]) - [THRIFT-3003](https://issues.apache.org/jira/browse/THRIFT-3003) - Missing LICENSE file prevents package from being installed - [THRIFT-3008](https://issues.apache.org/jira/browse/THRIFT-3008) - Node.js server does not fully support exception - [THRIFT-3007](https://issues.apache.org/jira/browse/THRIFT-3007) - Travis build is broken because of directory conflict - [THRIFT-3009](https://issues.apache.org/jira/browse/THRIFT-3009) - TSSLSocket does not use the correct hostname (breaks certificate checks) - [THRIFT-3011](https://issues.apache.org/jira/browse/THRIFT-3011) - C# test server testException() not implemented according to specs - [THRIFT-3012](https://issues.apache.org/jira/browse/THRIFT-3012) - Timing problems in NamedPipe implementation due to unnecessary open/close - [THRIFT-3019](https://issues.apache.org/jira/browse/THRIFT-3019) - Golang generator missing docstring for structs - [THRIFT-3021](https://issues.apache.org/jira/browse/THRIFT-3021) - Service remote tool does not import stub package with package prefix - [THRIFT-3026](https://issues.apache.org/jira/browse/THRIFT-3026) - TMultiplexedProcessor does not have a constructor - [THRIFT-3028](https://issues.apache.org/jira/browse/THRIFT-3028) - Regression caused by THRIFT-2180 - [THRIFT-3017](https://issues.apache.org/jira/browse/THRIFT-3017) - order of map key/value types incorrect for one CTOR - [THRIFT-3020](https://issues.apache.org/jira/browse/THRIFT-3020) - Cannot compile thrift as C++03 - [THRIFT-3024](https://issues.apache.org/jira/browse/THRIFT-3024) - User-Agent "BattleNet" used in some Thrift library files - [THRIFT-3047](https://issues.apache.org/jira/browse/THRIFT-3047) - Uneven calls to indent_up and indent_down in Cocoa generator - [THRIFT-3048](https://issues.apache.org/jira/browse/THRIFT-3048) - NodeJS decoding of I64 is inconsistent across protocols - [THRIFT-3043](https://issues.apache.org/jira/browse/THRIFT-3043) - go compiler generator uses non C++98 code - [THRIFT-3044](https://issues.apache.org/jira/browse/THRIFT-3044) - Docker README.md paths to Dockerfiles are incorrect - [THRIFT-3040](https://issues.apache.org/jira/browse/THRIFT-3040) - bower.json wrong "main" path - [THRIFT-3051](https://issues.apache.org/jira/browse/THRIFT-3051) - Go Thrift generator creates bad go code - [THRIFT-3057](https://issues.apache.org/jira/browse/THRIFT-3057) - Java compiler build is broken - [THRIFT-3061](https://issues.apache.org/jira/browse/THRIFT-3061) - C++ TSSLSocket shutdown delay/vulnerability - [THRIFT-3062](https://issues.apache.org/jira/browse/THRIFT-3062) - C++ TServerSocket invalid port number (over 999999) causes stack corruption - [THRIFT-3065](https://issues.apache.org/jira/browse/THRIFT-3065) - Update libthrift dependencies (slf4j, httpcore, httpclient) - [THRIFT-3244](https://issues.apache.org/jira/browse/THRIFT-3244) - TypeScript: fix namespace of included types - [THRIFT-3246](https://issues.apache.org/jira/browse/THRIFT-3246) - Reduce the number of trivial warnings in Windows C++ CMake builds - [THRIFT-3224](https://issues.apache.org/jira/browse/THRIFT-3224) - Fix TNamedPipeServer unpredictable behavior on accept - [THRIFT-3230](https://issues.apache.org/jira/browse/THRIFT-3230) - Python compiler generates wrong code if there is function throwing a typedef of exception with another namespace - [THRIFT-3236](https://issues.apache.org/jira/browse/THRIFT-3236) - MaxSkipDepth never checked - [THRIFT-3239](https://issues.apache.org/jira/browse/THRIFT-3239) - Limit recursion depth - [THRIFT-3241](https://issues.apache.org/jira/browse/THRIFT-3241) - fatal error: runtime: cannot map pages in arena address space - [THRIFT-3242](https://issues.apache.org/jira/browse/THRIFT-3242) - OSGi Import-Package directive is missing the Apache HTTP packages - [THRIFT-3234](https://issues.apache.org/jira/browse/THRIFT-3234) - Limit recursion depth - [THRIFT-3222](https://issues.apache.org/jira/browse/THRIFT-3222) - TypeScript: Generated Enums are quoted - [THRIFT-3229](https://issues.apache.org/jira/browse/THRIFT-3229) - unexpected Timeout exception when desired bytes are only partially available - [THRIFT-3231](https://issues.apache.org/jira/browse/THRIFT-3231) - CPP: Limit recursion depth to 64 - [THRIFT-3235](https://issues.apache.org/jira/browse/THRIFT-3235) - Limit recursion depth - [THRIFT-3175](https://issues.apache.org/jira/browse/THRIFT-3175) - fastbinary.c python deserialize can cause huge allocations from garbage - [THRIFT-3176](https://issues.apache.org/jira/browse/THRIFT-3176) - Union incorrectly implements == - [THRIFT-3177](https://issues.apache.org/jira/browse/THRIFT-3177) - Fails to run rake test - [THRIFT-3180](https://issues.apache.org/jira/browse/THRIFT-3180) - lua plugin: framed transport do not work - [THRIFT-3179](https://issues.apache.org/jira/browse/THRIFT-3179) - lua plugin cant connect to remote server because function l_socket_create_and_connect always bind socket to localhost - [THRIFT-3248](https://issues.apache.org/jira/browse/THRIFT-3248) - TypeScript: additional comma in method signature without parameters - [THRIFT-3302](https://issues.apache.org/jira/browse/THRIFT-3302) - Go JSON protocol should encode Thrift byte type as signed integer string - [THRIFT-3297](https://issues.apache.org/jira/browse/THRIFT-3297) - c_glib: an abstract base class is not generated - [THRIFT-3294](https://issues.apache.org/jira/browse/THRIFT-3294) - TZlibTransport for Java does not write data correctly - [THRIFT-3296](https://issues.apache.org/jira/browse/THRIFT-3296) - Go cross test does not conform to spec - [THRIFT-3295](https://issues.apache.org/jira/browse/THRIFT-3295) - C# library does not build on Mono 4.0.2.5 or later - [THRIFT-3293](https://issues.apache.org/jira/browse/THRIFT-3293) - JavaScript: null values turn into empty structs in constructor - [THRIFT-3310](https://issues.apache.org/jira/browse/THRIFT-3310) - lib/erl/README.md has incorrect formatting - [THRIFT-3319](https://issues.apache.org/jira/browse/THRIFT-3319) - CSharp tutorial will not build using the *.sln - [THRIFT-3335](https://issues.apache.org/jira/browse/THRIFT-3335) - Ruby server does not handle processor exception - [THRIFT-3338](https://issues.apache.org/jira/browse/THRIFT-3338) - Stray underscore in generated go when service name starts with "New" - [THRIFT-3324](https://issues.apache.org/jira/browse/THRIFT-3324) - Update Go Docs for pulling all packages - [THRIFT-3345](https://issues.apache.org/jira/browse/THRIFT-3345) - Clients blocked indefinitely when a java.lang.Error is thrown - [THRIFT-3332](https://issues.apache.org/jira/browse/THRIFT-3332) - make dist fails on clean build - [THRIFT-3326](https://issues.apache.org/jira/browse/THRIFT-3326) - Tests do not compile under *BSD - [THRIFT-3334](https://issues.apache.org/jira/browse/THRIFT-3334) - Markdown notation of protocol spec is malformed - [THRIFT-3331](https://issues.apache.org/jira/browse/THRIFT-3331) - warning: ‘etype’ may be used uninitialized in this function - [THRIFT-3349](https://issues.apache.org/jira/browse/THRIFT-3349) - Python server does not handle processor exception - [THRIFT-3343](https://issues.apache.org/jira/browse/THRIFT-3343) - Fix haskell README - [THRIFT-3340](https://issues.apache.org/jira/browse/THRIFT-3340) - Python: enable json tests again - [THRIFT-3311](https://issues.apache.org/jira/browse/THRIFT-3311) - Top level README.md has incorrect formmating - [THRIFT-2936](https://issues.apache.org/jira/browse/THRIFT-2936) - Minor memory leak in SSL - [THRIFT-3290](https://issues.apache.org/jira/browse/THRIFT-3290) - Using from in variable names causes the generated Python code to have errors - [THRIFT-3225](https://issues.apache.org/jira/browse/THRIFT-3225) - Fix TPipeServer unpredictable behavior on interrupt() - [THRIFT-3354](https://issues.apache.org/jira/browse/THRIFT-3354) - Fix word-extraction substr bug in initialism code - [THRIFT-2006](https://issues.apache.org/jira/browse/THRIFT-2006) - TBinaryProtocol message header call name length is not validated and can be used to core the server - [THRIFT-3329](https://issues.apache.org/jira/browse/THRIFT-3329) - C++ library unit tests don't compile against the new boost-1.59 unit test framework - [THRIFT-2630](https://issues.apache.org/jira/browse/THRIFT-2630) - windows7 64bit pc. ipv4 and ipv6 pc.can't use - [THRIFT-3336](https://issues.apache.org/jira/browse/THRIFT-3336) - Thrift generated streaming operators added in 0.9.2 cannot be overridden - [THRIFT-2681](https://issues.apache.org/jira/browse/THRIFT-2681) - Core of unwind_cleanup - [THRIFT-3317](https://issues.apache.org/jira/browse/THRIFT-3317) - cpp namespace org.apache issue appears in 0.9 ### Documentation - [THRIFT-3286](https://issues.apache.org/jira/browse/THRIFT-3286) - Apache Ant is a necessary dependency ### Improvement - [THRIFT-227](https://issues.apache.org/jira/browse/THRIFT-227) - Byte[] in collections aren't pretty printed like regular binary fields - [THRIFT-2744](https://issues.apache.org/jira/browse/THRIFT-2744) - Vagrantfile for Centos 6.5 - [THRIFT-2644](https://issues.apache.org/jira/browse/THRIFT-2644) - Haxe support - [THRIFT-2756](https://issues.apache.org/jira/browse/THRIFT-2756) - register Media Type @ IANA - [THRIFT-3076](https://issues.apache.org/jira/browse/THRIFT-3076) - Compatibility with Haxe 3.2.0 - [THRIFT-3081](https://issues.apache.org/jira/browse/THRIFT-3081) - C++ Consolidate client processing loops in TServers - [THRIFT-3083](https://issues.apache.org/jira/browse/THRIFT-3083) - C++ Consolidate server processing loops in TSimpleServer, TThreadedServer, TThreadPoolServer - [THRIFT-3084](https://issues.apache.org/jira/browse/THRIFT-3084) - C++ add concurrent client limit to threaded servers - [THRIFT-3074](https://issues.apache.org/jira/browse/THRIFT-3074) - Add compiler/cpp/lex.yythriftl.cc to gitignore. - [THRIFT-3134](https://issues.apache.org/jira/browse/THRIFT-3134) - Remove use of deprecated "phantom.args" - [THRIFT-3133](https://issues.apache.org/jira/browse/THRIFT-3133) - Allow "make cross" and "make precross" to run without building all languages - [THRIFT-3142](https://issues.apache.org/jira/browse/THRIFT-3142) - Make JavaScript use downloaded libraries - [THRIFT-3141](https://issues.apache.org/jira/browse/THRIFT-3141) - Improve logging of JavaScript test - [THRIFT-3144](https://issues.apache.org/jira/browse/THRIFT-3144) - Proposal: make String representation of enums in generated go code less verbose - [THRIFT-3130](https://issues.apache.org/jira/browse/THRIFT-3130) - Remove the last vestiges of THRIFT_OVERLOAD_IF from THRIFT-1316 - [THRIFT-3131](https://issues.apache.org/jira/browse/THRIFT-3131) - Consolidate suggested import path for go thrift library to git.apache.org in docs and code - [THRIFT-3092](https://issues.apache.org/jira/browse/THRIFT-3092) - Generated Haskell types should derive Generic - [THRIFT-3110](https://issues.apache.org/jira/browse/THRIFT-3110) - Print error log after cross test failures on Travis - [THRIFT-3114](https://issues.apache.org/jira/browse/THRIFT-3114) - Using local temp variables to not pollute the global table - [THRIFT-3106](https://issues.apache.org/jira/browse/THRIFT-3106) - CMake summary should give more information why a library is set to off - [THRIFT-3119](https://issues.apache.org/jira/browse/THRIFT-3119) - Java's TThreadedSelectorServer has indistinguishable log messages in run() - [THRIFT-3122](https://issues.apache.org/jira/browse/THRIFT-3122) - Javascript struct constructor should properly initialize struct and container members from plain js arguments - [THRIFT-3151](https://issues.apache.org/jira/browse/THRIFT-3151) - Fix links to git-wip*) - should be git.apache.org - [THRIFT-3167](https://issues.apache.org/jira/browse/THRIFT-3167) - Windows build from source instructions need to be revised - [THRIFT-3155](https://issues.apache.org/jira/browse/THRIFT-3155) - move contrib/mingw32-toolchain.cmake to build/cmake/ - [THRIFT-3160](https://issues.apache.org/jira/browse/THRIFT-3160) - Make generated go enums implement TextMarshaller and TextUnmarshaller interfaces - [THRIFT-3150](https://issues.apache.org/jira/browse/THRIFT-3150) - Add an option to thrift go generator to make Read and Write methods private - [THRIFT-3149](https://issues.apache.org/jira/browse/THRIFT-3149) - Make ReadFieldN methods in generated Go code private - [THRIFT-3172](https://issues.apache.org/jira/browse/THRIFT-3172) - Add tutorial to Thrift web site - [THRIFT-3214](https://issues.apache.org/jira/browse/THRIFT-3214) - Add Erlang option for using maps instead of dicts - [THRIFT-3201](https://issues.apache.org/jira/browse/THRIFT-3201) - Capture github test artifacts for failed builds - [THRIFT-3266](https://issues.apache.org/jira/browse/THRIFT-3266) - c_glib: Multiple compiler warnings building unit tests - [THRIFT-3285](https://issues.apache.org/jira/browse/THRIFT-3285) - c_glib: Build library with all warnings enabled, no warnings generated - [THRIFT-1954](https://issues.apache.org/jira/browse/THRIFT-1954) - Allow for a separate connection timeout value - [THRIFT-2098](https://issues.apache.org/jira/browse/THRIFT-2098) - Add support for Qt5+ - [THRIFT-2199](https://issues.apache.org/jira/browse/THRIFT-2199) - Remove Dense protocol (was: move to Contrib) - [THRIFT-406](https://issues.apache.org/jira/browse/THRIFT-406) - C++ Test suite cleanup - [THRIFT-902](https://issues.apache.org/jira/browse/THRIFT-902) - socket and connect timeout in TSocket should be distinguished - [THRIFT-388](https://issues.apache.org/jira/browse/THRIFT-388) - Use a separate wire format for async calls - [THRIFT-727](https://issues.apache.org/jira/browse/THRIFT-727) - support native C++ language specific exception message - [THRIFT-1784](https://issues.apache.org/jira/browse/THRIFT-1784) - pep-3110 compliance for exception handling - [THRIFT-1025](https://issues.apache.org/jira/browse/THRIFT-1025) - C++ ServerSocket should inherit from Socket with the necessary Ctor to listen on connections from a specific host - [THRIFT-2269](https://issues.apache.org/jira/browse/THRIFT-2269) - Can deploy libthrift-source.jar to maven center repository - [THRIFT-2804](https://issues.apache.org/jira/browse/THRIFT-2804) - Pull an interface out of TBaseAsyncProcessor - [THRIFT-2806](https://issues.apache.org/jira/browse/THRIFT-2806) - more whitespace fixups - [THRIFT-2811](https://issues.apache.org/jira/browse/THRIFT-2811) - Make remote socket address accessible - [THRIFT-2809](https://issues.apache.org/jira/browse/THRIFT-2809) - .gitignore update for compiler's visual project - [THRIFT-2846](https://issues.apache.org/jira/browse/THRIFT-2846) - Expose ciphers parameter from ssl.wrap_socket() - [THRIFT-2859](https://issues.apache.org/jira/browse/THRIFT-2859) - JSON generator: output complete descriptors - [THRIFT-2861](https://issues.apache.org/jira/browse/THRIFT-2861) - add buffered transport - [THRIFT-2865](https://issues.apache.org/jira/browse/THRIFT-2865) - Test case for Go: SeqId out of sequence - [THRIFT-2866](https://issues.apache.org/jira/browse/THRIFT-2866) - Go generator source code is hard to read and maintain - [THRIFT-2880](https://issues.apache.org/jira/browse/THRIFT-2880) - Read the network address from the listener if available. - [THRIFT-2875](https://issues.apache.org/jira/browse/THRIFT-2875) - Typo in TDenseProtocol.h comment - [THRIFT-2874](https://issues.apache.org/jira/browse/THRIFT-2874) - TBinaryProtocol member variable "string_buf_" is never used. - [THRIFT-2855](https://issues.apache.org/jira/browse/THRIFT-2855) - Move contributing.md to the root of the repository - [THRIFT-2862](https://issues.apache.org/jira/browse/THRIFT-2862) - Enable RTTI and/or build macros for generated code - [THRIFT-2876](https://issues.apache.org/jira/browse/THRIFT-2876) - Add test for THRIFT-2526 Assignment operators and copy constructors in c++ don't copy the __isset struct - [THRIFT-2897](https://issues.apache.org/jira/browse/THRIFT-2897) - Generate -isEqual: and -hash methods - [THRIFT-2909](https://issues.apache.org/jira/browse/THRIFT-2909) - Improve travis build - [THRIFT-2921](https://issues.apache.org/jira/browse/THRIFT-2921) - Make Erlang impl ready for OTP 18 release (dict/0 and set/0 are deprecated) - [THRIFT-2928](https://issues.apache.org/jira/browse/THRIFT-2928) - Rename the erlang test_server module - [THRIFT-2940](https://issues.apache.org/jira/browse/THRIFT-2940) - Allow installing Thrift from git as NPM module by providing package.json in top level directory - [THRIFT-2937](https://issues.apache.org/jira/browse/THRIFT-2937) - Allow setting a maximum frame size in TFramedTransport - [THRIFT-2976](https://issues.apache.org/jira/browse/THRIFT-2976) - nodejs: xhr and websocket support for browserify - [THRIFT-2996](https://issues.apache.org/jira/browse/THRIFT-2996) - Test for Haxe 3.1.3 or better - [THRIFT-2969](https://issues.apache.org/jira/browse/THRIFT-2969) - nodejs: DRY up library tests - [THRIFT-2973](https://issues.apache.org/jira/browse/THRIFT-2973) - Update Haxe lib readme regarding Haxe 3.1.3 - [THRIFT-2952](https://issues.apache.org/jira/browse/THRIFT-2952) - Improve handling of Server.Stop() - [THRIFT-2964](https://issues.apache.org/jira/browse/THRIFT-2964) - nodejs: move protocols and transports into separate files - [THRIFT-2963](https://issues.apache.org/jira/browse/THRIFT-2963) - nodejs) - add test coverage - [THRIFT-3006](https://issues.apache.org/jira/browse/THRIFT-3006) - Attach 'omitempty' json tag for optional fields in Go - [THRIFT-3027](https://issues.apache.org/jira/browse/THRIFT-3027) - Go compiler does not ensure common initialisms have consistent case - [THRIFT-3030](https://issues.apache.org/jira/browse/THRIFT-3030) - TThreadedServer: Property for number of clientThreads - [THRIFT-3023](https://issues.apache.org/jira/browse/THRIFT-3023) - Go compiler is a little overly conservative with names of attributes - [THRIFT-3018](https://issues.apache.org/jira/browse/THRIFT-3018) - Compact protocol for Delphi - [THRIFT-3025](https://issues.apache.org/jira/browse/THRIFT-3025) - Change pure Int constants into @enums (where possible) - [THRIFT-3031](https://issues.apache.org/jira/browse/THRIFT-3031) - migrate "shouldStop" flag to TServer - [THRIFT-3022](https://issues.apache.org/jira/browse/THRIFT-3022) - Compact protocol for Haxe - [THRIFT-3041](https://issues.apache.org/jira/browse/THRIFT-3041) - Generate asynchronous clients for Cocoa - [THRIFT-3053](https://issues.apache.org/jira/browse/THRIFT-3053) - Perl SSL Socket Support (Encryption) - [THRIFT-3247](https://issues.apache.org/jira/browse/THRIFT-3247) - Generate a C++ thread-safe client - [THRIFT-3217](https://issues.apache.org/jira/browse/THRIFT-3217) - Provide a little endian variant of the binary protocol in C++ - [THRIFT-3223](https://issues.apache.org/jira/browse/THRIFT-3223) - TypeScript: Add initial support for Enum Maps - [THRIFT-3220](https://issues.apache.org/jira/browse/THRIFT-3220) - Option to suppress @Generated Annotation entirely - [THRIFT-3300](https://issues.apache.org/jira/browse/THRIFT-3300) - Reimplement TZlibTransport in Java using streams - [THRIFT-3288](https://issues.apache.org/jira/browse/THRIFT-3288) - c_glib: Build unit tests with all warnings enabled, no warnings generated - [THRIFT-3347](https://issues.apache.org/jira/browse/THRIFT-3347) - Improve cross test servers and clients - [THRIFT-3342](https://issues.apache.org/jira/browse/THRIFT-3342) - Improve ruby cross test client and server compatibility - [THRIFT-2296](https://issues.apache.org/jira/browse/THRIFT-2296) - Add C++ Base class for service - [THRIFT-3337](https://issues.apache.org/jira/browse/THRIFT-3337) - Add testBool method to cross tests - [THRIFT-3303](https://issues.apache.org/jira/browse/THRIFT-3303) - Disable concurrent cabal jobs on Travis to avoid GHC crash - [THRIFT-2623](https://issues.apache.org/jira/browse/THRIFT-2623) - Docker container for Thrift - [THRIFT-3298](https://issues.apache.org/jira/browse/THRIFT-3298) - thrift endian converters may conflict with other libraries - [THRIFT-1559](https://issues.apache.org/jira/browse/THRIFT-1559) - Provide memory pool for TBinaryProtocol to eliminate memory fragmentation - [THRIFT-424](https://issues.apache.org/jira/browse/THRIFT-424) - Steal ProtocolBuffers' VarInt implementation for C++ ### New Feature - [THRIFT-3070](https://issues.apache.org/jira/browse/THRIFT-3070) - Add ability to set the LocalCertificateSelectionCallback - [THRIFT-1909](https://issues.apache.org/jira/browse/THRIFT-1909) - Java: Add compiler flag to use the "option pattern" for optional fields - [THRIFT-2099](https://issues.apache.org/jira/browse/THRIFT-2099) - Stop TThreadPoolServer with alive connections. - [THRIFT-123](https://issues.apache.org/jira/browse/THRIFT-123) - implement TZlibTransport in Java - [THRIFT-2368](https://issues.apache.org/jira/browse/THRIFT-2368) - New option: reuse-objects for Java generator - [THRIFT-2836](https://issues.apache.org/jira/browse/THRIFT-2836) - Optionally generate C++11 MoveConstructible types - [THRIFT-2824](https://issues.apache.org/jira/browse/THRIFT-2824) - Flag to disable html escaping doctext - [THRIFT-2819](https://issues.apache.org/jira/browse/THRIFT-2819) - Add WebsSocket client to node.js - [THRIFT-3050](https://issues.apache.org/jira/browse/THRIFT-3050) - Client certificate authentication for non-http TLS in C# - [THRIFT-3292](https://issues.apache.org/jira/browse/THRIFT-3292) - Implement TZlibTransport in Go ### Question - [THRIFT-2583](https://issues.apache.org/jira/browse/THRIFT-2583) - Thrift on xPC target (SpeedGoat) - [THRIFT-2592](https://issues.apache.org/jira/browse/THRIFT-2592) - thrift server using c_glib - [THRIFT-2832](https://issues.apache.org/jira/browse/THRIFT-2832) - c_glib: Handle string lists correctly - [THRIFT-3136](https://issues.apache.org/jira/browse/THRIFT-3136) - thrift installation problem on mac - [THRIFT-3346](https://issues.apache.org/jira/browse/THRIFT-3346) - c_glib: Tutorials example crashes saying Calculator.ping implementation returned FALSE but did not set an error ### Sub-task - [THRIFT-2578](https://issues.apache.org/jira/browse/THRIFT-2578) - Moving 'make cross' from test.sh to test.py - [THRIFT-2734](https://issues.apache.org/jira/browse/THRIFT-2734) - Go coding standards - [THRIFT-2748](https://issues.apache.org/jira/browse/THRIFT-2748) - Add Vagrantfile for Centos 6.5 - [THRIFT-2753](https://issues.apache.org/jira/browse/THRIFT-2753) - Misc. Haxe improvements - [THRIFT-2640](https://issues.apache.org/jira/browse/THRIFT-2640) - Compact Protocol in Cocoa - [THRIFT-3262](https://issues.apache.org/jira/browse/THRIFT-3262) - warning: overflow in implicit constant conversion in DenseProtoTest.cpp - [THRIFT-3194](https://issues.apache.org/jira/browse/THRIFT-3194) - Can't build with go enabled. gomock SCC path incorrect. - [THRIFT-3275](https://issues.apache.org/jira/browse/THRIFT-3275) - c_glib tutorial warnings in generated code - [THRIFT-1125](https://issues.apache.org/jira/browse/THRIFT-1125) - Multiplexing support for the Ruby Library - [THRIFT-2807](https://issues.apache.org/jira/browse/THRIFT-2807) - PHP Code Style - [THRIFT-2841](https://issues.apache.org/jira/browse/THRIFT-2841) - Add comprehensive integration tests for the whole Go stack - [THRIFT-2815](https://issues.apache.org/jira/browse/THRIFT-2815) - Haxe: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-2886](https://issues.apache.org/jira/browse/THRIFT-2886) - Integrate binary type in standard Thrift cross test - [THRIFT-2946](https://issues.apache.org/jira/browse/THRIFT-2946) - Enhance usability of cross test framework - [THRIFT-2967](https://issues.apache.org/jira/browse/THRIFT-2967) - Add .editorconfig to root - [THRIFT-3033](https://issues.apache.org/jira/browse/THRIFT-3033) - Perl: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-3174](https://issues.apache.org/jira/browse/THRIFT-3174) - Initialism code in the Go compiler doesn't check first word - [THRIFT-3193](https://issues.apache.org/jira/browse/THRIFT-3193) - Option to suppress date value in @Generated annotation - [THRIFT-3305](https://issues.apache.org/jira/browse/THRIFT-3305) - Missing dist files for 0.9.3 release candidate - [THRIFT-3341](https://issues.apache.org/jira/browse/THRIFT-3341) - Add testBool methods - [THRIFT-3308](https://issues.apache.org/jira/browse/THRIFT-3308) - Fix broken test cases for 0.9.3 release candidate ### Task - [THRIFT-2834](https://issues.apache.org/jira/browse/THRIFT-2834) - Remove semi-colons from python code generator - [THRIFT-2853](https://issues.apache.org/jira/browse/THRIFT-2853) - Adjust comments not applying anymore after THRIFT-2852 ### Test - [THRIFT-3211](https://issues.apache.org/jira/browse/THRIFT-3211) - Add make cross support for php TCompactProtocol ### Wish - [THRIFT-2838](https://issues.apache.org/jira/browse/THRIFT-2838) - TNonblockingServer can bind to port 0 (i.e., get an OS-assigned port) but there is no way to get the port number ## 0.9.2 ### Bug - [THRIFT-2793](https://issues.apache.org/jira/browse/THRIFT-2793) - Go compiler produces uncompilable code - [THRIFT-1481](https://issues.apache.org/jira/browse/THRIFT-1481) - Unix domain sockets in C++ do not support the abstract namespace - [THRIFT-1455](https://issues.apache.org/jira/browse/THRIFT-1455) - TBinaryProtocolT::writeString casts from size_t to uint32_t, which is not safe on 64-bit platforms - [THRIFT-1579](https://issues.apache.org/jira/browse/THRIFT-1579) - PHP Extension) - function thrift_protocol_read_binary not working from TBinarySerializer::deserialize - [THRIFT-1584](https://issues.apache.org/jira/browse/THRIFT-1584) - Error: could not SetMinThreads in ThreadPool on single-core machines - [THRIFT-1614](https://issues.apache.org/jira/browse/THRIFT-1614) - Thrift build from svn repo sources fails with automake-1.12 - [THRIFT-1047](https://issues.apache.org/jira/browse/THRIFT-1047) - rb_thrift_memory_buffer_write treats arg as string without check, segfaults if you pass non-string - [THRIFT-1639](https://issues.apache.org/jira/browse/THRIFT-1639) - Java/Python: Serialization/Deserialization of double type using CompactProtocol - [THRIFT-1647](https://issues.apache.org/jira/browse/THRIFT-1647) - NodeJS BufferedTransport does not work beyond the hello-world example - [THRIFT-2130](https://issues.apache.org/jira/browse/THRIFT-2130) - Thrift's D library/test: parts of "make check" code do not compile with recent dmd-2.062 through dmd-2.064alpha - [THRIFT-2140](https://issues.apache.org/jira/browse/THRIFT-2140) - Error compiling cpp tutorials - [THRIFT-2139](https://issues.apache.org/jira/browse/THRIFT-2139) - MSVC 2012 Error) - Cannot compile due to BoostThreadFactory - [THRIFT-2138](https://issues.apache.org/jira/browse/THRIFT-2138) - pkgconfig file created with wrong include path - [THRIFT-2160](https://issues.apache.org/jira/browse/THRIFT-2160) - Warning in thrift.h when compiling with -Wunused and NDEBUG - [THRIFT-2158](https://issues.apache.org/jira/browse/THRIFT-2158) - Compact, JSON, and SimpleJSON protocols are not working correctly - [THRIFT-2167](https://issues.apache.org/jira/browse/THRIFT-2167) - nodejs lib throws error if options argument isn't passed - [THRIFT-2288](https://issues.apache.org/jira/browse/THRIFT-2288) - Go impl of Thrift JSON protocol wrongly writes/expects true/false for bools - [THRIFT-2147](https://issues.apache.org/jira/browse/THRIFT-2147) - Thrift IDL grammar allows for dotted identifier names - [THRIFT-2145](https://issues.apache.org/jira/browse/THRIFT-2145) - Rack and Thin are not just development dependencies - [THRIFT-2267](https://issues.apache.org/jira/browse/THRIFT-2267) - Should be able to choose socket family in Python TSocket - [THRIFT-2276](https://issues.apache.org/jira/browse/THRIFT-2276) - java path in spec file needs updating - [THRIFT-2281](https://issues.apache.org/jira/browse/THRIFT-2281) - Generated send/recv code ignores errors returned by the underlying protocol - [THRIFT-2280](https://issues.apache.org/jira/browse/THRIFT-2280) - TJSONProtocol.Flush() does not really flush the transport - [THRIFT-2274](https://issues.apache.org/jira/browse/THRIFT-2274) - TNonblockingServer and TThreadedSelectorServer do not close their channel selectors on exit and leak file descriptors - [THRIFT-2265](https://issues.apache.org/jira/browse/THRIFT-2265) - php library doesn't build - [THRIFT-2232](https://issues.apache.org/jira/browse/THRIFT-2232) - IsSet* broken in Go - [THRIFT-2246](https://issues.apache.org/jira/browse/THRIFT-2246) - Unset enum value is printed by ToString() - [THRIFT-2240](https://issues.apache.org/jira/browse/THRIFT-2240) - thrift.vim (contrib) does not correctly handle 'union' - [THRIFT-2243](https://issues.apache.org/jira/browse/THRIFT-2243) - TNonblockingServer in thrift crashes when TFramedTransport opens - [THRIFT-2230](https://issues.apache.org/jira/browse/THRIFT-2230) - Cannot Build on RHEL/Centos/Amazon Linux 6.x - [THRIFT-2247](https://issues.apache.org/jira/browse/THRIFT-2247) - Go generator doesn't deal well with map keys of type binary - [THRIFT-2253](https://issues.apache.org/jira/browse/THRIFT-2253) - Python Tornado TTornadoServer base class change - [THRIFT-2261](https://issues.apache.org/jira/browse/THRIFT-2261) - java: error: unmappable character for encoding ASCII - [THRIFT-2259](https://issues.apache.org/jira/browse/THRIFT-2259) - C#: unexpected null logDelegate() pointer causes AV in TServer.serve() - [THRIFT-2225](https://issues.apache.org/jira/browse/THRIFT-2225) - SSLContext destroy before cleanupOpenSSL - [THRIFT-2224](https://issues.apache.org/jira/browse/THRIFT-2224) - TSSLSocket.h and TSSLServerSocket.h should use the platfromsocket too - [THRIFT-2229](https://issues.apache.org/jira/browse/THRIFT-2229) - thrift failed to build on OSX 10.9 GM - [THRIFT-2227](https://issues.apache.org/jira/browse/THRIFT-2227) - Thrift compiler generates spurious warnings with Xlint - [THRIFT-2219](https://issues.apache.org/jira/browse/THRIFT-2219) - Thrift gem fails to build on OS X Mavericks with 1.9.3 rubies - [THRIFT-2226](https://issues.apache.org/jira/browse/THRIFT-2226) - TServerSocket) - keepAlive wrong initialization order - [THRIFT-2285](https://issues.apache.org/jira/browse/THRIFT-2285) - TJsonProtocol implementation for Java doesn't allow a slash (/) to be escaped (\/) - [THRIFT-2216](https://issues.apache.org/jira/browse/THRIFT-2216) - Extraneous semicolon in TProtocolUtil.h makes clang mad - [THRIFT-2215](https://issues.apache.org/jira/browse/THRIFT-2215) - Generated HTML/Graphviz lists referenced enum identifiers as UNKNOWN. - [THRIFT-2211](https://issues.apache.org/jira/browse/THRIFT-2211) - Exception constructor does not contain namespace prefix. - [THRIFT-2210](https://issues.apache.org/jira/browse/THRIFT-2210) - lib/java TSimpleJSONProtocol can emit invalid JSON - [THRIFT-2209](https://issues.apache.org/jira/browse/THRIFT-2209) - Ruby generator -- please namespace classes - [THRIFT-2202](https://issues.apache.org/jira/browse/THRIFT-2202) - Delphi TServerImpl.DefaultLogDelegate may stop the server with I/O-Error 105 - [THRIFT-2201](https://issues.apache.org/jira/browse/THRIFT-2201) - Ternary operator returns different types (build error for some compilers) - [THRIFT-2200](https://issues.apache.org/jira/browse/THRIFT-2200) - nested structs cause generate_fingerprint() to slow down at excessive CPU load - [THRIFT-2197](https://issues.apache.org/jira/browse/THRIFT-2197) - fix jar output directory in rpm spec file - [THRIFT-2196](https://issues.apache.org/jira/browse/THRIFT-2196) - Fix invalid dependency in Makefile.am - [THRIFT-2194](https://issues.apache.org/jira/browse/THRIFT-2194) - Node: Not actually prepending residual data in TFramedTransport.receiver - [THRIFT-2193](https://issues.apache.org/jira/browse/THRIFT-2193) - Java code generator emits spurious semicolon when deep copying binary data - [THRIFT-2191](https://issues.apache.org/jira/browse/THRIFT-2191) - Fix charp JSONProtocol.ReadJSONDouble (specify InvariantCulture) - [THRIFT-2214](https://issues.apache.org/jira/browse/THRIFT-2214) - System header sys/param.h is included inside the Thrift namespace - [THRIFT-2178](https://issues.apache.org/jira/browse/THRIFT-2178) - Thrift generator returns error exit code on --version - [THRIFT-2171](https://issues.apache.org/jira/browse/THRIFT-2171) - NodeJS implementation has extremely low test coverage - [THRIFT-2183](https://issues.apache.org/jira/browse/THRIFT-2183) - gem install fails on zsh - [THRIFT-2182](https://issues.apache.org/jira/browse/THRIFT-2182) - segfault in regression tests (GC bug in rb_thrift_memory_buffer_write) - [THRIFT-2181](https://issues.apache.org/jira/browse/THRIFT-2181) - oneway calls don't work in NodeJS - [THRIFT-2169](https://issues.apache.org/jira/browse/THRIFT-2169) - JavaME Thrift Library causes "java.io.IOException: No Response Entries Available" after using the Thrift client for some time - [THRIFT-2168](https://issues.apache.org/jira/browse/THRIFT-2168) - Node.js appears broken (at least, examples don't work as intended) - [THRIFT-2293](https://issues.apache.org/jira/browse/THRIFT-2293) - TSSLTransportFactory.createSSLContext() leaves files open - [THRIFT-2279](https://issues.apache.org/jira/browse/THRIFT-2279) - TSerializer only returns the first 1024 bytes serialized - [THRIFT-2278](https://issues.apache.org/jira/browse/THRIFT-2278) - Buffered transport doesn't support writes > buffer size - [THRIFT-2275](https://issues.apache.org/jira/browse/THRIFT-2275) - Fix memory leak in golang compact_protocol. - [THRIFT-2282](https://issues.apache.org/jira/browse/THRIFT-2282) - Incorect code generated for some typedefs - [THRIFT-2009](https://issues.apache.org/jira/browse/THRIFT-2009) - Go redeclaration error - [THRIFT-1964](https://issues.apache.org/jira/browse/THRIFT-1964) - 'Isset' causes problems with C#/.NET serializers - [THRIFT-2026](https://issues.apache.org/jira/browse/THRIFT-2026) - Fix TCompactProtocol 64 bit builds - [THRIFT-2108](https://issues.apache.org/jira/browse/THRIFT-2108) - Fix TAsyncClientManager timeout race - [THRIFT-2068](https://issues.apache.org/jira/browse/THRIFT-2068) - Multiple calls from same connection are not processed in node - [THRIFT-1750](https://issues.apache.org/jira/browse/THRIFT-1750) - Make compiler build cleanly under visual studio 10 - [THRIFT-1755](https://issues.apache.org/jira/browse/THRIFT-1755) - Comment parsing bug - [THRIFT-1771](https://issues.apache.org/jira/browse/THRIFT-1771) - "make check" fails on x64 for libboost_unit_test_framework.a - [THRIFT-1841](https://issues.apache.org/jira/browse/THRIFT-1841) - NodeJS Thrift incorrectly parses non-UTF8-string types - [THRIFT-1908](https://issues.apache.org/jira/browse/THRIFT-1908) - Using php thrift_protocol accelerated transfer causes core dump - [THRIFT-1892](https://issues.apache.org/jira/browse/THRIFT-1892) - Socket timeouts are declared in milli-seconds, but are actually set in micro-seconds - [THRIFT-2303](https://issues.apache.org/jira/browse/THRIFT-2303) - TBufferredTransport not properly closing underlying transport - [THRIFT-2313](https://issues.apache.org/jira/browse/THRIFT-2313) - nodejs server crash after processing the first request when using MultiplexedProcessor/FramedBuffer/BinaryProtocol - [THRIFT-2311](https://issues.apache.org/jira/browse/THRIFT-2311) - Go: invalid code generated when exception name is a go keyword - [THRIFT-2308](https://issues.apache.org/jira/browse/THRIFT-2308) - node: TJSONProtocol parse error when reading from buffered message - [THRIFT-2316](https://issues.apache.org/jira/browse/THRIFT-2316) - ccp: TFileTransportTest - [THRIFT-2352](https://issues.apache.org/jira/browse/THRIFT-2352) - msvc failed to compile thrift tests - [THRIFT-2337](https://issues.apache.org/jira/browse/THRIFT-2337) - Golang does not report TIMED_OUT exceptions - [THRIFT-2340](https://issues.apache.org/jira/browse/THRIFT-2340) - Generated server implementation does not send response type EXCEPTION on the Thrift.TApplicationExceptionType.UNKNOWN_METHOD exception - [THRIFT-2354](https://issues.apache.org/jira/browse/THRIFT-2354) - Connection errors can lead to case_clause exceptions - [THRIFT-2339](https://issues.apache.org/jira/browse/THRIFT-2339) - Uncaught exception in thrift c# driver - [THRIFT-2356](https://issues.apache.org/jira/browse/THRIFT-2356) - c++ thrift client not working with ssl (SSL_connect hangs) - [THRIFT-2331](https://issues.apache.org/jira/browse/THRIFT-2331) - Missing call to ReadStructBegin() in TApplicationException.Read() - [THRIFT-2323](https://issues.apache.org/jira/browse/THRIFT-2323) - Uncompileable Delphi code generated for typedef'd structs - [THRIFT-2322](https://issues.apache.org/jira/browse/THRIFT-2322) - Correctly show the number of times ExecutorService (java) has rejected the client. - [THRIFT-2389](https://issues.apache.org/jira/browse/THRIFT-2389) - namespaces handled wrongly in acrionscript 3.0 implementation - [THRIFT-2388](https://issues.apache.org/jira/browse/THRIFT-2388) - GoLang) - Fix data races in simple_server and server_socket - [THRIFT-2386](https://issues.apache.org/jira/browse/THRIFT-2386) - Thrift refuses to link yylex - [THRIFT-2375](https://issues.apache.org/jira/browse/THRIFT-2375) - Excessive
's in generated HTML - [THRIFT-2373](https://issues.apache.org/jira/browse/THRIFT-2373) - warning CS0414 in THttpClient.cs: private field 'Thrift.Transport.THttpClient.connection' assigned but never used - [THRIFT-2372](https://issues.apache.org/jira/browse/THRIFT-2372) - thrift/json_protocol.go:160: function ends without a return statement - [THRIFT-2371](https://issues.apache.org/jira/browse/THRIFT-2371) - ruby bundler version fails on ~1.3.1, remove and take latest avail - [THRIFT-2370](https://issues.apache.org/jira/browse/THRIFT-2370) - Compiler SEGFAULTs generating HTML documentation for complex strucre - [THRIFT-2384](https://issues.apache.org/jira/browse/THRIFT-2384) - Binary map keys produce uncompilable code in go - [THRIFT-2380](https://issues.apache.org/jira/browse/THRIFT-2380) - unreachable code (CID 1174546, CID 1174679) - [THRIFT-2378](https://issues.apache.org/jira/browse/THRIFT-2378) - service method arguments of binary type lead to uncompileable Go code - [THRIFT-2363](https://issues.apache.org/jira/browse/THRIFT-2363) - Issue with character encoding of Success returned from Login using Thrift Proxy and NodeJS - [THRIFT-2359](https://issues.apache.org/jira/browse/THRIFT-2359) - TBufferedTransport doesn't clear it's buffer on a failed flush call - [THRIFT-2428](https://issues.apache.org/jira/browse/THRIFT-2428) - Python 3 setup.py support - [THRIFT-2367](https://issues.apache.org/jira/browse/THRIFT-2367) - Build failure: stdlib and boost both define uint64_t - [THRIFT-2365](https://issues.apache.org/jira/browse/THRIFT-2365) - C# decodes too many binary bytes from JSON - [THRIFT-2402](https://issues.apache.org/jira/browse/THRIFT-2402) - byte count of FrameBuffer in AWAITING_CLOSE state is not subtracted from readBufferBytesAllocated - [THRIFT-2396](https://issues.apache.org/jira/browse/THRIFT-2396) - Build Error on MacOSX - [THRIFT-2395](https://issues.apache.org/jira/browse/THRIFT-2395) - thrift Ruby gem requires development dependency 'thin' regardless of environment - [THRIFT-2414](https://issues.apache.org/jira/browse/THRIFT-2414) - c_glib fix several bug. - [THRIFT-2420](https://issues.apache.org/jira/browse/THRIFT-2420) - Go argument parser for methods without arguments does not skip fields - [THRIFT-2439](https://issues.apache.org/jira/browse/THRIFT-2439) - Bug in TProtocolDecorator Class causes parsing errors - [THRIFT-2419](https://issues.apache.org/jira/browse/THRIFT-2419) - golang) - Fix fmt.Errorf in generated code - [THRIFT-2418](https://issues.apache.org/jira/browse/THRIFT-2418) - Go handler function panics on internal error - [THRIFT-2405](https://issues.apache.org/jira/browse/THRIFT-2405) - Node.js Multiplexer tests fail (silently) - [THRIFT-2581](https://issues.apache.org/jira/browse/THRIFT-2581) - TFDTransport destructor should not throw - [THRIFT-2575](https://issues.apache.org/jira/browse/THRIFT-2575) - Thrift includes siginfo_t within apache::thrift::protocol namespace - [THRIFT-2577](https://issues.apache.org/jira/browse/THRIFT-2577) - TFileTransport missuse of closesocket on windows platform - [THRIFT-2576](https://issues.apache.org/jira/browse/THRIFT-2576) - Implement Thrift.Protocol.prototype.skip method in JavaScript library - [THRIFT-2588](https://issues.apache.org/jira/browse/THRIFT-2588) - Thrift compiler is not buildable in Visual Studio 2010 - [THRIFT-2594](https://issues.apache.org/jira/browse/THRIFT-2594) - JS Compiler: Single quotes are not being escaped in constants. - [THRIFT-2591](https://issues.apache.org/jira/browse/THRIFT-2591) - TFramedTransport does not handle payloads split across packets correctly - [THRIFT-2599](https://issues.apache.org/jira/browse/THRIFT-2599) - Uncompileable Delphi code due to naming conflicts with IDL - [THRIFT-2590](https://issues.apache.org/jira/browse/THRIFT-2590) - C++ Visual Studio solution doesn't include Multiplexing support - [THRIFT-2595](https://issues.apache.org/jira/browse/THRIFT-2595) - Node.js: Fix global leaks and copy-paste errors - [THRIFT-2565](https://issues.apache.org/jira/browse/THRIFT-2565) - autoconf fails to find mingw-g++ cross compiler on travis CI - [THRIFT-2555](https://issues.apache.org/jira/browse/THRIFT-2555) - excessive "unused field" comments - [THRIFT-2554](https://issues.apache.org/jira/browse/THRIFT-2554) - double initialization in generated Read() method - [THRIFT-2551](https://issues.apache.org/jira/browse/THRIFT-2551) - OutOfMemoryError "unable to create new native thread" kills serve thread - [THRIFT-2543](https://issues.apache.org/jira/browse/THRIFT-2543) - Generated enum type in haskell should be qualified - [THRIFT-2560](https://issues.apache.org/jira/browse/THRIFT-2560) - Thrift compiler generator tries to concat ints with strings using + - [THRIFT-2559](https://issues.apache.org/jira/browse/THRIFT-2559) - Centos 6.5 unable to "make" with Thrift 0.9.1 - [THRIFT-2526](https://issues.apache.org/jira/browse/THRIFT-2526) - Assignment operators and copy constructors in c++ don't copy the __isset struct - [THRIFT-2454](https://issues.apache.org/jira/browse/THRIFT-2454) - c_glib: There is no gethostbyname_r() in some OS. - [THRIFT-2451](https://issues.apache.org/jira/browse/THRIFT-2451) - Do not use pointers for optional fields with defaults. Do not write such fields if its value set to default. Also, do not use pointers for any optional fields mapped to go map or slice. generate Get accessors - [THRIFT-2450](https://issues.apache.org/jira/browse/THRIFT-2450) - include HowToContribute in the src repo - [THRIFT-2448](https://issues.apache.org/jira/browse/THRIFT-2448) - thrift/test/test.sh has incorrect Node.js test path - [THRIFT-2460](https://issues.apache.org/jira/browse/THRIFT-2460) - unopened socket fd must be less than zero. - [THRIFT-2459](https://issues.apache.org/jira/browse/THRIFT-2459) - --version should not exit 1 - [THRIFT-2468](https://issues.apache.org/jira/browse/THRIFT-2468) - Timestamp handling - [THRIFT-2467](https://issues.apache.org/jira/browse/THRIFT-2467) - Unable to build contrib/fb303 on OSX 10.9.2 - [THRIFT-2466](https://issues.apache.org/jira/browse/THRIFT-2466) - Improper error handling for SSL/TLS connections that don't complete a handshake - [THRIFT-2463](https://issues.apache.org/jira/browse/THRIFT-2463) - test/py/RunClientServer.py fails sometimes - [THRIFT-2458](https://issues.apache.org/jira/browse/THRIFT-2458) - Generated golang server code for "oneway" methods is incorrect - [THRIFT-2456](https://issues.apache.org/jira/browse/THRIFT-2456) - THttpClient fails when using async support outside Silverlight - [THRIFT-2524](https://issues.apache.org/jira/browse/THRIFT-2524) - Visual Studio project is missing TThreadedServer files - [THRIFT-2523](https://issues.apache.org/jira/browse/THRIFT-2523) - Visual Studio project is missing OverlappedSubmissionThread files - [THRIFT-2520](https://issues.apache.org/jira/browse/THRIFT-2520) - cpp:cob_style generates incorrect .tcc file - [THRIFT-2508](https://issues.apache.org/jira/browse/THRIFT-2508) - Uncompileable C# code due to language keywords in IDL - [THRIFT-2506](https://issues.apache.org/jira/browse/THRIFT-2506) - Update TProtocolException error codes to be used consistently throughout the library - [THRIFT-2505](https://issues.apache.org/jira/browse/THRIFT-2505) - go: struct should always be a pointer to avoid copying of potentially size-unbounded structs - [THRIFT-2515](https://issues.apache.org/jira/browse/THRIFT-2515) - TLS Method error during make - [THRIFT-2503](https://issues.apache.org/jira/browse/THRIFT-2503) - C++: Fix name collision when a struct has a member named "val" - [THRIFT-2477](https://issues.apache.org/jira/browse/THRIFT-2477) - thrift --help text with misplaced comma - [THRIFT-2492](https://issues.apache.org/jira/browse/THRIFT-2492) - test/cpp does not compile on mac - [THRIFT-2500](https://issues.apache.org/jira/browse/THRIFT-2500) - sending random data crashes thrift(golang) service - [THRIFT-2475](https://issues.apache.org/jira/browse/THRIFT-2475) - c_glib: buffered_transport_write function return always TRUE. - [THRIFT-2495](https://issues.apache.org/jira/browse/THRIFT-2495) - JavaScript/Node string constants lack proper escaping - [THRIFT-2491](https://issues.apache.org/jira/browse/THRIFT-2491) - unable to import generated ThriftTest service - [THRIFT-2490](https://issues.apache.org/jira/browse/THRIFT-2490) - c_glib: if fail to read a exception from server, client may be occurred double free - [THRIFT-2470](https://issues.apache.org/jira/browse/THRIFT-2470) - THttpHandler swallows exceptions from processor - [THRIFT-2533](https://issues.apache.org/jira/browse/THRIFT-2533) - Boost version in requirements should be updated - [THRIFT-2532](https://issues.apache.org/jira/browse/THRIFT-2532) - Java version in installation requirements should be updated - [THRIFT-2529](https://issues.apache.org/jira/browse/THRIFT-2529) - TBufferedTransport split Tcp data bug in nodeJs - [THRIFT-2537](https://issues.apache.org/jira/browse/THRIFT-2537) - Path for "go get" does not work (pull request 115) - [THRIFT-2443](https://issues.apache.org/jira/browse/THRIFT-2443) - Node fails cross lang tests - [THRIFT-2437](https://issues.apache.org/jira/browse/THRIFT-2437) - Author fields in Python setup.py must be strings not lists. - [THRIFT-2435](https://issues.apache.org/jira/browse/THRIFT-2435) - Java compiler doesn't like struct member names that are identical to an existing enum or struct type - [THRIFT-2434](https://issues.apache.org/jira/browse/THRIFT-2434) - Missing namespace import for php TMultiplexedProcessor implementation - [THRIFT-2432](https://issues.apache.org/jira/browse/THRIFT-2432) - Flaky parallel build - [THRIFT-2430](https://issues.apache.org/jira/browse/THRIFT-2430) - Crash during TThreadPoolServer shutdown - [THRIFT-667](https://issues.apache.org/jira/browse/THRIFT-667) - Period should not be allowed in identifier names - [THRIFT-1212](https://issues.apache.org/jira/browse/THRIFT-1212) - Members capital case conflict - [THRIFT-2584](https://issues.apache.org/jira/browse/THRIFT-2584) - Error handler not listened on javascript client - [THRIFT-2294](https://issues.apache.org/jira/browse/THRIFT-2294) - Incorrect Makefile generation - [THRIFT-2601](https://issues.apache.org/jira/browse/THRIFT-2601) - Fix vagrant to work again for builds again - [THRIFT-2092](https://issues.apache.org/jira/browse/THRIFT-2092) - TNonblocking server should release handler as soon as connection closes - [THRIFT-2557](https://issues.apache.org/jira/browse/THRIFT-2557) - CS0542 member names cannot be the same as their enclosing type - [THRIFT-2605](https://issues.apache.org/jira/browse/THRIFT-2605) - TSocket warning on gcc 4.8.3 - [THRIFT-2607](https://issues.apache.org/jira/browse/THRIFT-2607) - ThreadManager.cpp warning on clang++ 3.4 - [THRIFT-1998](https://issues.apache.org/jira/browse/THRIFT-1998) - TCompactProtocol.tcc) - one more warning on Visual 2010 - [THRIFT-2610](https://issues.apache.org/jira/browse/THRIFT-2610) - MSVC warning in TSocket.cpp - [THRIFT-2614](https://issues.apache.org/jira/browse/THRIFT-2614) - TNonblockingServer.cpp warnings on MSVC - [THRIFT-2608](https://issues.apache.org/jira/browse/THRIFT-2608) - TNonblockingServer.cpp warnings on clang 3.4 - [THRIFT-2606](https://issues.apache.org/jira/browse/THRIFT-2606) - ThreadManager.h warning in clang++ 3.4 - [THRIFT-2609](https://issues.apache.org/jira/browse/THRIFT-2609) - TFileTransport.h unused field warning (clang 3.4) - [THRIFT-2416](https://issues.apache.org/jira/browse/THRIFT-2416) - Cannot use TCompactProtocol with MSVC - [THRIFT-1803](https://issues.apache.org/jira/browse/THRIFT-1803) - Ruby Thrift 0.9.0 tries to encode UUID to UTF8 and crashes - [THRIFT-2385](https://issues.apache.org/jira/browse/THRIFT-2385) - Problem with gethostbyname2 during make check - [THRIFT-2262](https://issues.apache.org/jira/browse/THRIFT-2262) - thrift server 'MutateRow' operation gives no indication of success / failure - [THRIFT-2048](https://issues.apache.org/jira/browse/THRIFT-2048) - Prefer boolean context to nullptr_t conversion - [THRIFT-2528](https://issues.apache.org/jira/browse/THRIFT-2528) - Thrift Erlang Library: Multiple thrift applications in one bundle - [THRIFT-1999](https://issues.apache.org/jira/browse/THRIFT-1999) - warning on gcc 4.7 while compiling BoostMutex.cpp - [THRIFT-2104](https://issues.apache.org/jira/browse/THRIFT-2104) - Structs lose binary data when transferred from server to client in Java - [THRIFT-2184](https://issues.apache.org/jira/browse/THRIFT-2184) - undefined method rspec_verify for Thrift::MemoryBufferTransport - [THRIFT-2351](https://issues.apache.org/jira/browse/THRIFT-2351) - PHP TCompactProtocol has fails to decode messages - [THRIFT-2016](https://issues.apache.org/jira/browse/THRIFT-2016) - Resource Leak in thrift struct under compiler/cpp/src/parse/t_function.h - [THRIFT-2273](https://issues.apache.org/jira/browse/THRIFT-2273) - Please delete old releases from mirroring system - [THRIFT-2270](https://issues.apache.org/jira/browse/THRIFT-2270) - Faulty library version numbering at build or documentation - [THRIFT-2203](https://issues.apache.org/jira/browse/THRIFT-2203) - Tests keeping failing on Jenkins and Travis CI - [THRIFT-2399](https://issues.apache.org/jira/browse/THRIFT-2399) - thrift.el: recognize "//"-style comments in emacs thrift-mode - [THRIFT-2582](https://issues.apache.org/jira/browse/THRIFT-2582) - "FileTransport error" exception is raised when trying to use Java's TFileTransport - [THRIFT-1682](https://issues.apache.org/jira/browse/THRIFT-1682) - Multiple thread calling a Service function unsafely causes message corruption and terminates with Broken Pipe - [THRIFT-2357](https://issues.apache.org/jira/browse/THRIFT-2357) - recurse option has no effect when generating php - [THRIFT-2248](https://issues.apache.org/jira/browse/THRIFT-2248) - Go generator doesn't deal well with map keys of type binary - [THRIFT-2426](https://issues.apache.org/jira/browse/THRIFT-2426) - clarify IP rights and contributions from fbthrift - [THRIFT-2041](https://issues.apache.org/jira/browse/THRIFT-2041) - TNonblocking server compilation on windows (ARITHMETIC_RIGHT_SHIFT) - [THRIFT-2400](https://issues.apache.org/jira/browse/THRIFT-2400) - thrift.el: recognize "//"-style comments in emacs thrift-mode - [THRIFT-1717](https://issues.apache.org/jira/browse/THRIFT-1717) - Fix deb build in jenkins - [THRIFT-2266](https://issues.apache.org/jira/browse/THRIFT-2266) - ThreadManager.h:24:10: fatal error: 'tr1/functional' file not found on Mac 10.9 (Mavericks) - [THRIFT-1300](https://issues.apache.org/jira/browse/THRIFT-1300) - Test failures with parallel builds (make -j) - [THRIFT-2487](https://issues.apache.org/jira/browse/THRIFT-2487) - Tutorial requires two IDL files but only one is linked from the Thrift web site - [THRIFT-2329](https://issues.apache.org/jira/browse/THRIFT-2329) - missing release tags within git - [THRIFT-2306](https://issues.apache.org/jira/browse/THRIFT-2306) - concurent client calls with nodejs - [THRIFT-2222](https://issues.apache.org/jira/browse/THRIFT-2222) - ruby gem cannot be compiled on OS X mavericks - [THRIFT-2381](https://issues.apache.org/jira/browse/THRIFT-2381) - code which generated by thrift2/hbase.thrift compile error - [THRIFT-2390](https://issues.apache.org/jira/browse/THRIFT-2390) - no close event when connection lost - [THRIFT-2146](https://issues.apache.org/jira/browse/THRIFT-2146) - Unable to pass multiple "--gen" options to the thrift compiler - [THRIFT-2438](https://issues.apache.org/jira/browse/THRIFT-2438) - Unexpected readFieldEnd call causes JSON Parsing errors - [THRIFT-2498](https://issues.apache.org/jira/browse/THRIFT-2498) - Error message "Invalid method name" while trying to call HBase Thrift API - [THRIFT-841](https://issues.apache.org/jira/browse/THRIFT-841) - Build cruft - [THRIFT-2570](https://issues.apache.org/jira/browse/THRIFT-2570) - Wrong URL given in http://thrift.apache.org/developers - [THRIFT-2604](https://issues.apache.org/jira/browse/THRIFT-2604) - Fix debian packaging - [THRIFT-2618](https://issues.apache.org/jira/browse/THRIFT-2618) - Unignore /aclocal files required for build - [THRIFT-2562](https://issues.apache.org/jira/browse/THRIFT-2562) - ./configure create MakeFile in lib/d with errors - [THRIFT-2593](https://issues.apache.org/jira/browse/THRIFT-2593) - Unable to build thrift on ubuntu-12.04 (Precise) - [THRIFT-2461](https://issues.apache.org/jira/browse/THRIFT-2461) - Can't install thrift-0.8.0 on OS X 10.9.2 - [THRIFT-2602](https://issues.apache.org/jira/browse/THRIFT-2602) - Fix missing dist files - [THRIFT-2620](https://issues.apache.org/jira/browse/THRIFT-2620) - Fix python packaging - [THRIFT-2545](https://issues.apache.org/jira/browse/THRIFT-2545) - Test CPP fails to build (possibly typo) ## Documentation - [THRIFT-2155](https://issues.apache.org/jira/browse/THRIFT-2155) - Adding one liner guide to rename the version.h.in and rename thrifty.cc.h - [THRIFT-1991](https://issues.apache.org/jira/browse/THRIFT-1991) - Add exceptions to examples - [THRIFT-2334](https://issues.apache.org/jira/browse/THRIFT-2334) - add a tutorial for node JS - [THRIFT-2392](https://issues.apache.org/jira/browse/THRIFT-2392) - Actionscript tutorial - [THRIFT-2383](https://issues.apache.org/jira/browse/THRIFT-2383) - contrib: sample for connecting Thrift with Rebus - [THRIFT-2382](https://issues.apache.org/jira/browse/THRIFT-2382) - contrib: sample for connecting Thrift with STOMP ### Improvement - [THRIFT-1457](https://issues.apache.org/jira/browse/THRIFT-1457) - Capacity of TframedTransport write buffer is never reset - [THRIFT-1135](https://issues.apache.org/jira/browse/THRIFT-1135) - Node.js tutorial - [THRIFT-1371](https://issues.apache.org/jira/browse/THRIFT-1371) - Socket timeouts (SO_RCVTIMEO and SO_SNDTIMEO) not supported on Solaris - [THRIFT-2142](https://issues.apache.org/jira/browse/THRIFT-2142) - Minor tweaks to thrift.el for better emacs package compatibility - [THRIFT-2268](https://issues.apache.org/jira/browse/THRIFT-2268) - Modify TSaslTransport to ignore TCP health checks from loadbalancers - [THRIFT-2264](https://issues.apache.org/jira/browse/THRIFT-2264) - GitHub page incorrectly states that Thrift is still incubating - [THRIFT-2263](https://issues.apache.org/jira/browse/THRIFT-2263) - Always generate good hashCode for Java - [THRIFT-2233](https://issues.apache.org/jira/browse/THRIFT-2233) - Java compiler should defensively copy its binary inputs - [THRIFT-2239](https://issues.apache.org/jira/browse/THRIFT-2239) - Address FindBugs errors - [THRIFT-2249](https://issues.apache.org/jira/browse/THRIFT-2249) - Add SMP Build option to thrift.spec (and three config defines) - [THRIFT-2254](https://issues.apache.org/jira/browse/THRIFT-2254) - Exceptions generated by Go compiler should implement error interface - [THRIFT-2260](https://issues.apache.org/jira/browse/THRIFT-2260) - Thrift imposes unneeded dependency on commons-lang3 - [THRIFT-2258](https://issues.apache.org/jira/browse/THRIFT-2258) - Add TLS v1.1/1.2 support to TSSLSocket.cpp - [THRIFT-2205](https://issues.apache.org/jira/browse/THRIFT-2205) - Node.js Test Server to support test.js JavaScript Browser test and sundry fixes - [THRIFT-2204](https://issues.apache.org/jira/browse/THRIFT-2204) - SSL client for the cocoa client - [THRIFT-2172](https://issues.apache.org/jira/browse/THRIFT-2172) - Java compiler allocates optionals array for every struct with an optional field - [THRIFT-2185](https://issues.apache.org/jira/browse/THRIFT-2185) - use cabal instead of runhaskell in haskell library - [THRIFT-1926](https://issues.apache.org/jira/browse/THRIFT-1926) - PHP Constant Generation Refactoring - [THRIFT-2029](https://issues.apache.org/jira/browse/THRIFT-2029) - Port C++ tests to Windows - [THRIFT-2054](https://issues.apache.org/jira/browse/THRIFT-2054) - TSimpleFileTransport) - Java Lib has no straight forward TTransport based file transport - [THRIFT-2040](https://issues.apache.org/jira/browse/THRIFT-2040) - "uninitialized variable" warnings on MSVC/windows - [THRIFT-2034](https://issues.apache.org/jira/browse/THRIFT-2034) - Give developers' C++ code direct access to socket FDs on server side - [THRIFT-2095](https://issues.apache.org/jira/browse/THRIFT-2095) - Use print function for Python 3 compatibility - [THRIFT-1868](https://issues.apache.org/jira/browse/THRIFT-1868) - Make the TPC backlog configurable in the Java servers - [THRIFT-1813](https://issues.apache.org/jira/browse/THRIFT-1813) - Add @Generated annotation to generated classes - [THRIFT-1815](https://issues.apache.org/jira/browse/THRIFT-1815) - Code generators line buffer output - [THRIFT-2305](https://issues.apache.org/jira/browse/THRIFT-2305) - TFramedTransport empty constructor should probably be private - [THRIFT-2304](https://issues.apache.org/jira/browse/THRIFT-2304) - Move client assignments from construtor in method - [THRIFT-2309](https://issues.apache.org/jira/browse/THRIFT-2309) - Ruby (gem) & PHP RPM subpackages - [THRIFT-2318](https://issues.apache.org/jira/browse/THRIFT-2318) - perl: dependency Class::Accessor not checked - [THRIFT-2317](https://issues.apache.org/jira/browse/THRIFT-2317) - exclude tutorial from build - [THRIFT-2320](https://issues.apache.org/jira/browse/THRIFT-2320) - Program level doctext does not get attached by parser - [THRIFT-2349](https://issues.apache.org/jira/browse/THRIFT-2349) - Golang) - improve tutorial - [THRIFT-2348](https://issues.apache.org/jira/browse/THRIFT-2348) - PHP Generator: add array typehint to functions - [THRIFT-2344](https://issues.apache.org/jira/browse/THRIFT-2344) - configure.ac: compiler-only option - [THRIFT-2343](https://issues.apache.org/jira/browse/THRIFT-2343) - Golang) - Return a single error for all exceptions instead of multiple return values - [THRIFT-2341](https://issues.apache.org/jira/browse/THRIFT-2341) - Enable generation of Delphi XMLDoc comments (a.k.a. "Help Insight") - [THRIFT-2355](https://issues.apache.org/jira/browse/THRIFT-2355) - Add SSL and Web Socket Support to Node and JavaScript - [THRIFT-2350](https://issues.apache.org/jira/browse/THRIFT-2350) - Add async calls to normal JavaScript - [THRIFT-2330](https://issues.apache.org/jira/browse/THRIFT-2330) - Generate PHPDoc comments - [THRIFT-2332](https://issues.apache.org/jira/browse/THRIFT-2332) - RPMBUILD: run bootstrap (if needed) - [THRIFT-2391](https://issues.apache.org/jira/browse/THRIFT-2391) - simple socket transport for actionscript 3.0 - [THRIFT-2376](https://issues.apache.org/jira/browse/THRIFT-2376) - nodejs: allow Promise style calls for client and server - [THRIFT-2369](https://issues.apache.org/jira/browse/THRIFT-2369) - Add ssl support for nodejs implementation - [THRIFT-2401](https://issues.apache.org/jira/browse/THRIFT-2401) - Haskell tutorial compiles - [THRIFT-2417](https://issues.apache.org/jira/browse/THRIFT-2417) - C# Union classes are not partial - [THRIFT-2415](https://issues.apache.org/jira/browse/THRIFT-2415) - Named pipes server performance & message mode - [THRIFT-2404](https://issues.apache.org/jira/browse/THRIFT-2404) - emit warning on (typically inefficient) list - [THRIFT-2398](https://issues.apache.org/jira/browse/THRIFT-2398) - Improve Node Server Library - [THRIFT-2397](https://issues.apache.org/jira/browse/THRIFT-2397) - Add CORS and CSP support for JavaScript and Node.js libraries - [THRIFT-2407](https://issues.apache.org/jira/browse/THRIFT-2407) - use markdown (rename README => README.md) - [THRIFT-2300](https://issues.apache.org/jira/browse/THRIFT-2300) - D configure info output should follow same format as other languages - [THRIFT-2579](https://issues.apache.org/jira/browse/THRIFT-2579) - Windows CE support - [THRIFT-2574](https://issues.apache.org/jira/browse/THRIFT-2574) - Compiler option to generate namespace directories for Ruby - [THRIFT-2571](https://issues.apache.org/jira/browse/THRIFT-2571) - Simplify cross compilation using CMake - [THRIFT-2569](https://issues.apache.org/jira/browse/THRIFT-2569) - Introduce file to specify third party library locations on Windows - [THRIFT-2568](https://issues.apache.org/jira/browse/THRIFT-2568) - Implement own certificate handler - [THRIFT-2552](https://issues.apache.org/jira/browse/THRIFT-2552) - eliminate warning from configure.ac - [THRIFT-2549](https://issues.apache.org/jira/browse/THRIFT-2549) - Generate json tag for struct members. use go.tag annotation to override the default generated tag. - [THRIFT-2544](https://issues.apache.org/jira/browse/THRIFT-2544) - Add support for socket transport for c# library when using Windows Phone projects - [THRIFT-2453](https://issues.apache.org/jira/browse/THRIFT-2453) - haskell tutorial: fix up division by 0 example - [THRIFT-2449](https://issues.apache.org/jira/browse/THRIFT-2449) - Enhance typedef structure to distinguish between forwards and real typedefs - [THRIFT-2446](https://issues.apache.org/jira/browse/THRIFT-2446) - There is no way to handle server stream errors - [THRIFT-2455](https://issues.apache.org/jira/browse/THRIFT-2455) - Allow client certificates to be used with THttpClient - [THRIFT-2511](https://issues.apache.org/jira/browse/THRIFT-2511) - Node.js needs the compact protocol - [THRIFT-2493](https://issues.apache.org/jira/browse/THRIFT-2493) - Node.js lib needs HTTP client - [THRIFT-2502](https://issues.apache.org/jira/browse/THRIFT-2502) - Optimize go implementations of binary and compact protocols for speed - [THRIFT-2494](https://issues.apache.org/jira/browse/THRIFT-2494) - Add enum toString helper function in c_glib - [THRIFT-2471](https://issues.apache.org/jira/browse/THRIFT-2471) - Make cpp.ref annotation language agnostic - [THRIFT-2497](https://issues.apache.org/jira/browse/THRIFT-2497) - server and client for test/go, also several fixes and improvements - [THRIFT-2535](https://issues.apache.org/jira/browse/THRIFT-2535) - TJSONProtocol when serialized yields TField ids rather than names - [THRIFT-2220](https://issues.apache.org/jira/browse/THRIFT-2220) - Add a new struct structv? - [THRIFT-1352](https://issues.apache.org/jira/browse/THRIFT-1352) - Thrift server - [THRIFT-989](https://issues.apache.org/jira/browse/THRIFT-989) - Push boost m4 macros upstream - [THRIFT-1349](https://issues.apache.org/jira/browse/THRIFT-1349) - Remove unnecessary print outs - [THRIFT-2496](https://issues.apache.org/jira/browse/THRIFT-2496) - server and client for test/go, also several fixes and improvements - [THRIFT-1114](https://issues.apache.org/jira/browse/THRIFT-1114) - Maven publish shouldn't require passwords hardcoded in settings.xml - [THRIFT-2043](https://issues.apache.org/jira/browse/THRIFT-2043) - visual 2010 warnings) - unreachable code - [THRIFT-1683](https://issues.apache.org/jira/browse/THRIFT-1683) - Implement alternatives to Javascript Client side Transport protocol, just as NPAPI and WebSocket. - [THRIFT-1746](https://issues.apache.org/jira/browse/THRIFT-1746) - provide a SPDX file - [THRIFT-1772](https://issues.apache.org/jira/browse/THRIFT-1772) - Serialization does not check types of embedded structures. - [THRIFT-2387](https://issues.apache.org/jira/browse/THRIFT-2387) - nodejs: external imports should be centralized in index.js - [THRIFT-2037](https://issues.apache.org/jira/browse/THRIFT-2037) - More general macro THRIFT_UNUSED_VARIABLE ### New Feature - [THRIFT-1012](https://issues.apache.org/jira/browse/THRIFT-1012) - Transport for DataInput DataOutput interface - [THRIFT-2256](https://issues.apache.org/jira/browse/THRIFT-2256) - Using c++11/c++0x std library replace boost library - [THRIFT-2250](https://issues.apache.org/jira/browse/THRIFT-2250) - JSON and MemoryBuffer for JavaME - [THRIFT-2114](https://issues.apache.org/jira/browse/THRIFT-2114) - Python Service Remote SSL Option - [THRIFT-1719](https://issues.apache.org/jira/browse/THRIFT-1719) - SASL client support for Python - [THRIFT-1894](https://issues.apache.org/jira/browse/THRIFT-1894) - Thrift multi-threaded async Java Server using Java 7 AsynchronousChannelGroup - [THRIFT-1893](https://issues.apache.org/jira/browse/THRIFT-1893) - HTTP/JSON server/client for node js - [THRIFT-2347](https://issues.apache.org/jira/browse/THRIFT-2347) - C# TLS Transport based on THRIFT-181 - [THRIFT-2377](https://issues.apache.org/jira/browse/THRIFT-2377) - Allow addition of custom HTTP Headers to an HTTP Transport - [THRIFT-2408](https://issues.apache.org/jira/browse/THRIFT-2408) - Named Pipe Transport Option for C# - [THRIFT-2572](https://issues.apache.org/jira/browse/THRIFT-2572) - Add string/collection length limit checks (from C++) to java protocol readers - [THRIFT-2469](https://issues.apache.org/jira/browse/THRIFT-2469) - "java:fullcamel" option to automatically camel-case underscored attribute names - [THRIFT-795](https://issues.apache.org/jira/browse/THRIFT-795) - Importing service functions (simulation multiple inheritance) - [THRIFT-2164](https://issues.apache.org/jira/browse/THRIFT-2164) - Add a Get/Post Http Server to Node along with examples - [THRIFT-2255](https://issues.apache.org/jira/browse/THRIFT-2255) - add Parent Class for generated Struct class ### Question - [THRIFT-2539](https://issues.apache.org/jira/browse/THRIFT-2539) - Tsocket.cpp addrinfo ai_flags = AI_ADDRCONFIG - [THRIFT-2440](https://issues.apache.org/jira/browse/THRIFT-2440) - how to connect as3 to java by thrift , - [THRIFT-2379](https://issues.apache.org/jira/browse/THRIFT-2379) - Memmory leaking while using multithreading in C++ server. - [THRIFT-2277](https://issues.apache.org/jira/browse/THRIFT-2277) - Thrift: installing fb303 error - [THRIFT-2567](https://issues.apache.org/jira/browse/THRIFT-2567) - Csharp slow ? - [THRIFT-2573](https://issues.apache.org/jira/browse/THRIFT-2573) - thrift 0.9.2 release ### Sub-task - [THRIFT-981](https://issues.apache.org/jira/browse/THRIFT-981) - cocoa: add version Info to the library - [THRIFT-2132](https://issues.apache.org/jira/browse/THRIFT-2132) - Go: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-2299](https://issues.apache.org/jira/browse/THRIFT-2299) - TJsonProtocol implementation for Ruby does not allow for both possible slash (solidus) encodings - [THRIFT-2298](https://issues.apache.org/jira/browse/THRIFT-2298) - TJsonProtocol implementation for C# does not allow for both possible slash (solidus) encodings - [THRIFT-2297](https://issues.apache.org/jira/browse/THRIFT-2297) - TJsonProtocol implementation for Delphi does not allow for both possible slash (solidus) encodings - [THRIFT-2271](https://issues.apache.org/jira/browse/THRIFT-2271) - JavaScript: Support for Multiplexing Services - [THRIFT-2251](https://issues.apache.org/jira/browse/THRIFT-2251) - go test for compact protocol is not running - [THRIFT-2195](https://issues.apache.org/jira/browse/THRIFT-2195) - Delphi: Add event handlers for server and processing events - [THRIFT-2176](https://issues.apache.org/jira/browse/THRIFT-2176) - TSimpleJSONProtocol.ReadFieldBegin() does not return field type and ID - [THRIFT-2175](https://issues.apache.org/jira/browse/THRIFT-2175) - Wrong field type set for binary - [THRIFT-2174](https://issues.apache.org/jira/browse/THRIFT-2174) - Deserializing JSON fails in specific cases - [THRIFT-2053](https://issues.apache.org/jira/browse/THRIFT-2053) - NodeJS: Support for Multiplexing Services - [THRIFT-1914](https://issues.apache.org/jira/browse/THRIFT-1914) - Python: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-1810](https://issues.apache.org/jira/browse/THRIFT-1810) - add ruby to test/test.sh - [THRIFT-2310](https://issues.apache.org/jira/browse/THRIFT-2310) - PHP: Client-side support for Multiplexing Services - [THRIFT-2346](https://issues.apache.org/jira/browse/THRIFT-2346) - C#: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-2345](https://issues.apache.org/jira/browse/THRIFT-2345) - Delphi: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol - [THRIFT-2338](https://issues.apache.org/jira/browse/THRIFT-2338) - First doctext wrongly interpreted as program doctext in some cases - [THRIFT-2325](https://issues.apache.org/jira/browse/THRIFT-2325) - SSL test certificates - [THRIFT-2358](https://issues.apache.org/jira/browse/THRIFT-2358) - C++: add compact protocol to cross language test suite - [THRIFT-2425](https://issues.apache.org/jira/browse/THRIFT-2425) - PHP: Server-side support for Multiplexing Services - [THRIFT-2421](https://issues.apache.org/jira/browse/THRIFT-2421) - Tree/Recursive struct support in thrift - [THRIFT-2290](https://issues.apache.org/jira/browse/THRIFT-2290) - Update Go tutorial to align with THRIFT-2232 - [THRIFT-2558](https://issues.apache.org/jira/browse/THRIFT-2558) - CSharp compiler generator tries to concat ints with strings using + - [THRIFT-2507](https://issues.apache.org/jira/browse/THRIFT-2507) - Additional LUA TProtocolException error code needed? - [THRIFT-2499](https://issues.apache.org/jira/browse/THRIFT-2499) - Compiler: allow annotations without "= value" - [THRIFT-2534](https://issues.apache.org/jira/browse/THRIFT-2534) - Cross language test results should recorded to a status.md or status.html file automatically - [THRIFT-66](https://issues.apache.org/jira/browse/THRIFT-66) - Java: Allow multiplexing multiple services over a single TCP connection - [THRIFT-1681](https://issues.apache.org/jira/browse/THRIFT-1681) - Add Lua Support - [THRIFT-1727](https://issues.apache.org/jira/browse/THRIFT-1727) - Ruby-1.9: data loss: "binary" fields are re-encoded - [THRIFT-1726](https://issues.apache.org/jira/browse/THRIFT-1726) - Ruby-1.9: "binary" fields are represented by string whose encoding is "UTF-8" - [THRIFT-988](https://issues.apache.org/jira/browse/THRIFT-988) - perl: add version Info to the library via configure - [THRIFT-334](https://issues.apache.org/jira/browse/THRIFT-334) - Compact Protocol for PHP - [THRIFT-2444](https://issues.apache.org/jira/browse/THRIFT-2444) - pull request 88: thrift: clean up enum value assignment ### Task - [THRIFT-2223](https://issues.apache.org/jira/browse/THRIFT-2223) - Spam links on wiki - [THRIFT-2566](https://issues.apache.org/jira/browse/THRIFT-2566) - Please create a DOAP file for your TLP - [THRIFT-2237](https://issues.apache.org/jira/browse/THRIFT-2237) - Update archive to contain all versions - [THRIFT-962](https://issues.apache.org/jira/browse/THRIFT-962) - Tutorial page on our website is really unhelpful ### Test - [THRIFT-2327](https://issues.apache.org/jira/browse/THRIFT-2327) - nodejs: nodejs test suite should be bundled with the library - [THRIFT-2445](https://issues.apache.org/jira/browse/THRIFT-2445) - THRIFT-2384 (code generation for go maps with binary keys) should be tested - [THRIFT-2501](https://issues.apache.org/jira/browse/THRIFT-2501) - C# The test parameters from the TestServer and TestClient are different from the http://thrift.apache.org/test/ ### Wish - [THRIFT-2190](https://issues.apache.org/jira/browse/THRIFT-2190) - Add the JavaScript thrift.js lib to the Bower registry - [THRIFT-2076](https://issues.apache.org/jira/browse/THRIFT-2076) - boost::optional instead of __isset ## 0.9.1 ### Bug - [THRIFT-1440](https://issues.apache.org/jira/browse/THRIFT-1440) - debian packaging: minor-ish policy problems - [THRIFT-1402](https://issues.apache.org/jira/browse/THRIFT-1402) - Generated Y_types.js does not require() X_types.js when an include in the IDL file was used - [THRIFT-1551](https://issues.apache.org/jira/browse/THRIFT-1551) - 2 thrift file define only struct (no service), one include another, the gen nodejs file didn't have "requires" at the top - [THRIFT-1264](https://issues.apache.org/jira/browse/THRIFT-1264) - TSocketClient is queried by run loop after deallocation in Cocoa - [THRIFT-1600](https://issues.apache.org/jira/browse/THRIFT-1600) - Thrift Go Compiler and Library out of date with Go 1 Release. - [THRIFT-1603](https://issues.apache.org/jira/browse/THRIFT-1603) - Thrift IDL allows for multiple exceptions, args or struct member names to be the same - [THRIFT-1062](https://issues.apache.org/jira/browse/THRIFT-1062) - Problems with python tutorials - [THRIFT-864](https://issues.apache.org/jira/browse/THRIFT-864) - default value fails if identifier is a struct - [THRIFT-930](https://issues.apache.org/jira/browse/THRIFT-930) - Ruby and Haskell bindings don't properly support DESTDIR (makes packaging painful) - [THRIFT-820](https://issues.apache.org/jira/browse/THRIFT-820) - The readLength attribute of TBinaryProtocol is used as an instance variable and is decremented on each call of checkReadLength - [THRIFT-1640](https://issues.apache.org/jira/browse/THRIFT-1640) - None of the tutorials linked on the website contain content - [THRIFT-1637](https://issues.apache.org/jira/browse/THRIFT-1637) - NPM registry does not include version 0.8 - [THRIFT-1648](https://issues.apache.org/jira/browse/THRIFT-1648) - NodeJS clients always receive 0 for 'double' values. - [THRIFT-1660](https://issues.apache.org/jira/browse/THRIFT-1660) - Python Thrift library can be installed with pip but not easy_install - [THRIFT-1657](https://issues.apache.org/jira/browse/THRIFT-1657) - Chrome browser sending OPTIONS method before POST in xmlHttpRequest - [THRIFT-2118](https://issues.apache.org/jira/browse/THRIFT-2118) - Certificate error handling still incorrect - [THRIFT-2137](https://issues.apache.org/jira/browse/THRIFT-2137) - Ruby test lib fails jenkins build #864 - [THRIFT-2136](https://issues.apache.org/jira/browse/THRIFT-2136) - Vagrant build not compiling java, ruby, php, go libs due to missing dependencies - [THRIFT-2135](https://issues.apache.org/jira/browse/THRIFT-2135) - GO lib leaves behind test files that are auto generated - [THRIFT-2134](https://issues.apache.org/jira/browse/THRIFT-2134) - mingw-cross-compile script failing with strip errors - [THRIFT-2133](https://issues.apache.org/jira/browse/THRIFT-2133) - java TestTBinaryProtocol.java test failing - [THRIFT-2126](https://issues.apache.org/jira/browse/THRIFT-2126) - lib/cpp/src/thrift/concurrency/STD* files missing from DIST - [THRIFT-2125](https://issues.apache.org/jira/browse/THRIFT-2125) - debian missing from DIST - [THRIFT-2124](https://issues.apache.org/jira/browse/THRIFT-2124) - .o, .so, .la, .deps, .libs, gen-* files left tutorials, test and lib/cpp when making DIST - [THRIFT-2123](https://issues.apache.org/jira/browse/THRIFT-2123) - GO lib missing files in DIST build - [THRIFT-2121](https://issues.apache.org/jira/browse/THRIFT-2121) - Compilation bug for Node.js - [THRIFT-2129](https://issues.apache.org/jira/browse/THRIFT-2129) - php ext missing from dist - [THRIFT-2128](https://issues.apache.org/jira/browse/THRIFT-2128) - lib GO tests fail with funct ends without a return statement - [THRIFT-2286](https://issues.apache.org/jira/browse/THRIFT-2286) - Failed to compile Thrift0.9.1 with boost1.55 by VS2010 if select Debug-mt&x64 mode. - [THRIFT-1973](https://issues.apache.org/jira/browse/THRIFT-1973) - TCompactProtocol in C# lib does not serialize and deserialize negative int32 and int64 number correctly - [THRIFT-1992](https://issues.apache.org/jira/browse/THRIFT-1992) - casts in TCompactProtocol.tcc causing "dereferencing type-punned pointer will break strict-aliasing rules" warnings from gcc - [THRIFT-1930](https://issues.apache.org/jira/browse/THRIFT-1930) - C# generates unsigned byte for Thrift "byte" type - [THRIFT-1929](https://issues.apache.org/jira/browse/THRIFT-1929) - Update website to use Mirrors for downloads - [THRIFT-1928](https://issues.apache.org/jira/browse/THRIFT-1928) - Race may still exist in TFileTransport::flush() - [THRIFT-1934](https://issues.apache.org/jira/browse/THRIFT-1934) - Tabs in Example section on main page are not working - [THRIFT-1933](https://issues.apache.org/jira/browse/THRIFT-1933) - Delphi generator crashes when a typedef references another typedef from an included file - [THRIFT-1942](https://issues.apache.org/jira/browse/THRIFT-1942) - Binary accelerated cpp extension does not use Thrift namespaces for Exceptions - [THRIFT-1959](https://issues.apache.org/jira/browse/THRIFT-1959) - C#: Add Union TMemoryBuffer support - [THRIFT-1958](https://issues.apache.org/jira/browse/THRIFT-1958) - C#: Use static Object.Equals instead of .Equals() calls in equals - [THRIFT-1957](https://issues.apache.org/jira/browse/THRIFT-1957) - NodeJS TFramedTransport and TBufferedTransport read bytes as unsigned - [THRIFT-1955](https://issues.apache.org/jira/browse/THRIFT-1955) - Union Type writer generated in C# does not WriteStructBegin - [THRIFT-1952](https://issues.apache.org/jira/browse/THRIFT-1952) - Travis CI - [THRIFT-1949](https://issues.apache.org/jira/browse/THRIFT-1949) - WP7 build broken - [THRIFT-1943](https://issues.apache.org/jira/browse/THRIFT-1943) - docstrings for enum values are ignored - [THRIFT-2070](https://issues.apache.org/jira/browse/THRIFT-2070) - Improper `HexChar' and 'HexVal' implementation in TJSONProtocol.cs - [THRIFT-2017](https://issues.apache.org/jira/browse/THRIFT-2017) - Resource Leak in thrift struct under compiler/cpp/src/parse/t_program.h - [THRIFT-2032](https://issues.apache.org/jira/browse/THRIFT-2032) - C# client leaks sockets/handles - [THRIFT-1996](https://issues.apache.org/jira/browse/THRIFT-1996) - JavaME Constants generation is broken / inconsistent with regular Java generation - [THRIFT-2002](https://issues.apache.org/jira/browse/THRIFT-2002) - Haskell: Test use Data.Maybe instead of Maybe - [THRIFT-2051](https://issues.apache.org/jira/browse/THRIFT-2051) - Vagrant fails to build erlang - [THRIFT-2050](https://issues.apache.org/jira/browse/THRIFT-2050) - Vagrant C# lib compile fails with TException missing - [THRIFT-1978](https://issues.apache.org/jira/browse/THRIFT-1978) - Ruby: Thrift should allow for the SSL verify mode to be set - [THRIFT-1984](https://issues.apache.org/jira/browse/THRIFT-1984) - namespace collision in python bindings - [THRIFT-1988](https://issues.apache.org/jira/browse/THRIFT-1988) - When trying to build a debian package it fails as the file NEWS doesn't exist - [THRIFT-1975](https://issues.apache.org/jira/browse/THRIFT-1975) - TBinaryProtocol CheckLength can't be used for a client - [THRIFT-1995](https://issues.apache.org/jira/browse/THRIFT-1995) - '.' allowed at end of identifier generates non-compilable code - [THRIFT-2112](https://issues.apache.org/jira/browse/THRIFT-2112) - Error in Go generator when using typedefs in map keys - [THRIFT-2088](https://issues.apache.org/jira/browse/THRIFT-2088) - Typos in Thrift compiler help text - [THRIFT-2080](https://issues.apache.org/jira/browse/THRIFT-2080) - C# multiplex processor does not catch IOException - [THRIFT-2082](https://issues.apache.org/jira/browse/THRIFT-2082) - Executing "gmake clean" is broken - [THRIFT-2102](https://issues.apache.org/jira/browse/THRIFT-2102) - constants are not referencing to correct type when included from another thrift file - [THRIFT-2100](https://issues.apache.org/jira/browse/THRIFT-2100) - typedefs are not correctly referenced when including from other thrift files - [THRIFT-2066](https://issues.apache.org/jira/browse/THRIFT-2066) - 'make install' does not install two headers required for C++ bindings - [THRIFT-2065](https://issues.apache.org/jira/browse/THRIFT-2065) - Not valid constants filename in Java - [THRIFT-2047](https://issues.apache.org/jira/browse/THRIFT-2047) - Thrift.Protocol.TCompactProtocol, intToZigZag data lost (TCompactProtocol.cs) - [THRIFT-2036](https://issues.apache.org/jira/browse/THRIFT-2036) - Thrift gem warns about class variable access from top level - [THRIFT-2057](https://issues.apache.org/jira/browse/THRIFT-2057) - Vagrant fails on php tests - [THRIFT-2105](https://issues.apache.org/jira/browse/THRIFT-2105) - Generated code for default values of collections ignores t_field::T_REQUIRED - [THRIFT-2091](https://issues.apache.org/jira/browse/THRIFT-2091) - Unnecessary 'friend' declaration causes warning in TWinsockSingleton - [THRIFT-2090](https://issues.apache.org/jira/browse/THRIFT-2090) - Go generator, fix including of other thrift files - [THRIFT-2106](https://issues.apache.org/jira/browse/THRIFT-2106) - Fix support for namespaces in GO generator - [THRIFT-1783](https://issues.apache.org/jira/browse/THRIFT-1783) - C# doesn't handle required fields correctly - [THRIFT-1782](https://issues.apache.org/jira/browse/THRIFT-1782) - async only defined in silverlight - [THRIFT-1779](https://issues.apache.org/jira/browse/THRIFT-1779) - Missing process_XXXX method in generated TProcessor implementation for all 'oneway' service functions - [THRIFT-1692](https://issues.apache.org/jira/browse/THRIFT-1692) - SO_REUSEADDR allows for socket hijacking on Windows - [THRIFT-1720](https://issues.apache.org/jira/browse/THRIFT-1720) - JRuby times out on successful connection - [THRIFT-1713](https://issues.apache.org/jira/browse/THRIFT-1713) - Named and Anonymous Pipe transport (Delphi) - [THRIFT-1699](https://issues.apache.org/jira/browse/THRIFT-1699) - Native Union#read has extra read_field_end call - [THRIFT-1749](https://issues.apache.org/jira/browse/THRIFT-1749) - Python TSSLSocket error handling obscures actual error - [THRIFT-1748](https://issues.apache.org/jira/browse/THRIFT-1748) - Guard and RWGuard macros defined in global namespace - [THRIFT-1734](https://issues.apache.org/jira/browse/THRIFT-1734) - Front webpage is still advertising v0.8 as current release - [THRIFT-1729](https://issues.apache.org/jira/browse/THRIFT-1729) - C glib refactor left empty folders in svn - [THRIFT-1767](https://issues.apache.org/jira/browse/THRIFT-1767) - unions can't have required fields (Delphi) - [THRIFT-1765](https://issues.apache.org/jira/browse/THRIFT-1765) - Incorrect error message printed for null or negative keys - [THRIFT-1778](https://issues.apache.org/jira/browse/THRIFT-1778) - Configure requires manual intervention due to tar failure - [THRIFT-1777](https://issues.apache.org/jira/browse/THRIFT-1777) - TPipeServer is UNSTOPPABLE - [THRIFT-1753](https://issues.apache.org/jira/browse/THRIFT-1753) - Multiple C++ Windows, OSX, and iOS portability issues - [THRIFT-1756](https://issues.apache.org/jira/browse/THRIFT-1756) - 'make -j 8' fails with "unterminated #ifdef" error - [THRIFT-1773](https://issues.apache.org/jira/browse/THRIFT-1773) - Python library should run on python 2.4 - [THRIFT-1769](https://issues.apache.org/jira/browse/THRIFT-1769) - unions can't have required fields (C++) - [THRIFT-1768](https://issues.apache.org/jira/browse/THRIFT-1768) - unions can't have required fields (Compiler) - [THRIFT-1666](https://issues.apache.org/jira/browse/THRIFT-1666) - htonll usage in TBinaryProtocol.tcc generates warning with MSVC2010 - [THRIFT-1919](https://issues.apache.org/jira/browse/THRIFT-1919) - libthrift depends on httpcore-4.1.3 (directly) and httpcore-4.1.4 (transitively) - [THRIFT-1864](https://issues.apache.org/jira/browse/THRIFT-1864) - implement event handler for non-blocking server - [THRIFT-1859](https://issues.apache.org/jira/browse/THRIFT-1859) - Generated error c++ code with -out and include_prefix param - [THRIFT-1869](https://issues.apache.org/jira/browse/THRIFT-1869) - TThreadPoolServer (java) dies when threadpool is consumed - [THRIFT-1842](https://issues.apache.org/jira/browse/THRIFT-1842) - Memory leak with Pipes - [THRIFT-1838](https://issues.apache.org/jira/browse/THRIFT-1838) - Can't build compiler on OS X because of missing thrifty.h - [THRIFT-1846](https://issues.apache.org/jira/browse/THRIFT-1846) - Restore socket.h header to support builds with Android NDK - [THRIFT-1850](https://issues.apache.org/jira/browse/THRIFT-1850) - make check hangs on TSocket tests in TransportTest.cpp - [THRIFT-1873](https://issues.apache.org/jira/browse/THRIFT-1873) - Binary protocol factory ignores struct read/write flags - [THRIFT-1872](https://issues.apache.org/jira/browse/THRIFT-1872) - issues with TBufferedTransport buffer - [THRIFT-1904](https://issues.apache.org/jira/browse/THRIFT-1904) - Incorrect code is generated for typedefs which use included types - [THRIFT-1903](https://issues.apache.org/jira/browse/THRIFT-1903) - PHP namespaces cause binary protocols to not be used - [THRIFT-1895](https://issues.apache.org/jira/browse/THRIFT-1895) - Delphi: reserved variable name "result" not detected properly - [THRIFT-1881](https://issues.apache.org/jira/browse/THRIFT-1881) - TNonblockingServer does not release open connections or threads on shutdown - [THRIFT-1888](https://issues.apache.org/jira/browse/THRIFT-1888) - Java Thrift client can't connect to Python Thrift server on same host - [THRIFT-1831](https://issues.apache.org/jira/browse/THRIFT-1831) - Bug in list deserializer - [THRIFT-1824](https://issues.apache.org/jira/browse/THRIFT-1824) - many compile warning, becase Thread.h includes config.h - [THRIFT-1823](https://issues.apache.org/jira/browse/THRIFT-1823) - Missing parenthesis breaks "IS_..." macro in generated code - [THRIFT-1806](https://issues.apache.org/jira/browse/THRIFT-1806) - Python generation always truncates __init__.py files - [THRIFT-1795](https://issues.apache.org/jira/browse/THRIFT-1795) - Race condition in TThreadedServerPool java implementation - [THRIFT-1794](https://issues.apache.org/jira/browse/THRIFT-1794) - C# asyncctp broken - [THRIFT-1804](https://issues.apache.org/jira/browse/THRIFT-1804) - Binary+compact protocol single byte error in Ruby library (ARM architecture): caused by different char signedness - [THRIFT-1800](https://issues.apache.org/jira/browse/THRIFT-1800) - Documentation text not always escaped correctly when rendered to HTML - [THRIFT-1788](https://issues.apache.org/jira/browse/THRIFT-1788) - C#: Constants static constructor does not compile - [THRIFT-1816](https://issues.apache.org/jira/browse/THRIFT-1816) - Need "require" included thrift files in "xxx_types.js" - [THRIFT-1907](https://issues.apache.org/jira/browse/THRIFT-1907) - Compiling namespace and sub-namespace directives for unrecognized generators should only be a warning - [THRIFT-1913](https://issues.apache.org/jira/browse/THRIFT-1913) - skipping unknown fields in java unions - [THRIFT-2553](https://issues.apache.org/jira/browse/THRIFT-2553) - C++ linker error) - transport/TSocket - [THRIFT-274](https://issues.apache.org/jira/browse/THRIFT-274) - Towards a working release/versioning process ### Documentation - [THRIFT-1971](https://issues.apache.org/jira/browse/THRIFT-1971) - [Graphviz] Adds tutorial/general description documentation - [THRIFT-2001](https://issues.apache.org/jira/browse/THRIFT-2001) - http://thrift.apache.org/ Example "C++ Server" tab is broken ### Improvement - [THRIFT-1574](https://issues.apache.org/jira/browse/THRIFT-1574) - Apache project branding requirements: DOAP file [PATCH] - [THRIFT-1347](https://issues.apache.org/jira/browse/THRIFT-1347) - Unify the exceptions returned in generated Go code - [THRIFT-1353](https://issues.apache.org/jira/browse/THRIFT-1353) - Switch to performance branch, get rid of BinaryParser - [THRIFT-1629](https://issues.apache.org/jira/browse/THRIFT-1629) - Ruby 1.9 Compatibility during Thrift configure, make, install - [THRIFT-991](https://issues.apache.org/jira/browse/THRIFT-991) - Refactor Haskell code and generator - [THRIFT-990](https://issues.apache.org/jira/browse/THRIFT-990) - Sanify gettimeofday usage codebase-wide - [THRIFT-791](https://issues.apache.org/jira/browse/THRIFT-791) - Let C++ TSimpleServer be driven by an external main loop - [THRIFT-2117](https://issues.apache.org/jira/browse/THRIFT-2117) - Cocoa TBinaryProtocol strictWrite should be set to true by default - [THRIFT-2014](https://issues.apache.org/jira/browse/THRIFT-2014) - Change C++ lib includes to use style throughout - [THRIFT-1972](https://issues.apache.org/jira/browse/THRIFT-1972) - Add support for async processors - [THRIFT-1970](https://issues.apache.org/jira/browse/THRIFT-1970) - [Graphviz] Adds option to render exceptions relationships - [THRIFT-1966](https://issues.apache.org/jira/browse/THRIFT-1966) - Support different files for SSL certificates and keys - [THRIFT-1965](https://issues.apache.org/jira/browse/THRIFT-1965) - Adds Graphviz (graph description language) generator - [THRIFT-1956](https://issues.apache.org/jira/browse/THRIFT-1956) - Switch to Apache Commons Lang 3 - [THRIFT-1962](https://issues.apache.org/jira/browse/THRIFT-1962) - Multiplex processor should send any TApplicationException back to client - [THRIFT-1960](https://issues.apache.org/jira/browse/THRIFT-1960) - main() declares 22 unused gen bools - [THRIFT-1951](https://issues.apache.org/jira/browse/THRIFT-1951) - libthrift.jar has source files in it - [THRIFT-1997](https://issues.apache.org/jira/browse/THRIFT-1997) - Add accept backlog configuration method to TServerSocket - [THRIFT-2003](https://issues.apache.org/jira/browse/THRIFT-2003) - Deprecate senum - [THRIFT-2052](https://issues.apache.org/jira/browse/THRIFT-2052) - Vagrant machine image defaults to only 384MB of RAM - [THRIFT-1980](https://issues.apache.org/jira/browse/THRIFT-1980) - Modernize Go tooling, fix go client library. - [THRIFT-1977](https://issues.apache.org/jira/browse/THRIFT-1977) - C# compiler should generate constant files prefixed with thrift file name - [THRIFT-1985](https://issues.apache.org/jira/browse/THRIFT-1985) - add a Vagrantfile to build and test Apache Thrift fully reproducible - [THRIFT-1994](https://issues.apache.org/jira/browse/THRIFT-1994) - Deprecate slist - [THRIFT-1993](https://issues.apache.org/jira/browse/THRIFT-1993) - Factory to create instances from known (generated) interface types with Delphi - [THRIFT-2081](https://issues.apache.org/jira/browse/THRIFT-2081) - Specified timeout should be used in TSocket.Open() - [THRIFT-2084](https://issues.apache.org/jira/browse/THRIFT-2084) - Delphi: Ability to create entity Thrift-generated instances based on TypeInfo - [THRIFT-2083](https://issues.apache.org/jira/browse/THRIFT-2083) - Improve the go lib: buffered Transport, save memory allocation, handle concurrent request - [THRIFT-2109](https://issues.apache.org/jira/browse/THRIFT-2109) - Secure connections should be supported in Go - [THRIFT-2107](https://issues.apache.org/jira/browse/THRIFT-2107) - minor Go generator fixes - [THRIFT-1695](https://issues.apache.org/jira/browse/THRIFT-1695) - allow warning-free compilation in VS 2012 and GNU 4.6 - [THRIFT-1735](https://issues.apache.org/jira/browse/THRIFT-1735) - integrate tutorial into regular build - [THRIFT-1716](https://issues.apache.org/jira/browse/THRIFT-1716) - max allowed connections should be PIPE_UNLIMITED_INSTANCES - [THRIFT-1715](https://issues.apache.org/jira/browse/THRIFT-1715) - Allow excluding python parts when building contrib/fb303 - [THRIFT-1733](https://issues.apache.org/jira/browse/THRIFT-1733) - Fix RPM build issues on RHEL6/OL6 systems - [THRIFT-1728](https://issues.apache.org/jira/browse/THRIFT-1728) - Upgradation of httpcomponents - [THRIFT-1876](https://issues.apache.org/jira/browse/THRIFT-1876) - Use enum names instead of casted integers in assignments - [THRIFT-1874](https://issues.apache.org/jira/browse/THRIFT-1874) - timeout for the server-side end of a named pipe - [THRIFT-1897](https://issues.apache.org/jira/browse/THRIFT-1897) - Support validation of required fields - [THRIFT-1896](https://issues.apache.org/jira/browse/THRIFT-1896) - Add TBase protocol for Cocoa - [THRIFT-1880](https://issues.apache.org/jira/browse/THRIFT-1880) - Make named pipes server work asynchronously (overlapped) to allow for clean server stops - [THRIFT-1878](https://issues.apache.org/jira/browse/THRIFT-1878) - Add the possibility to send custom headers - [THRIFT-1882](https://issues.apache.org/jira/browse/THRIFT-1882) - Use single include - [THRIFT-1793](https://issues.apache.org/jira/browse/THRIFT-1793) - C#: Use static read instead of instance read - [THRIFT-1799](https://issues.apache.org/jira/browse/THRIFT-1799) - Option to generate HTML in "standalone mode" - [THRIFT-1815](https://issues.apache.org/jira/browse/THRIFT-1815) - Code generators line buffer output - [THRIFT-1890](https://issues.apache.org/jira/browse/THRIFT-1890) - C++: Make named pipes server work asynchronously - [THRIFT-474](https://issues.apache.org/jira/browse/THRIFT-474) - Generating Ruby on Rails friendly code ### New Feature - [THRIFT-801](https://issues.apache.org/jira/browse/THRIFT-801) - Provide an interactive shell (irb) when generating ruby bindings - [THRIFT-2292](https://issues.apache.org/jira/browse/THRIFT-2292) - Android Library Project - [THRIFT-2012](https://issues.apache.org/jira/browse/THRIFT-2012) - Modernizing Go - [THRIFT-1969](https://issues.apache.org/jira/browse/THRIFT-1969) - C#: Tests not properly linked from the solution - [THRIFT-1785](https://issues.apache.org/jira/browse/THRIFT-1785) - C#: Add TMemoryBuffer serializer/deserializer - [THRIFT-1780](https://issues.apache.org/jira/browse/THRIFT-1780) - Add option to generate nullable values - [THRIFT-1786](https://issues.apache.org/jira/browse/THRIFT-1786) - C# Union Typing - [THRIFT-591](https://issues.apache.org/jira/browse/THRIFT-591) - Make the C++ runtime library be compatible with Windows and Visual Studio - [THRIFT-514](https://issues.apache.org/jira/browse/THRIFT-514) - Add option to configure compiler output directory ### Question - [THRIFT-1764](https://issues.apache.org/jira/browse/THRIFT-1764) - how to get the context of client when on a rpc call in server side? - [THRIFT-1791](https://issues.apache.org/jira/browse/THRIFT-1791) - thrift's namespace directive when generating haskell code ### Sub-task - [THRIFT-1594](https://issues.apache.org/jira/browse/THRIFT-1594) - Java test clients should have a return codes that reflect whether it succeeds or not. - [THRIFT-1595](https://issues.apache.org/jira/browse/THRIFT-1595) - Java test server should follow the documented behavior as of THRIFT-1590 - [THRIFT-986](https://issues.apache.org/jira/browse/THRIFT-986) - st: add version Info to the library - [THRIFT-985](https://issues.apache.org/jira/browse/THRIFT-985) - php: add version Info to the library - [THRIFT-984](https://issues.apache.org/jira/browse/THRIFT-984) - ocaml: add version Info to the library - [THRIFT-1924](https://issues.apache.org/jira/browse/THRIFT-1924) - Delphi: Inconsistency in serialization of optional fields - [THRIFT-1922](https://issues.apache.org/jira/browse/THRIFT-1922) - C#: Inconsistency in serialization of optional fields - [THRIFT-1961](https://issues.apache.org/jira/browse/THRIFT-1961) - C# tests should be in lib/csharp/test/... - [THRIFT-1822](https://issues.apache.org/jira/browse/THRIFT-1822) - PHP unit test does not work - [THRIFT-1902](https://issues.apache.org/jira/browse/THRIFT-1902) - C++: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-1901](https://issues.apache.org/jira/browse/THRIFT-1901) - C#: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-1899](https://issues.apache.org/jira/browse/THRIFT-1899) - Delphi: Support for Multiplexing Services on any Transport, Protocol and Server - [THRIFT-563](https://issues.apache.org/jira/browse/THRIFT-563) - Support for Multiplexing Services on any Transport, Protocol and Server ## 0.9 ### Bug - [THRIFT-1438](https://issues.apache.org/jira/browse/THRIFT-1438) - lib/cpp/src/windows/config.h should read version from configure.ac rather than a #define - [THRIFT-1446](https://issues.apache.org/jira/browse/THRIFT-1446) - Compile error with Delphi 2009 in constant initializer - [THRIFT-1450](https://issues.apache.org/jira/browse/THRIFT-1450) - Problems building thrift 0.8.0 for Python and Ruby - [THRIFT-1449](https://issues.apache.org/jira/browse/THRIFT-1449) - Ruby client does not work on solaris (?) - [THRIFT-1447](https://issues.apache.org/jira/browse/THRIFT-1447) - NullpointerException in ProcessFunction.class :in "oneway" method - [THRIFT-1433](https://issues.apache.org/jira/browse/THRIFT-1433) - TServerSocket fix for MSVC - [THRIFT-1429](https://issues.apache.org/jira/browse/THRIFT-1429) - The nonblocking servers is supposed to use TransportFactory to read the data - [THRIFT-1427](https://issues.apache.org/jira/browse/THRIFT-1427) - PHP library uses non-multibyte safe functions with mbstring function overloading - [THRIFT-1421](https://issues.apache.org/jira/browse/THRIFT-1421) - Debian Packages can not be built - [THRIFT-1394](https://issues.apache.org/jira/browse/THRIFT-1394) - Treatment of optional fields is not consistent between C++ and Java - [THRIFT-1511](https://issues.apache.org/jira/browse/THRIFT-1511) - Server with oneway support ( JAVA ) - [THRIFT-1496](https://issues.apache.org/jira/browse/THRIFT-1496) - PHP compiler not namespacing enums - [THRIFT-1495](https://issues.apache.org/jira/browse/THRIFT-1495) - PHP TestClient fatals on missing class - [THRIFT-1508](https://issues.apache.org/jira/browse/THRIFT-1508) - TServerSocket does not allow for the user to specify the IP address to bind to - [THRIFT-1504](https://issues.apache.org/jira/browse/THRIFT-1504) - Cocoa Generator should use local file imports for base Thrift headers - [THRIFT-1512](https://issues.apache.org/jira/browse/THRIFT-1512) - Thrift socket support for Windows XP - [THRIFT-1502](https://issues.apache.org/jira/browse/THRIFT-1502) - TSimpleServer::serve(): Do not print out error message if server was stopped. - [THRIFT-1501](https://issues.apache.org/jira/browse/THRIFT-1501) - PHP old namespaces not generated for enums - [THRIFT-1483](https://issues.apache.org/jira/browse/THRIFT-1483) - java compiler does not generate type parameters for services in extended clauses - [THRIFT-1479](https://issues.apache.org/jira/browse/THRIFT-1479) - Compiled PHP process functions missing writeMessageEnd() - [THRIFT-1492](https://issues.apache.org/jira/browse/THRIFT-1492) - enabling c_glib render thrift unusable (even for C++ code) - [THRIFT-1491](https://issues.apache.org/jira/browse/THRIFT-1491) - Uninitialize processorFactory_ member in TServer.h - [THRIFT-1475](https://issues.apache.org/jira/browse/THRIFT-1475) - Incomplete records generation for Erlang - [THRIFT-1486](https://issues.apache.org/jira/browse/THRIFT-1486) - Javascript manual testserver not returning content types - [THRIFT-1488](https://issues.apache.org/jira/browse/THRIFT-1488) - src/concurrency/Thread.h:91:58: error: invalid conversion from 'pthread_t {aka _opaque_pthread_t*}' to 'apache::thrift::concurrency::Thread::id_t {aka long long unsigned int}' [-fpermissive] - [THRIFT-1490](https://issues.apache.org/jira/browse/THRIFT-1490) - Windows-specific header files) - fixes & tweaks - [THRIFT-1526](https://issues.apache.org/jira/browse/THRIFT-1526) - Union TupleSchemeFactory returns StandardSchemes - [THRIFT-1527](https://issues.apache.org/jira/browse/THRIFT-1527) - Generated implementation of tupleReadStruct in unions return null when the setfield is unrecognized - [THRIFT-1524](https://issues.apache.org/jira/browse/THRIFT-1524) - TNonBlockingServer does not compile in Visual Studio 2010 - [THRIFT-1529](https://issues.apache.org/jira/browse/THRIFT-1529) - TupleProtocol can unintentionally include an extra byte in bit vectors when number of optional fields is an integral of 8 - [THRIFT-1473](https://issues.apache.org/jira/browse/THRIFT-1473) - JSON context stack may be left in an incorrect state when an exception is thrown during read or write operations - [THRIFT-1456](https://issues.apache.org/jira/browse/THRIFT-1456) - System.Net.HttpWebRequest' does not contain a definition for 'Proxy' - [THRIFT-1468](https://issues.apache.org/jira/browse/THRIFT-1468) - Memory leak in TSaslServerTransport - [THRIFT-1461](https://issues.apache.org/jira/browse/THRIFT-1461) - Recent TNonblockingServer changes broke --enable-boostthreads=yes, Windows - [THRIFT-1460](https://issues.apache.org/jira/browse/THRIFT-1460) - why not add unicode strings support to python directly? - [THRIFT-1464](https://issues.apache.org/jira/browse/THRIFT-1464) - AbstractNonblockingServer.FrameBuffer TNonblockingTransport accessor changed from public to private - [THRIFT-1467](https://issues.apache.org/jira/browse/THRIFT-1467) - Possible AV with empty strings when using JSON protocol - [THRIFT-1523](https://issues.apache.org/jira/browse/THRIFT-1523) - clientTimeout not worked as expected in TServerSocket created by TSSLTransportFactory - [THRIFT-1537](https://issues.apache.org/jira/browse/THRIFT-1537) - TFramedTransport issues - [THRIFT-1519](https://issues.apache.org/jira/browse/THRIFT-1519) - Thirft Build Failure referencing rb_intern2 symbol - [THRIFT-1518](https://issues.apache.org/jira/browse/THRIFT-1518) - Generated C++ code only sends the first optional field in the write() function for a struct. - [THRIFT-1515](https://issues.apache.org/jira/browse/THRIFT-1515) - NameError: global name 'TApplicationException' is not defined - [THRIFT-1554](https://issues.apache.org/jira/browse/THRIFT-1554) - Inherited service methods are not resolved in derived service implementations - [THRIFT-1553](https://issues.apache.org/jira/browse/THRIFT-1553) - thrift nodejs service side can't read map structure, key as enum, value as Object - [THRIFT-1575](https://issues.apache.org/jira/browse/THRIFT-1575) - Typo in server/TThreadPoolServer.h - [THRIFT-1327](https://issues.apache.org/jira/browse/THRIFT-1327) - Fix Spec Suite under Ruby-1.8.7 (works for MRI Ruby-1.9.2) - [THRIFT-1326](https://issues.apache.org/jira/browse/THRIFT-1326) - on some platforms, #include is necessary to be included in Thrift.h - [THRIFT-1159](https://issues.apache.org/jira/browse/THRIFT-1159) - THttpClient->Flush() issue (connection thru proxy) - [THRIFT-1277](https://issues.apache.org/jira/browse/THRIFT-1277) - Node.js serializes false booleans as null - [THRIFT-1224](https://issues.apache.org/jira/browse/THRIFT-1224) - Cannot insert UTF-8 text - [THRIFT-1267](https://issues.apache.org/jira/browse/THRIFT-1267) - Node.js can't throw exceptions. - [THRIFT-1338](https://issues.apache.org/jira/browse/THRIFT-1338) - Do not use an unpatched autoconf 2.65 to generate release tarball - [THRIFT-1128](https://issues.apache.org/jira/browse/THRIFT-1128) - MAC OS X: thrift.h incompatibility with Thrift.h - [THRIFT-1631](https://issues.apache.org/jira/browse/THRIFT-1631) - Fix C++ server constructor typos - [THRIFT-1602](https://issues.apache.org/jira/browse/THRIFT-1602) - PHP C Extension is not Compatible with PHP 5.4 - [THRIFT-1610](https://issues.apache.org/jira/browse/THRIFT-1610) - IWebProxy not available on WP7 platform - [THRIFT-1606](https://issues.apache.org/jira/browse/THRIFT-1606) - Race condition in BoostThreadFactory.cpp - [THRIFT-1604](https://issues.apache.org/jira/browse/THRIFT-1604) - Python exception handeling for changes from PEP 3110 - [THRIFT-1607](https://issues.apache.org/jira/browse/THRIFT-1607) - Incorrect file modes for several source files - [THRIFT-1583](https://issues.apache.org/jira/browse/THRIFT-1583) - c_glib leaks memory - [THRIFT-1582](https://issues.apache.org/jira/browse/THRIFT-1582) - Bad includes of nested thrift files in c_glib - [THRIFT-1578](https://issues.apache.org/jira/browse/THRIFT-1578) - C_GLib generated code does not compile - [THRIFT-1597](https://issues.apache.org/jira/browse/THRIFT-1597) - TJSONProtocol.php is missing from Makefile.am - [THRIFT-1591](https://issues.apache.org/jira/browse/THRIFT-1591) - Enable TCP_NODELAY for ruby gem - [THRIFT-1624](https://issues.apache.org/jira/browse/THRIFT-1624) - Isset Generated differently on different platforms - [THRIFT-1622](https://issues.apache.org/jira/browse/THRIFT-1622) - Incorrect size returned on read - [THRIFT-1621](https://issues.apache.org/jira/browse/THRIFT-1621) - Memory leaks - [THRIFT-1612](https://issues.apache.org/jira/browse/THRIFT-1612) - Base64 encoding is broken - [THRIFT-1627](https://issues.apache.org/jira/browse/THRIFT-1627) - compiler built using compilers.vcxproj cannot be used to build some test .thrift files - [THRIFT-1571](https://issues.apache.org/jira/browse/THRIFT-1571) - Update Ruby HTTP transport for recent Ruby versions - [THRIFT-1023](https://issues.apache.org/jira/browse/THRIFT-1023) - Thrift encoding (UTF-8) issue with Ruby 1.9.2 - [THRIFT-1090](https://issues.apache.org/jira/browse/THRIFT-1090) - Document the generation of a file called "Constants.java" - [THRIFT-1082](https://issues.apache.org/jira/browse/THRIFT-1082) - Thrift::FramedTransport sometimes calls close() on an undefined value - [THRIFT-956](https://issues.apache.org/jira/browse/THRIFT-956) - Python module's version meta-data should be updated - [THRIFT-973](https://issues.apache.org/jira/browse/THRIFT-973) - Cocoa library won't compile using clang - [THRIFT-1632](https://issues.apache.org/jira/browse/THRIFT-1632) - ruby: data corruption in thrift_native implementation of MemoryBufferTransport - [THRIFT-1665](https://issues.apache.org/jira/browse/THRIFT-1665) - TBinaryProtocol: exceeded message length raises generic TException - [THRIFT-1664](https://issues.apache.org/jira/browse/THRIFT-1664) - Reference to non-existing variable in build script - [THRIFT-1663](https://issues.apache.org/jira/browse/THRIFT-1663) - Java Thrift server is not throwing exceptions - [THRIFT-1662](https://issues.apache.org/jira/browse/THRIFT-1662) - "removeObject:" should be "removeObserver:" in [-TSocketServer dealloc]? - [THRIFT-1643](https://issues.apache.org/jira/browse/THRIFT-1643) - Denial of Service attack in TBinaryProtocol.readString - [THRIFT-1674](https://issues.apache.org/jira/browse/THRIFT-1674) - Update Thrift D library to be compatible with 2.060 - [THRIFT-1673](https://issues.apache.org/jira/browse/THRIFT-1673) - Ruby compile flags for extension for multi arch builds (os x) - [THRIFT-1655](https://issues.apache.org/jira/browse/THRIFT-1655) - Configure still trying to use thrift_generators in output - [THRIFT-1654](https://issues.apache.org/jira/browse/THRIFT-1654) - c_glib thrift_socket_read() returns corrupted data - [THRIFT-1653](https://issues.apache.org/jira/browse/THRIFT-1653) - TThreadedSelectorServer leaks CLOSE_WAIT sockets - [THRIFT-1658](https://issues.apache.org/jira/browse/THRIFT-1658) - Java thrift server is not throwing TApplicationException - [THRIFT-1656](https://issues.apache.org/jira/browse/THRIFT-1656) - Setting proper headers in THttpServer.cpp so that "Cross-Origin Resource Sharing" on js client can work. - [THRIFT-1652](https://issues.apache.org/jira/browse/THRIFT-1652) - TSaslTransport does not log the error when kerberos auth fails - [THRIFT-2272](https://issues.apache.org/jira/browse/THRIFT-2272) - CLONE) - Denial of Service attack in TBinaryProtocol.readString - [THRIFT-2086](https://issues.apache.org/jira/browse/THRIFT-2086) - Invalid generated code for Node.JS when using namespaces - [THRIFT-1686](https://issues.apache.org/jira/browse/THRIFT-1686) - t_php_generator.cc uses "and" instead of "&&", and causes compiler errors with Visual Studio - [THRIFT-1693](https://issues.apache.org/jira/browse/THRIFT-1693) - libthrift has dependency on two different versions of httpcore - [THRIFT-1689](https://issues.apache.org/jira/browse/THRIFT-1689) - don't exit(-1) in TNonblockingServer - [THRIFT-1679](https://issues.apache.org/jira/browse/THRIFT-1679) - NodeJS: protocol readString() should treat string as utf8, not binary - [THRIFT-1721](https://issues.apache.org/jira/browse/THRIFT-1721) - Dist broken due to 0.8.0 to 0.9.0 changes - [THRIFT-1710](https://issues.apache.org/jira/browse/THRIFT-1710) - Minor issues in test case code - [THRIFT-1709](https://issues.apache.org/jira/browse/THRIFT-1709) - Warning "Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first" in TBinaryProtocol.cs at ReadInt64() - [THRIFT-1707](https://issues.apache.org/jira/browse/THRIFT-1707) - [ruby] Adjust server_spec.rb for RSpec 2.11.x and Ruby 1.9.3 - [THRIFT-1671](https://issues.apache.org/jira/browse/THRIFT-1671) - Cocoa code generator does not put keywords into generated method calls - [THRIFT-1670](https://issues.apache.org/jira/browse/THRIFT-1670) - Incompatibilities between different versions of a Thrift interface - [THRIFT-1669](https://issues.apache.org/jira/browse/THRIFT-1669) - NameError: global name 'TApplicationException' is not defined - [THRIFT-1668](https://issues.apache.org/jira/browse/THRIFT-1668) - Compile error in contrib/fb303, thrift/TDispatchProcessor.h: No such file or directory - [THRIFT-1845](https://issues.apache.org/jira/browse/THRIFT-1845) - Fix compiler warning caused by implicit string conversion with Xcode 4.6 - [THRIFT-304](https://issues.apache.org/jira/browse/THRIFT-304) - Building the Python library requires development headers - [THRIFT-369](https://issues.apache.org/jira/browse/THRIFT-369) - sets and maps break equality - [THRIFT-556](https://issues.apache.org/jira/browse/THRIFT-556) - Ruby compiler does not correctly referred to top-level modules when a submodule masks the top-level name - [THRIFT-481](https://issues.apache.org/jira/browse/THRIFT-481) - indentation of ruby classes is off by a few ### Improvement - [THRIFT-1498](https://issues.apache.org/jira/browse/THRIFT-1498) - Allow TThreadedPoolServer.Args to pass a ExecutorService - [THRIFT-1444](https://issues.apache.org/jira/browse/THRIFT-1444) - FunctionRunner) - add syntactic sugar to create shared_ptrs - [THRIFT-1443](https://issues.apache.org/jira/browse/THRIFT-1443) - define a TProcessor helper class to implement process() - [THRIFT-1441](https://issues.apache.org/jira/browse/THRIFT-1441) - Generate constructor with parameters for exception class to let it update message property automatically. - [THRIFT-1520](https://issues.apache.org/jira/browse/THRIFT-1520) - Embed version number in erlang .app file - [THRIFT-1480](https://issues.apache.org/jira/browse/THRIFT-1480) - python: remove tabs, adjust whitespace and address PEP8 warnings - [THRIFT-1485](https://issues.apache.org/jira/browse/THRIFT-1485) - Performance: pass large and/or refcounted arguments as "const" - [THRIFT-1484](https://issues.apache.org/jira/browse/THRIFT-1484) - Introduce phpunit test suite - [THRIFT-1532](https://issues.apache.org/jira/browse/THRIFT-1532) - The type specifications in the generated Erlang code should include "undefined" where it's used as a default value - [THRIFT-1534](https://issues.apache.org/jira/browse/THRIFT-1534) - Required fields in the Delphi code generator. - [THRIFT-1469](https://issues.apache.org/jira/browse/THRIFT-1469) - Java isset space optimization - [THRIFT-1465](https://issues.apache.org/jira/browse/THRIFT-1465) - Visibility of methods in generated java code - [THRIFT-1453](https://issues.apache.org/jira/browse/THRIFT-1453) - Don't change types of arguments when serializing with thrift php extension - [THRIFT-1452](https://issues.apache.org/jira/browse/THRIFT-1452) - generate a swap() method for all generated structs - [THRIFT-1451](https://issues.apache.org/jira/browse/THRIFT-1451) - FramedTransport: Prevent infinite loop when writing - [THRIFT-1521](https://issues.apache.org/jira/browse/THRIFT-1521) - Two patches for more Performance - [THRIFT-1555](https://issues.apache.org/jira/browse/THRIFT-1555) - Delphi version of the tutorial code - [THRIFT-1535](https://issues.apache.org/jira/browse/THRIFT-1535) - Why thrift don't use wrapped class for optional fields ? - [THRIFT-1204](https://issues.apache.org/jira/browse/THRIFT-1204) - Ruby autogenerated files should require 'thrift' gem - [THRIFT-1344](https://issues.apache.org/jira/browse/THRIFT-1344) - Using the httpc module directly rather than the deprecated http layer - [THRIFT-1343](https://issues.apache.org/jira/browse/THRIFT-1343) - no_auto_import min/2 to avoid compile warning - [THRIFT-1340](https://issues.apache.org/jira/browse/THRIFT-1340) - Add support of ARC to Objective-C - [THRIFT-1611](https://issues.apache.org/jira/browse/THRIFT-1611) - Improved code generation for typedefs - [THRIFT-1593](https://issues.apache.org/jira/browse/THRIFT-1593) - Pass on errors like "connection closed" to the handler module - [THRIFT-1615](https://issues.apache.org/jira/browse/THRIFT-1615) - PHP Namespace - [THRIFT-1567](https://issues.apache.org/jira/browse/THRIFT-1567) - Thrift/cpp: Allow alternate classes to be used for - [THRIFT-1072](https://issues.apache.org/jira/browse/THRIFT-1072) - Missing) - (id) initWithSharedProcessor in TSharedProcessorFactory.h - [THRIFT-1650](https://issues.apache.org/jira/browse/THRIFT-1650) - [ruby] Update clean items and svn:ignore entries for OS X artifacts - [THRIFT-1661](https://issues.apache.org/jira/browse/THRIFT-1661) - [PATCH] Add --with-qt4 configure option - [THRIFT-1675](https://issues.apache.org/jira/browse/THRIFT-1675) - Do we have any plan to support scala? - [THRIFT-1645](https://issues.apache.org/jira/browse/THRIFT-1645) - Replace Object#tee with more conventional Object#tap in specs - [THRIFT-1644](https://issues.apache.org/jira/browse/THRIFT-1644) - Upgrade RSpec to 2.10.x and refactor specs as needed - [THRIFT-1672](https://issues.apache.org/jira/browse/THRIFT-1672) - MonoTouch (and Mono for Android) compatibility - [THRIFT-1702](https://issues.apache.org/jira/browse/THRIFT-1702) - a thrift manual - [THRIFT-1694](https://issues.apache.org/jira/browse/THRIFT-1694) - Re-Enable serialization for WP7 Silverlight - [THRIFT-1691](https://issues.apache.org/jira/browse/THRIFT-1691) - Serializer/deserializer support for Delphi - [THRIFT-1688](https://issues.apache.org/jira/browse/THRIFT-1688) - Update IDL page markup - [THRIFT-1725](https://issues.apache.org/jira/browse/THRIFT-1725) - Tutorial web pages for Delphi and C# - [THRIFT-1714](https://issues.apache.org/jira/browse/THRIFT-1714) - [ruby] Explicitly add CWD to Ruby test_suites.rb - [THRIFT-317](https://issues.apache.org/jira/browse/THRIFT-317) - Issues with Java struct validation - [THRIFT-164](https://issues.apache.org/jira/browse/THRIFT-164) - Build web tutorial on Incubator web site - [THRIFT-541](https://issues.apache.org/jira/browse/THRIFT-541) - Cocoa code generator doesn't put keywords before all arguments. - [THRIFT-681](https://issues.apache.org/jira/browse/THRIFT-681) - The HTML generator does not handle JavaDoc style comments very well ### New Feature - [THRIFT-1500](https://issues.apache.org/jira/browse/THRIFT-1500) - D programming language support - [THRIFT-1510](https://issues.apache.org/jira/browse/THRIFT-1510) - There should be an implementation of the JsonProtocol for ruby - [THRIFT-1115](https://issues.apache.org/jira/browse/THRIFT-1115) - python TBase class for dynamic (de)serialization, and __slots__ option for memory savings - [THRIFT-1953](https://issues.apache.org/jira/browse/THRIFT-1953) - support for asp.net mvc 3 ### Question - [THRIFT-1235](https://issues.apache.org/jira/browse/THRIFT-1235) - How could I use THttpServerTransportFactory withTNonBlockingServer - [THRIFT-1368](https://issues.apache.org/jira/browse/THRIFT-1368) - TNonblockingServer usage - [THRIFT-1061](https://issues.apache.org/jira/browse/THRIFT-1061) - Read an invalid frame size of 0. Are you using TFramedTransport on the client side? - [THRIFT-491](https://issues.apache.org/jira/browse/THRIFT-491) - Ripping raw pthreads out of TFileTransport and associated test issues ### Sub-task - [THRIFT-1596](https://issues.apache.org/jira/browse/THRIFT-1596) - Delphi: Test clients should have a return codes that reflect whether they succeeded or not - [THRIFT-982](https://issues.apache.org/jira/browse/THRIFT-982) - javame: add version Info to the library - [THRIFT-1722](https://issues.apache.org/jira/browse/THRIFT-1722) - C# WP7 Assembly addition beaks mono build - [THRIFT-336](https://issues.apache.org/jira/browse/THRIFT-336) - Compact Protocol in C# ### Test - [THRIFT-1613](https://issues.apache.org/jira/browse/THRIFT-1613) - Add code back into empty source file ToStringTest.java - [THRIFT-1718](https://issues.apache.org/jira/browse/THRIFT-1718) - Incorrect check in TFileTransportTest ### Wish - [THRIFT-1463](https://issues.apache.org/jira/browse/THRIFT-1463) - Decouple Thrift IDL from generators - [THRIFT-1466](https://issues.apache.org/jira/browse/THRIFT-1466) - Proper Documentation for Thrift C Glib - [THRIFT-1539](https://issues.apache.org/jira/browse/THRIFT-1539) - Build and distribute the fb303 python libraries along with thrift - [THRIFT-1685](https://issues.apache.org/jira/browse/THRIFT-1685) - Please add "aereo.com" to "Powered by Apache Thrift" list in about page - [THRIFT-330](https://issues.apache.org/jira/browse/THRIFT-330) - TProcessor) - additional method to called when connection is broken ## 0.8 ### Bug - [THRIFT-1436](https://issues.apache.org/jira/browse/THRIFT-1436) - pip install thrift fails on Windows with "Unable to find vcvarsall.bat" - [THRIFT-1432](https://issues.apache.org/jira/browse/THRIFT-1432) - Javascript struct constants declared in the same file as their struct definition will cause an error - [THRIFT-1428](https://issues.apache.org/jira/browse/THRIFT-1428) - shared.thrft does not include namespace for php, so thrift compiler generate incorrect name - [THRIFT-1426](https://issues.apache.org/jira/browse/THRIFT-1426) - Dist package missing files for release 0.8 - [THRIFT-1425](https://issues.apache.org/jira/browse/THRIFT-1425) - The Node package is incompatible with latest node (0.6) & npm (1.0.27) - [THRIFT-1416](https://issues.apache.org/jira/browse/THRIFT-1416) - Python Unit test is broken on ci - [THRIFT-1419](https://issues.apache.org/jira/browse/THRIFT-1419) - AbstractNonBlockingServer does not catch errors when invoking the processor - [THRIFT-1424](https://issues.apache.org/jira/browse/THRIFT-1424) - Ruby specs fail when run with rake - [THRIFT-1420](https://issues.apache.org/jira/browse/THRIFT-1420) - Nonblocking and HsHa server should make sure to close all their socket connections when the selector exits - [THRIFT-1413](https://issues.apache.org/jira/browse/THRIFT-1413) - Generated code does not read MapEnd / ListEnd / SetEnd - [THRIFT-1409](https://issues.apache.org/jira/browse/THRIFT-1409) - Name conflict check does not work properly for exception object(Delphi). - [THRIFT-1408](https://issues.apache.org/jira/browse/THRIFT-1408) - Delphi Test Server: Exception test case fails due to naming conflict with e.message - [THRIFT-1407](https://issues.apache.org/jira/browse/THRIFT-1407) - Typo in Python socket server causes Thrift to fail when we enable a global socket timout - [THRIFT-1397](https://issues.apache.org/jira/browse/THRIFT-1397) - CI server fails during build due to unused parameters in delphi generator - [THRIFT-1404](https://issues.apache.org/jira/browse/THRIFT-1404) - Delphi compiler generates struct reader code with problem. - [THRIFT-1400](https://issues.apache.org/jira/browse/THRIFT-1400) - Ruby native extension aborts with __stack_chk_fail in OSX - [THRIFT-1399](https://issues.apache.org/jira/browse/THRIFT-1399) - One of the TServerImpl.Create CTORs lacks implementation - [THRIFT-1390](https://issues.apache.org/jira/browse/THRIFT-1390) - Debian packages build fix for Squeeze (build from the official 0.7.0 tarball) - [THRIFT-1393](https://issues.apache.org/jira/browse/THRIFT-1393) - TTransportException's thrown from THttpClient contain superfluous slashes in the Exception message - [THRIFT-1392](https://issues.apache.org/jira/browse/THRIFT-1392) - Enabling both namespaces and autoloading in generated PHP code won't work. - [THRIFT-1406](https://issues.apache.org/jira/browse/THRIFT-1406) - Build error after applying THRIFT-1395 - [THRIFT-1405](https://issues.apache.org/jira/browse/THRIFT-1405) - Delphi compiler does not generates container serializer properly. - [THRIFT-1411](https://issues.apache.org/jira/browse/THRIFT-1411) - java generator does not provide type parameter for TBaseProcessor - [THRIFT-1473](https://issues.apache.org/jira/browse/THRIFT-1473) - JSON context stack may be left in an incorrect state when an exception is thrown during read or write operations - [THRIFT-1331](https://issues.apache.org/jira/browse/THRIFT-1331) - Ruby library deserializes an empty map to nil - [THRIFT-1330](https://issues.apache.org/jira/browse/THRIFT-1330) - PHP Namespaces no longer generated - [THRIFT-1328](https://issues.apache.org/jira/browse/THRIFT-1328) - TBaseHelper.toString(...) appends ByteBuffer data outside of valid buffer range - [THRIFT-1322](https://issues.apache.org/jira/browse/THRIFT-1322) - OCaml lib fail to compile: Thrift.ml line 305, int vs int32 mismatch - [THRIFT-1143](https://issues.apache.org/jira/browse/THRIFT-1143) - Build doesn't detect correct architecture type on 64bit osx - [THRIFT-1205](https://issues.apache.org/jira/browse/THRIFT-1205) - port server unduly fragile with arbitrary input - [THRIFT-1279](https://issues.apache.org/jira/browse/THRIFT-1279) - type set is handled incorrectly when writing object - [THRIFT-1298](https://issues.apache.org/jira/browse/THRIFT-1298) - Standard scheme doesn't read or write metadata along with field values - [THRIFT-1265](https://issues.apache.org/jira/browse/THRIFT-1265) - C++ container deserialize - [THRIFT-1263](https://issues.apache.org/jira/browse/THRIFT-1263) - publish ruby client to rubygems - [THRIFT-1384](https://issues.apache.org/jira/browse/THRIFT-1384) - Java help menu missing newline near javame flag - [THRIFT-1382](https://issues.apache.org/jira/browse/THRIFT-1382) - Bundle install doesnot work because thrift crashes - [THRIFT-1381](https://issues.apache.org/jira/browse/THRIFT-1381) - Thrift C++ libs have incorrectly versioned names - [THRIFT-1350](https://issues.apache.org/jira/browse/THRIFT-1350) - Go library code does not build as of r60 (most recent release) - [THRIFT-1365](https://issues.apache.org/jira/browse/THRIFT-1365) - TupleProtocol#writeBitSet unintentionally writes a variable length byte array - [THRIFT-1359](https://issues.apache.org/jira/browse/THRIFT-1359) - --gen-cob cpp:cob_style does not compile anymore - [THRIFT-1319](https://issues.apache.org/jira/browse/THRIFT-1319) - Mismatch between how a union reads and writes a container - [THRIFT-1309](https://issues.apache.org/jira/browse/THRIFT-1309) - libfb303-0.7.0.jar missing in maven repository - [THRIFT-1238](https://issues.apache.org/jira/browse/THRIFT-1238) - Thrift JS client cannot read map of structures - [THRIFT-1254](https://issues.apache.org/jira/browse/THRIFT-1254) - Code can't be compiled against a regular JRE: Object.clone() override has a different return type - [THRIFT-1367](https://issues.apache.org/jira/browse/THRIFT-1367) - Mac OSX build fails with "no such file to load -- spec/rake/spectask" - [THRIFT-1355](https://issues.apache.org/jira/browse/THRIFT-1355) - Running make in lib/rb doesn't build the native extensions - [THRIFT-1370](https://issues.apache.org/jira/browse/THRIFT-1370) - Debian packaging should Build-Depend on libglib2.0-dev - [THRIFT-1342](https://issues.apache.org/jira/browse/THRIFT-1342) - Compilation problem on Windows of fastbinary.c - [THRIFT-1341](https://issues.apache.org/jira/browse/THRIFT-1341) - TProtocol.h endian detection wrong with boost - [THRIFT-1583](https://issues.apache.org/jira/browse/THRIFT-1583) - c_glib leaks memory - [THRIFT-1582](https://issues.apache.org/jira/browse/THRIFT-1582) - Bad includes of nested thrift files in c_glib - [THRIFT-1578](https://issues.apache.org/jira/browse/THRIFT-1578) - C_GLib generated code does not compile - [THRIFT-1027](https://issues.apache.org/jira/browse/THRIFT-1027) - 'make -j 16' fails with "unterminated #ifdef" error - [THRIFT-1121](https://issues.apache.org/jira/browse/THRIFT-1121) - Java server performance regression in 0.6 - [THRIFT-857](https://issues.apache.org/jira/browse/THRIFT-857) - tests run by "make install" fail if generators are disabled - [THRIFT-380](https://issues.apache.org/jira/browse/THRIFT-380) - Use setuptools for python build ### Dependency upgrade - [THRIFT-1257](https://issues.apache.org/jira/browse/THRIFT-1257) - thrift's dependency scope on javax.servlet:servlet-api should be 'provided' ### Improvement - [THRIFT-1445](https://issues.apache.org/jira/browse/THRIFT-1445) - minor C++ generator variable cleanup - [THRIFT-1435](https://issues.apache.org/jira/browse/THRIFT-1435) - make TException.Message property conformant to the usual expectations - [THRIFT-1431](https://issues.apache.org/jira/browse/THRIFT-1431) - Rename 'sys' module to 'util' - [THRIFT-1396](https://issues.apache.org/jira/browse/THRIFT-1396) - Dephi generator has dependacy on boost 1.42 later. - [THRIFT-1395](https://issues.apache.org/jira/browse/THRIFT-1395) - Patch to prevent warnings for integer types in some cases - [THRIFT-1275](https://issues.apache.org/jira/browse/THRIFT-1275) - thrift: always prefix namespaces with " ::" - [THRIFT-1274](https://issues.apache.org/jira/browse/THRIFT-1274) - thrift: fail compilation if an unexpected token is - [THRIFT-1271](https://issues.apache.org/jira/browse/THRIFT-1271) - thrift: fix missing namespace in generated local - [THRIFT-1270](https://issues.apache.org/jira/browse/THRIFT-1270) - thrift: add --allow-neg-keys argument to allow - [THRIFT-1345](https://issues.apache.org/jira/browse/THRIFT-1345) - Allow building without tests - [THRIFT-1286](https://issues.apache.org/jira/browse/THRIFT-1286) - Modernize the Thrift Ruby Library Dev Environment - [THRIFT-1284](https://issues.apache.org/jira/browse/THRIFT-1284) - thrift: fix processor inheritance - [THRIFT-1283](https://issues.apache.org/jira/browse/THRIFT-1283) - thrift: wrap t_cpp_generator::generate_process_function() to 80 - [THRIFT-1282](https://issues.apache.org/jira/browse/THRIFT-1282) - Upgrade httpclient to 4.1.2 (from 4.0.1) - [THRIFT-1281](https://issues.apache.org/jira/browse/THRIFT-1281) - add @generated to the docblock - [THRIFT-1280](https://issues.apache.org/jira/browse/THRIFT-1280) - Thrift: Improve Monitor exception-free interfaces - [THRIFT-1278](https://issues.apache.org/jira/browse/THRIFT-1278) - javadoc warnings) - compilation - [THRIFT-1227](https://issues.apache.org/jira/browse/THRIFT-1227) - Erlang implementation of thrift JSON protocol - [THRIFT-1295](https://issues.apache.org/jira/browse/THRIFT-1295) - Duplicate include in TSocket.cpp - [THRIFT-1294](https://issues.apache.org/jira/browse/THRIFT-1294) - thrift: fix log message typos in TSimpleServer - [THRIFT-1293](https://issues.apache.org/jira/browse/THRIFT-1293) - thrift: improve handling of exceptions thrown by - [THRIFT-1292](https://issues.apache.org/jira/browse/THRIFT-1292) - thrift: silence log spew from TThreadedServer - [THRIFT-1288](https://issues.apache.org/jira/browse/THRIFT-1288) - Allow typedefed exceptions in throws clauses - [THRIFT-1290](https://issues.apache.org/jira/browse/THRIFT-1290) - thrift: TNonblockingServer: clean up state in the - [THRIFT-1287](https://issues.apache.org/jira/browse/THRIFT-1287) - thrift: start refactoring some of the C++ processor - [THRIFT-1289](https://issues.apache.org/jira/browse/THRIFT-1289) - thrift: implement TNonblockingServer::stop() - [THRIFT-1305](https://issues.apache.org/jira/browse/THRIFT-1305) - thrift: make TConnection a private inner class of - [THRIFT-1304](https://issues.apache.org/jira/browse/THRIFT-1304) - TNonblockingServer: pass in the connection context to - [THRIFT-1302](https://issues.apache.org/jira/browse/THRIFT-1302) - thrift: raise an exception if send() times out in - [THRIFT-1301](https://issues.apache.org/jira/browse/THRIFT-1301) - thrift: consolidate common code in TNonblockingServer - [THRIFT-1377](https://issues.apache.org/jira/browse/THRIFT-1377) - abort PHP deserialization on unknown field type - [THRIFT-1379](https://issues.apache.org/jira/browse/THRIFT-1379) - fix uninitialized enum values in thrift C++ objects - [THRIFT-1376](https://issues.apache.org/jira/browse/THRIFT-1376) - Make port specification option in thrift remote - [THRIFT-1375](https://issues.apache.org/jira/browse/THRIFT-1375) - fixed a hex char conversion bug in TJSONProtocol - [THRIFT-1373](https://issues.apache.org/jira/browse/THRIFT-1373) - Fix user-defined exception generation in thrift (python) - [THRIFT-1361](https://issues.apache.org/jira/browse/THRIFT-1361) - Optional replacement of pthread by boost::thread - [THRIFT-1320](https://issues.apache.org/jira/browse/THRIFT-1320) - Consistency of configure generated config.h - [THRIFT-1317](https://issues.apache.org/jira/browse/THRIFT-1317) - Remove copy constructibility from - [THRIFT-1316](https://issues.apache.org/jira/browse/THRIFT-1316) - thrift: update server classes to accept - [THRIFT-1315](https://issues.apache.org/jira/browse/THRIFT-1315) - thrift: generate server interface factory classes - [THRIFT-1314](https://issues.apache.org/jira/browse/THRIFT-1314) - thrift: add TProcessorFactory - [THRIFT-1335](https://issues.apache.org/jira/browse/THRIFT-1335) - Add accept timeout to TServerSocket - [THRIFT-1334](https://issues.apache.org/jira/browse/THRIFT-1334) - Add more info to IllegalStateException - [THRIFT-1333](https://issues.apache.org/jira/browse/THRIFT-1333) - Make RWGuard not copyable - [THRIFT-1332](https://issues.apache.org/jira/browse/THRIFT-1332) - TSSLTransportParameters class uses hard coded value keyManagerType: SunX509 - [THRIFT-1251](https://issues.apache.org/jira/browse/THRIFT-1251) - Generated java code should indicate which fields are required and which are optional - [THRIFT-1387](https://issues.apache.org/jira/browse/THRIFT-1387) - Build MSVC libraries with Boost Threads instead of Pthreads - [THRIFT-1339](https://issues.apache.org/jira/browse/THRIFT-1339) - Extend Tuple Protocol to TUnions - [THRIFT-1031](https://issues.apache.org/jira/browse/THRIFT-1031) - Patch to compile Thrift for vc++ 9.0 and 10.0 - [THRIFT-1130](https://issues.apache.org/jira/browse/THRIFT-1130) - Add the ability to specify symbolic default value for optional boolean - [THRIFT-1123](https://issues.apache.org/jira/browse/THRIFT-1123) - Patch to compile Thrift server and client for vc++ 9.0 and 10.0 - [THRIFT-386](https://issues.apache.org/jira/browse/THRIFT-386) - Make it possible to build the Python library without the extension ### New Feature - [THRIFT-1401](https://issues.apache.org/jira/browse/THRIFT-1401) - JSON-protocol for Delphi XE Libraries - [THRIFT-1167](https://issues.apache.org/jira/browse/THRIFT-1167) - Java nonblocking server with more than one thread for select and handling IO - [THRIFT-1366](https://issues.apache.org/jira/browse/THRIFT-1366) - Delphi generator, lirbrary and unit test. - [THRIFT-1354](https://issues.apache.org/jira/browse/THRIFT-1354) - Add rake task to build just the gem file - [THRIFT-769](https://issues.apache.org/jira/browse/THRIFT-769) - Pluggable Serializers ### Sub-task - [THRIFT-1415](https://issues.apache.org/jira/browse/THRIFT-1415) - delphi: add version Info to the library - [THRIFT-1391](https://issues.apache.org/jira/browse/THRIFT-1391) - Improved Delphi XE test cases ## 0.7 ### Bug - [THRIFT-1140](https://issues.apache.org/jira/browse/THRIFT-1140) - Framed Transport Client using C (Glib) Library hangs when connecting to Ruby Server - [THRIFT-1154](https://issues.apache.org/jira/browse/THRIFT-1154) - HttpClient does not specify the connection close parameter - [THRIFT-1153](https://issues.apache.org/jira/browse/THRIFT-1153) - HttpClient does not specify the connection close parameter - [THRIFT-1149](https://issues.apache.org/jira/browse/THRIFT-1149) - Nonblocking server fails when client connection is reset - [THRIFT-1146](https://issues.apache.org/jira/browse/THRIFT-1146) - Android Incompatibility : in Android < 2.3 java.io.IOException doesn't support for Throwable parameter in constructor - [THRIFT-1133](https://issues.apache.org/jira/browse/THRIFT-1133) - Java and JavaScript tutorial is broken since we have Java maven deployment - [THRIFT-1132](https://issues.apache.org/jira/browse/THRIFT-1132) - Deserialization error in TApplicationException C# - [THRIFT-1131](https://issues.apache.org/jira/browse/THRIFT-1131) - C# JSON Protocol is unable to decode escaped characters in string - [THRIFT-1208](https://issues.apache.org/jira/browse/THRIFT-1208) - python TCompactProtocol.py writeBool and readBool not follow the compact-proto-spec-2.txt spec for CONTAINER_WRITE, CONTAINER_READ - [THRIFT-1200](https://issues.apache.org/jira/browse/THRIFT-1200) - JS compiler generates code that clobbers existing namespaces - [THRIFT-1183](https://issues.apache.org/jira/browse/THRIFT-1183) - Pure-ruby CompactProtocol raises ArgumentError when deserializing under Ruby 1.9 - [THRIFT-1182](https://issues.apache.org/jira/browse/THRIFT-1182) - Native deserializer segfaults on incorrect list element type - [THRIFT-1181](https://issues.apache.org/jira/browse/THRIFT-1181) - AS3 compiler generates incorrect code for setting default values in constructor - [THRIFT-1234](https://issues.apache.org/jira/browse/THRIFT-1234) - thrift --help is missing doc on py:utf8strings - [THRIFT-1180](https://issues.apache.org/jira/browse/THRIFT-1180) - AS3 compiler generates uncompilable code for binary types. - [THRIFT-1194](https://issues.apache.org/jira/browse/THRIFT-1194) - Java lib does not install artifacts to local dir correctly - [THRIFT-1193](https://issues.apache.org/jira/browse/THRIFT-1193) - Potential infinite loop in nonblocking_server - [THRIFT-1192](https://issues.apache.org/jira/browse/THRIFT-1192) - Typo: TProtocol.h tests for HAVE_SYS_PARAM_H_ - [THRIFT-1190](https://issues.apache.org/jira/browse/THRIFT-1190) - readBufferBytesAllocated in TNonblockingServer.java should be AtomicLong to fix FD leakage and general server malfunction - [THRIFT-1187](https://issues.apache.org/jira/browse/THRIFT-1187) - nonblocking_server shutdown race under Ruby 1.9 - [THRIFT-1178](https://issues.apache.org/jira/browse/THRIFT-1178) - Java: TBase signature should be T extends TBase - [THRIFT-1164](https://issues.apache.org/jira/browse/THRIFT-1164) - Segmentation fault on NULL pointer in t_js_generator::generate_const - [THRIFT-1171](https://issues.apache.org/jira/browse/THRIFT-1171) - Perl write/readDouble assumes little-endian platform - [THRIFT-1222](https://issues.apache.org/jira/browse/THRIFT-1222) - Unhandled exception for TEvhttpServer request - [THRIFT-1220](https://issues.apache.org/jira/browse/THRIFT-1220) - TProcessor::process never returns false - [THRIFT-1285](https://issues.apache.org/jira/browse/THRIFT-1285) - Stable 0.7.0 Windows compiler exe available on the webside is not the good one - [THRIFT-1218](https://issues.apache.org/jira/browse/THRIFT-1218) - c_glib uses wrong name in pkg-config - [THRIFT-1215](https://issues.apache.org/jira/browse/THRIFT-1215) - Undefined property Thirft in lib/js/thrift.js - [THRIFT-1211](https://issues.apache.org/jira/browse/THRIFT-1211) - When using THttpClient, non 200 responses leave the connection open - [THRIFT-1228](https://issues.apache.org/jira/browse/THRIFT-1228) - The php accelerator module calls flush incorrectly - [THRIFT-1308](https://issues.apache.org/jira/browse/THRIFT-1308) - libfb303-0.7.0.jar missing in maven repository - [THRIFT-1255](https://issues.apache.org/jira/browse/THRIFT-1255) - Mismatch of method name between JavaME's lib and generated code (compareTo/compareObjects) - [THRIFT-1253](https://issues.apache.org/jira/browse/THRIFT-1253) - Code generated for maps is not compiling - [THRIFT-1252](https://issues.apache.org/jira/browse/THRIFT-1252) - Segfault in Ruby deserializer - [THRIFT-1094](https://issues.apache.org/jira/browse/THRIFT-1094) - bug in TCompactProto python readMessageEnd method and updated test cases - [THRIFT-1093](https://issues.apache.org/jira/browse/THRIFT-1093) - several bugs in python TCompactProtocol - [THRIFT-1092](https://issues.apache.org/jira/browse/THRIFT-1092) - generated validate() method has wrong indentation - [THRIFT-1011](https://issues.apache.org/jira/browse/THRIFT-1011) - Error generating package imports when using classes from other packages - [THRIFT-1050](https://issues.apache.org/jira/browse/THRIFT-1050) - Declaring an argument named "manager" to a service method produces code that fails compile due to name conflicts with protected ivars in TAsyncClient - [THRIFT-1074](https://issues.apache.org/jira/browse/THRIFT-1074) - .keystore and .truststore are missing from the 0.6.0 distribution - [THRIFT-1067](https://issues.apache.org/jira/browse/THRIFT-1067) - Tons of bugs in php implementation - [THRIFT-1065](https://issues.apache.org/jira/browse/THRIFT-1065) - Unexpected exceptions not proper handled on JS - [THRIFT-1076](https://issues.apache.org/jira/browse/THRIFT-1076) - Erlang Thrift socket server has a bug that causes java thrift client of framed binary client to throw "out of sequence" exception - [THRIFT-1057](https://issues.apache.org/jira/browse/THRIFT-1057) - casts in TBinaryProtocol.tcc causing "dereferencing type-punned pointer will break strict-aliasing rules" warnings from gcc - [THRIFT-1055](https://issues.apache.org/jira/browse/THRIFT-1055) - csharp TServerSocket and TSocket do not disable Nagle via Socket.NoDelay = true like cpp and java do - [THRIFT-1054](https://issues.apache.org/jira/browse/THRIFT-1054) - explicit call to PKG_PROG_PKG_CONFIG is missing and first use of PKG_CHECK_MODULES may not happen, causes mono detection to fail - [THRIFT-1117](https://issues.apache.org/jira/browse/THRIFT-1117) - JavaScript Unit Test does not work anymore because libthrift*.jar where moved by Maven Deployment - [THRIFT-1111](https://issues.apache.org/jira/browse/THRIFT-1111) - The HTML generator does not distinguish between string and binary types - [THRIFT-1032](https://issues.apache.org/jira/browse/THRIFT-1032) - "make dist" fails due to c_glib problem - [THRIFT-1036](https://issues.apache.org/jira/browse/THRIFT-1036) - Auto-generated C++ code fails to compile with "-Werror -Wextra -Wall" g++ compiler flags - [THRIFT-1041](https://issues.apache.org/jira/browse/THRIFT-1041) - TDeserializer holds onto a reference of the array it reads after it is done deserializing - [THRIFT-1106](https://issues.apache.org/jira/browse/THRIFT-1106) - C++ code TAsyncProtocolProcessor.h & TAsyncBufferProcessor.h dont have virtual functions but no virtual destructor. Causes warnings on -Wall - [THRIFT-1105](https://issues.apache.org/jira/browse/THRIFT-1105) - OCaml generator does not prefix methods of included structs with their type - [THRIFT-1104](https://issues.apache.org/jira/browse/THRIFT-1104) - INSTALLDIRS should be included in configure script - [THRIFT-1102](https://issues.apache.org/jira/browse/THRIFT-1102) - typo in configure.ac: "==" operator in 'test' (instead of"'=") - [THRIFT-1101](https://issues.apache.org/jira/browse/THRIFT-1101) - bytebuffer length calculation in TBinaryProtocol writeBinary - [THRIFT-1098](https://issues.apache.org/jira/browse/THRIFT-1098) - Undefined properties in TBinaryProtocolFactory - [THRIFT-1081](https://issues.apache.org/jira/browse/THRIFT-1081) - PHP tests broken and somewhat incomplete - [THRIFT-1080](https://issues.apache.org/jira/browse/THRIFT-1080) - erlang test's 'make' fails on Mac OSX - [THRIFT-1078](https://issues.apache.org/jira/browse/THRIFT-1078) - ThriftTest.thrift generates invalid PHP library - [THRIFT-1120](https://issues.apache.org/jira/browse/THRIFT-1120) - proto.WriteListEnd being called in the wrong place - [THRIFT-1119](https://issues.apache.org/jira/browse/THRIFT-1119) - TJSONProtocol fails to UTF8 decode strings - [THRIFT-867](https://issues.apache.org/jira/browse/THRIFT-867) - PHP accelerator module's output transport is incompatible with TFramedTransport - [THRIFT-826](https://issues.apache.org/jira/browse/THRIFT-826) - PHP TSocket Write Timeout - [THRIFT-835](https://issues.apache.org/jira/browse/THRIFT-835) - Bad AS3 syntax in constructors that set default values - [THRIFT-788](https://issues.apache.org/jira/browse/THRIFT-788) - thrift_protocol.so: multiget/multiget_slice does not handle more than 17 keys correctly - [THRIFT-125](https://issues.apache.org/jira/browse/THRIFT-125) - OCaml libraries don't compile with 32-bit ocaml - [THRIFT-342](https://issues.apache.org/jira/browse/THRIFT-342) - PHP: can't have sets of complex types - [THRIFT-731](https://issues.apache.org/jira/browse/THRIFT-731) - configure doesn't check for ant >= 1.7 - [THRIFT-690](https://issues.apache.org/jira/browse/THRIFT-690) - Update TApplicationException codes - [THRIFT-638](https://issues.apache.org/jira/browse/THRIFT-638) - BufferedTransport + C extensions block until recv timeout is reached on last fread call ### Dependency upgrade - [THRIFT-1177](https://issues.apache.org/jira/browse/THRIFT-1177) - Update thrift to reflect changes in Go's networking libraries ### Improvement - [THRIFT-1155](https://issues.apache.org/jira/browse/THRIFT-1155) - Remove log4j dependency from java client - [THRIFT-1151](https://issues.apache.org/jira/browse/THRIFT-1151) - Produce more informative runtime error in case of schema and data mismatch during serialization - [THRIFT-1207](https://issues.apache.org/jira/browse/THRIFT-1207) - Support DESTDIR on "make install" of ruby libs - [THRIFT-1199](https://issues.apache.org/jira/browse/THRIFT-1199) - Union structs should have generated methods to test whether a specific field is currently set - [THRIFT-1233](https://issues.apache.org/jira/browse/THRIFT-1233) - Remove unused include in generated C++ code - [THRIFT-1189](https://issues.apache.org/jira/browse/THRIFT-1189) - Ruby deserializer speed improvements - [THRIFT-1170](https://issues.apache.org/jira/browse/THRIFT-1170) - Thrift Generated Code and Java 5 - [THRIFT-1174](https://issues.apache.org/jira/browse/THRIFT-1174) - Publish as3 client implementation via Maven for use by flex-mojos users - [THRIFT-1225](https://issues.apache.org/jira/browse/THRIFT-1225) - TCompactProtocol for PHP - [THRIFT-1221](https://issues.apache.org/jira/browse/THRIFT-1221) - Remove SimpleCallback.h - [THRIFT-1217](https://issues.apache.org/jira/browse/THRIFT-1217) - Use evutil_socketpair instead of pipe (Windows port) - [THRIFT-1216](https://issues.apache.org/jira/browse/THRIFT-1216) - build Java Library behind a proxy - [THRIFT-1231](https://issues.apache.org/jira/browse/THRIFT-1231) - Remove bogus include - [THRIFT-1213](https://issues.apache.org/jira/browse/THRIFT-1213) - Membuffer should provide a way to get back the buffer - [THRIFT-1237](https://issues.apache.org/jira/browse/THRIFT-1237) - Java fb303 missing some methods - [THRIFT-1063](https://issues.apache.org/jira/browse/THRIFT-1063) - Fix Erlang Tutorial Files - [THRIFT-1053](https://issues.apache.org/jira/browse/THRIFT-1053) - Make remote client's IP address available for all socket related transports - [THRIFT-1109](https://issues.apache.org/jira/browse/THRIFT-1109) - Deploy fb303 along side libthrift to maven repo - [THRIFT-1107](https://issues.apache.org/jira/browse/THRIFT-1107) - improvement for compiler-generated python for 'None' object comparisons - [THRIFT-1069](https://issues.apache.org/jira/browse/THRIFT-1069) - Add command line option to prevent thrift from inserting gen-* directories - [THRIFT-1049](https://issues.apache.org/jira/browse/THRIFT-1049) - Allow for TServerSocket python library to bind to a specific host - [THRIFT-1126](https://issues.apache.org/jira/browse/THRIFT-1126) - Extending struct_info for erlang bindings - [THRIFT-1100](https://issues.apache.org/jira/browse/THRIFT-1100) - python TSSLSocket improvements, including certificate validation - [THRIFT-994](https://issues.apache.org/jira/browse/THRIFT-994) - Don't try to invoke phpize if we don't have it - [THRIFT-993](https://issues.apache.org/jira/browse/THRIFT-993) - Some improvements in C++ stubs for oneway operations - [THRIFT-997](https://issues.apache.org/jira/browse/THRIFT-997) - Using valueOf for base types in getFieldValue - [THRIFT-418](https://issues.apache.org/jira/browse/THRIFT-418) - Don't do runtime sorting of struct fields - [THRIFT-151](https://issues.apache.org/jira/browse/THRIFT-151) - TSSLServerSocket and TSSLSocket implementation - [THRIFT-27](https://issues.apache.org/jira/browse/THRIFT-27) - Generated erlang types don't contain default values for records - [THRIFT-113](https://issues.apache.org/jira/browse/THRIFT-113) - to-string methods should omit optional null fields from output - [THRIFT-363](https://issues.apache.org/jira/browse/THRIFT-363) - Maven Deploy - [THRIFT-447](https://issues.apache.org/jira/browse/THRIFT-447) - Make an abstract base Client class so we can generate less code - [THRIFT-627](https://issues.apache.org/jira/browse/THRIFT-627) - should c++ have setters for optional fields? ### New Feature - [THRIFT-1236](https://issues.apache.org/jira/browse/THRIFT-1236) - Erlang Reconnecting Thrift Client - [THRIFT-1021](https://issues.apache.org/jira/browse/THRIFT-1021) - Framed transport support for OCaml - [THRIFT-1068](https://issues.apache.org/jira/browse/THRIFT-1068) - Python SSL Socket Support - [THRIFT-1103](https://issues.apache.org/jira/browse/THRIFT-1103) - TZlibTransport for python, a zlib compressed transport - [THRIFT-1083](https://issues.apache.org/jira/browse/THRIFT-1083) - Preforking python process pool server - [THRIFT-999](https://issues.apache.org/jira/browse/THRIFT-999) - Add TForkingServer ### Sub-task - [THRIFT-1152](https://issues.apache.org/jira/browse/THRIFT-1152) - Attributes from private to protected - [THRIFT-1038](https://issues.apache.org/jira/browse/THRIFT-1038) - Generated Java code for structures containing binary fields (or collections thereof) are not serializable (in the Java sense) even though they implement java.io.Serializable ### Task - [THRIFT-892](https://issues.apache.org/jira/browse/THRIFT-892) - Refactor erlang build system with rebar ### Wish - [THRIFT-625](https://issues.apache.org/jira/browse/THRIFT-625) - Add support for 'Go' ## 0.6.1 ### Bug - [THRIFT-1133](https://issues.apache.org/jira/browse/THRIFT-1133) - Java and JavaScript tutorial is broken since we have Java maven deployment - [THRIFT-1131](https://issues.apache.org/jira/browse/THRIFT-1131) - C# JSON Protocol is unable to decode escaped characters in string - [THRIFT-1074](https://issues.apache.org/jira/browse/THRIFT-1074) - .keystore and .truststore are missing from the 0.6.0 distribution ### Improvement - [THRIFT-1109](https://issues.apache.org/jira/browse/THRIFT-1109) - Deploy fb303 along side libthrift to maven repo - [THRIFT-363](https://issues.apache.org/jira/browse/THRIFT-363) - Maven Deploy ### Question - [THRIFT-1206](https://issues.apache.org/jira/browse/THRIFT-1206) - did the THRIFT 0.6.1 merge THRIFT-563 ? ### Sub-task - [THRIFT-1163](https://issues.apache.org/jira/browse/THRIFT-1163) - How can i use multi service in one program? ### Task - [THRIFT-1112](https://issues.apache.org/jira/browse/THRIFT-1112) - Apply THRIFT-363 to 0.6 branch - [THRIFT-1113](https://issues.apache.org/jira/browse/THRIFT-1113) - Apply THRIFT-1074 to 0.6 branch ## 0.6 ### Bug - [THRIFT-1020](https://issues.apache.org/jira/browse/THRIFT-1020) - OCaml compiler generates invalid OCaml - [THRIFT-1015](https://issues.apache.org/jira/browse/THRIFT-1015) - TUnion does not handle ByteBuffer in toString - [THRIFT-1013](https://issues.apache.org/jira/browse/THRIFT-1013) - generated java code may have name clashes with thrift library - [THRIFT-1009](https://issues.apache.org/jira/browse/THRIFT-1009) - TUnion does not correctly deep copy a ByteBuffer - [THRIFT-1032](https://issues.apache.org/jira/browse/THRIFT-1032) - "make dist" fails due to c_glib problem - [THRIFT-868](https://issues.apache.org/jira/browse/THRIFT-868) - Referencing constant values doesn't work with with typedef types - [THRIFT-971](https://issues.apache.org/jira/browse/THRIFT-971) - java module can't be compiled without ivy and network connection - [THRIFT-970](https://issues.apache.org/jira/browse/THRIFT-970) - Under heavy load, THttpClient may fail with "too many open files" - [THRIFT-969](https://issues.apache.org/jira/browse/THRIFT-969) - Java Tutorial broken, move CalculatorHandler to a separate file - [THRIFT-807](https://issues.apache.org/jira/browse/THRIFT-807) - JavaScript: Initialization of Base Types with 0 instead of null - [THRIFT-955](https://issues.apache.org/jira/browse/THRIFT-955) - Thrift compiler for Windows uses lowercase names and directories which is inconsistent with compiling on other platforms - [THRIFT-992](https://issues.apache.org/jira/browse/THRIFT-992) - Naming convention in C# constructor is not consistent with other fields causes compile errors - [THRIFT-1008](https://issues.apache.org/jira/browse/THRIFT-1008) - byte[] accessors throw NPE on unset field - [THRIFT-1006](https://issues.apache.org/jira/browse/THRIFT-1006) - Impossible to correctly qualify an enum constant in an external thrift file - [THRIFT-950](https://issues.apache.org/jira/browse/THRIFT-950) - Haskell bindings treat 'byte' as unsigned 8-bit int (Data.Word.Word8), java/cpp as signed (byte/int8_t). - [THRIFT-975](https://issues.apache.org/jira/browse/THRIFT-975) - lib/c_glib/README is missing => breaks make dist - [THRIFT-944](https://issues.apache.org/jira/browse/THRIFT-944) - Support all version-4s of base - [THRIFT-939](https://issues.apache.org/jira/browse/THRIFT-939) - optional binary fields throw NPE on default byte[] getters - [THRIFT-935](https://issues.apache.org/jira/browse/THRIFT-935) - PHP Extension aborts the build if php-config is not installed - [THRIFT-933](https://issues.apache.org/jira/browse/THRIFT-933) - Haskell's Thrift.cabal has warnings - [THRIFT-932](https://issues.apache.org/jira/browse/THRIFT-932) - Haskell tests need to be run through 'make check' (and probably 'cabal check') too - [THRIFT-904](https://issues.apache.org/jira/browse/THRIFT-904) - C# TSocket should disable nagle and linger - [THRIFT-941](https://issues.apache.org/jira/browse/THRIFT-941) - Make PHP C Extension use the defined Protocol writeMessageBegin function - [THRIFT-940](https://issues.apache.org/jira/browse/THRIFT-940) - 'make check' fails if boost is not in the std include and link paths - [THRIFT-924](https://issues.apache.org/jira/browse/THRIFT-924) - Fix generated php structure constants - [THRIFT-979](https://issues.apache.org/jira/browse/THRIFT-979) - ruby bindings used to work on jruby - [THRIFT-977](https://issues.apache.org/jira/browse/THRIFT-977) - Hex Conversion Bug in C++ TJSONProtocol - [THRIFT-347](https://issues.apache.org/jira/browse/THRIFT-347) - PHP TSocket Timeout Issues - [THRIFT-517](https://issues.apache.org/jira/browse/THRIFT-517) - TExceptions thrown by server result in cryptic error message on client) - Tried to read 4 bytes, but only got 0 bytes ### Improvement - [THRIFT-1024](https://issues.apache.org/jira/browse/THRIFT-1024) - Add Python Twisted example to the Tutorial - [THRIFT-958](https://issues.apache.org/jira/browse/THRIFT-958) - Change accessmodifer on trans_ field in the FrameBuffer class to public. - [THRIFT-957](https://issues.apache.org/jira/browse/THRIFT-957) - THsHaServer: Change access modifier of the invoker field. - [THRIFT-1002](https://issues.apache.org/jira/browse/THRIFT-1002) - CodeStyle: t_c_glib_generator.cc - [THRIFT-1005](https://issues.apache.org/jira/browse/THRIFT-1005) - Give unions byte[] signature methods to go along with their ByteBuffer counterparts - [THRIFT-951](https://issues.apache.org/jira/browse/THRIFT-951) - Add a new isServing() method to TServer - [THRIFT-943](https://issues.apache.org/jira/browse/THRIFT-943) - Silly readme typo fix. - [THRIFT-961](https://issues.apache.org/jira/browse/THRIFT-961) - JavaScript TestSuite using ant/ivy and Java's ServerTestBase Handler - [THRIFT-960](https://issues.apache.org/jira/browse/THRIFT-960) - add TestServer, TestNonblockingServer and TestClient again - [THRIFT-949](https://issues.apache.org/jira/browse/THRIFT-949) - Modify the TEnum interface so it defines a method similar to findByValue - [THRIFT-946](https://issues.apache.org/jira/browse/THRIFT-946) - Augment FieldValueMetaData so it differentiates 'string' and 'binary' fields. - [THRIFT-903](https://issues.apache.org/jira/browse/THRIFT-903) - custom ThreadFactory in THsHaServer - [THRIFT-913](https://issues.apache.org/jira/browse/THRIFT-913) - Test Case for Url encoded strings + simple enhancement to lib/js/test/RunTestServer.sh - [THRIFT-926](https://issues.apache.org/jira/browse/THRIFT-926) - Miscellaneous C++ improvements - [THRIFT-929](https://issues.apache.org/jira/browse/THRIFT-929) - Improvements to the C++ test suite - [THRIFT-893](https://issues.apache.org/jira/browse/THRIFT-893) - add JavaScript to the tutorial examples - [THRIFT-1003](https://issues.apache.org/jira/browse/THRIFT-1003) - Polishing c_glib code - [THRIFT-71](https://issues.apache.org/jira/browse/THRIFT-71) - Debian packaging for thrift ### New Feature - [THRIFT-1033](https://issues.apache.org/jira/browse/THRIFT-1033) - Node.js language target - [THRIFT-947](https://issues.apache.org/jira/browse/THRIFT-947) - Provide a helper method to determine the TProtocol used to serialize some data. - [THRIFT-928](https://issues.apache.org/jira/browse/THRIFT-928) - Make more statistics available in C++ servers - [THRIFT-922](https://issues.apache.org/jira/browse/THRIFT-922) - Templatized [de]serialization code for C++ - [THRIFT-923](https://issues.apache.org/jira/browse/THRIFT-923) - Event-driven client and server support for C++ - [THRIFT-925](https://issues.apache.org/jira/browse/THRIFT-925) - Provide name<->value map for enums in C++ - [THRIFT-927](https://issues.apache.org/jira/browse/THRIFT-927) - Add option to modify the PHP include path - [THRIFT-377](https://issues.apache.org/jira/browse/THRIFT-377) - TFileTransport port in Java - [THRIFT-106](https://issues.apache.org/jira/browse/THRIFT-106) - TSSLServerSocket - [THRIFT-582](https://issues.apache.org/jira/browse/THRIFT-582) - C implementation of Thrift - [THRIFT-745](https://issues.apache.org/jira/browse/THRIFT-745) - Make it easier to instantiate servers ### Sub-task - [THRIFT-1038](https://issues.apache.org/jira/browse/THRIFT-1038) - Generated Java code for structures containing binary fields (or collections thereof) are not serializable (in the Java sense) even though they implement java.io.Serializable ### Task - [THRIFT-862](https://issues.apache.org/jira/browse/THRIFT-862) - Async client issues / improvements ### Test - [THRIFT-581](https://issues.apache.org/jira/browse/THRIFT-581) - Add a testsuite for txThrift (Twisted) ## Incubating Versions Thrift 0.5.0) - Incubating -------------------------------------------------------------------------------- THRIFT-505 Build Make configure give a summary of the enabled components (David Reiss) THRIFT-506 Build Allow Thrift to be built without the C++ library (David Reiss) THRIFT-844 Build Build Requirements state autoconf 2.59+ is required, but 2.60+ is needed (Harlan Lieberman-Berg) THRIFT-850 Build Perl runtime requires Bit::Vector which may not be installed by default, but configure does not fail (Michael Lum) THRIFT-854 Build Provide configure option and make rules to build/install php extension (Anthony Molinaro) THRIFT-858 Build Have bootstrap.sh check for a suitable autoconf version before running (David Reiss) THRIFT-871 Build Thrift compiler for WIndows (binary distribution) (David Reiss) THRIFT-323 C# TJSONProtocol (Roger Meier) THRIFT-634 C# C# Compiler Generates Incorrect Code For Fields which begin with an uppercase letter (Jon S Akhtar) THRIFT-881 C# add csharp to the tutorial (Roger Meier) THRIFT-856 C++ Building cpp library fails on OS X with malloc and free not being declared in scope (James Clarke) THRIFT-865 C++ C++ compiler build depends on libfl even when flex/lex not detected (David Reiss) THRIFT-900 C++ Unix domain socket (Roger Meier) THRIFT-920 C++ C++ Test and Tutorial does not compile anymore due to the change within Enum handling (Roger Meier) THRIFT-567 C++ Can't immediately stop a TSimpleServer thread that is idle (Rush Manbert) THRIFT-756 C++ Exposing TSocket(int) constructor to public (Rajat Goel) THRIFT-798 C++ TNonblockingServer leaks resources when destroyed (David Reiss) THRIFT-812 C++, Python Demo of Thrift over ZeroMQ (David Reiss) THRIFT-629 Cocoa Unused Field In TSocketServer Appears To Break iPhone Build (Jon S Akhtar) THRIFT-838 Cocoa Generated Cocoa classes have useless @dynamic declarations (Kevin Ballard) THRIFT-805 Cocoa Don't generate process_XXXX methods for oneway methods (Brad Taylor) THRIFT-507 Compiler Remove the compiler's dependency on Boost (David Reiss) THRIFT-895 Compiler (General) Thrift compiler does not allow two different enumerations to have the same key name for one of the enum values (David Reiss) THRIFT-852 Compiler (General) Missing newline causes many compiler warnings (Anthony Molinaro) THRIFT-877 Compiler (General) smalltalk namespace doesn't work (Bruce Lowekamp) THRIFT-897 Compiler (General) Don't allow unqualified constant access to enum values (Bryan Duxbury) THRIFT-9 Compiler (General) Add a default namespace declaration for all languages (David Reiss) THRIFT-599 Erlang Don't use unnecessary processes in the Erlang transports and clients (David Reiss) THRIFT-646 Erlang Erlang library is missing install target (David Reiss) THRIFT-698 Erlang Generated module list should contain atoms, not strings (Anthony Molinaro) THRIFT-866 Erlang term() in spec definitions seems to not work in erlang R12 (Anthony Molinaro) THRIFT-886 Erlang Dialyzer warning (Anthony Molinaro) THRIFT-785 Erlang Framed transport server problems (Anthony Molinaro) THRIFT-884 HTML HTML Generator: add Key attribute to the Data Types Tables (Roger Meier) THRIFT-652 Haskell Generated field name for strut is not capitalized correctly (Christian Lavoie) THRIFT-743 Haskell compile error with GHC 6.12.1 (Christian Lavoie) THRIFT-901 Haskell Allow the bindings to compile without -fglasgow-exts and with -Wall -Werror (Christian Lavoie) THRIFT-905 Haskell Make haskell thrift bindings use automake to compile and install (Christian Lavoie) THRIFT-906 Haskell Improve type mappings (Christian Lavoie) THRIFT-914 Haskell Make haskell bindings 'easily' compilable (Christian Lavoie) THRIFT-918 Haskell Make haskell tests run again (Christian Lavoie) THRIFT-919 Haskell Update Haskell bindings README (Christian Lavoie) THRIFT-787 Haskell Enums are not read correctly (Christian Lavoie) THRIFT-250 Java ExecutorService as a constructor parameter for TServer (Ed Ceaser) THRIFT-693 Java Thrift compiler generated java code that throws compiler warnings about deprecated methods. (Bryan Duxbury) THRIFT-843 Java TNonblockingSocket connects without a timeout (Bryan Duxbury) THRIFT-845 Java async client does not respect timeout (Ning Liang) THRIFT-870 Java Java constants don't get Javadoc comments (Bryan Duxbury) THRIFT-873 Java Java tests fail due to Too many open files (Todd Lipcon) THRIFT-876 Java Add SASL support (Aaron T. Myers) THRIFT-879 Java Remove @Override from TUnion.clear (Dave Engberg) THRIFT-882 Java deep copy of binary fields does not copy ByteBuffer characteristics (arrayOffset, position) (Bryan Duxbury) THRIFT-888 Java async client should also have nonblocking connect (Eric Jensen) THRIFT-890 Java Java tutorial doesn't work (Todd Lipcon) THRIFT-894 Java Make default accessors for binary fields return byte[]; provide new accessors to get ByteBuffer version (Bryan Duxbury) THRIFT-896 Java TNonblockingSocket.isOpen() returns true even after close() (Eric Jensen) THRIFT-907 Java libfb303 doesn't compile in 0.4.0 (Todd Lipcon) THRIFT-912 Java Improvements and bug fixes to SASL implementation (Todd Lipcon) THRIFT-917 Java THsHaServer should not accept an ExecutorService without catching RejectedExecutionException (Ed Ceaser) THRIFT-931 Java Use log4j for Java tests (Todd Lipcon) THRIFT-880 JavaME JavaME code generator and runtime library (Dave Engberg) THRIFT-846 JavaScript JavaScript Test Framwork: extended Testcases (Roger Meier) THRIFT-885 JavaScript Url encoded strings never get decoded? How do we fix this? (T Jake Luciani) THRIFT-911 JavaScript (JavaScript compiler) Const structs, maps, sets, and lists generate a trailing comma (T Jake Luciani) THRIFT-860 OCaml copy method and reset method (Lev Walkin) THRIFT-682 PHP PHP extension doesn't compile on Mac OS X (Bryan Duxbury) THRIFT-851 PHP php extension fails to compile on centos 5.x (Todd Lipcon) THRIFT-840 Perl Perl protocol handler could be more robust against unrecognised types (Conrad Hughes) THRIFT-758 Perl incorrect deference in exception handling (Yann Kerherve) THRIFT-257 Python Support validation of required fields (Esteve Fernandez) THRIFT-335 Python Compact Protocol for Python (David Reiss) THRIFT-596 Python Make Python's TBufferedTransport use a configurable input buffer (David Reiss) THRIFT-597 Python Python THttpServer performance improvements (David Reiss) THRIFT-598 Python Allow Python's threading servers to use daemon threads (David Reiss) THRIFT-666 Python Allow the handler to override HTTP responses in THttpServer (David Reiss) THRIFT-673 Python Generated Python code has whitespace issues (Ian Eure) THRIFT-721 Python THttpClient ignores url parameters (Thomas Kho) THRIFT-824 Python TApplicationException.__str__() refers to class constants as globals (Peter Schuller) THRIFT-855 Python Include optimized compiled python objects in install (Anthony Molinaro) THRIFT-859 Python Allow py:twisted to be generated in different namespace than py (Bruce Lowekamp) THRIFT-869 Python TSocket.py on Mac (and FreeBSD) doesn't handle ECONNRESET from recv() (Steven Knight) THRIFT-875 Python Include python setup.cfg in dist (Anthony Molinaro) THRIFT-610 Ruby binary_protocol.rb segfaults [line 86] (Unassigned) THRIFT-899 Ruby Ruby read timeouts can sometimes be 2x what they should be (Ryan King) THRIFT-909 Ruby allow block argument to struct constructor (Michael Stockton) THRIFT-456 Test Suite Bad IP address string in test/cpp/src/main.cpp (Rush Manbert) Thrift 0.4.0) - Incubating -------------------------------------------------------------------------------- THRIFT-650 Build Make Check fails on Centos/OSX with 0.2.0 tarball (Anthony Molinaro) THRIFT-770 Build Get 'make dist' to work without first compiling source code (Anthony Molinaro) THRIFT-160 C# Created THttpTransport for the C# library based on WebHttpRequest (Michael Greene) THRIFT-834 C# THttpClient resends contents of message after transport errors (Anatoly Fayngelerin) THRIFT-247 C++ THttpServer Transport (Unassigned) THRIFT-676 C++ Change C++ code generator so that generated classes can be wrapped with SWIG (Unassigned) THRIFT-570 Compiler Thrift compiler does not error when duplicate method names are present (Bruce Simpson) THRIFT-808 Compiler Segfault when constant declaration references a struct field that doesn't exist (Bryan Duxbury) THRIFT-646 Erlang Erlang library is missing install target (Anthony Molinaro) THRIFT-544 General multiple enums with the same key generate invalid code (Ben Taitelbaum) THRIFT-434 General ruby compiler should warn when a reserved word is used (Michael Stockton) THRIFT-799 General Files missing proper Apache license header (Bryan Duxbury) THRIFT-832 HTML HTML generator shows unspecified struct fields as 'required' (Bryan Duxbury) THRIFT-226 Java Collections with binary keys or values break equals() (Bryan Duxbury) THRIFT-484 Java Ability to use a slice of a buffer instead of a direct byte[] for binary fields (Bryan Duxbury) THRIFT-714 Java maxWorkerThreads parameter to THsHaServer has no effect (Bryan Duxbury) THRIFT-751 Java Add clear() method to TBase (Bryan Duxbury) THRIFT-765 Java Improved string encoding and decoding performance (Bryan Duxbury) THRIFT-768 Java Async client for Java (Bryan Duxbury) THRIFT-774 Java TDeserializer should provide a partialDeserialize method for primitive types (Piotr Kozikowski) THRIFT-783 Java .equals java method is broken on structs containing binary-type fields (Unassigned) THRIFT-804 Java CompareTo is broken for unions set to map, set, or list (Bryan Duxbury) THRIFT-814 Java Include a TServlet in the standard Thrift distribution (Mathias Herberts) THRIFT-818 Java Async client doesn't send method args (Bryan Duxbury) THRIFT-830 Java Switch binary field implementation from byte[] to ByteBuffer (Bryan Duxbury) THRIFT-831 Java FramedTransport implementation that reuses its buffers (Bryan Duxbury) THRIFT-833 Java build.xml in lib/java is missing a classpathref attribute for the javadoc task (Bryan Duxbury) THRIFT-836 Java Race condition causes CancelledKeyException in TAsyncClientManager (Bryan Duxbury) THRIFT-842 Java Upgrade to current version of commons-lang (2.5 instead of 2.4) and/or change dependency in ivy.xml to not be exact (Bryan Duxbury) THRIFT-815 JavaScript Deserialization of lists is critically broken. (T Jake Luciani) THRIFT-827 OCaml OCaml generator to take default values into account (Lev Walkin) THRIFT-647 PHP PHP library is missing install target (Anthony Molinaro) THRIFT-682 PHP PHP extension doesn't compile on Mac OS X (Bryan Duxbury) THRIFT-718 PHP Thrift PHP library includes closing tags and extraneous whitespace (Nicholas Telford) THRIFT-778 PHP PHP socket listening server (Nick Jones) THRIFT-780 PHP PHP extension sometimes causes an abort with two exceptions at the same time (David Reiss) THRIFT-837 PHP PHP accelerator bug for writes > 8k (Thomas Kho) THRIFT-782 Perl Perl code for writing containers doesn't count length of write*Begin or write*End (Conrad Hughes) THRIFT-395 Python Python library + compiler does not support unicode strings (Unassigned) THRIFT-133 Ruby 'namespace ruby' should error out, or be an alias to 'namespace rb' (Bryan Duxbury) THRIFT-664 Ruby Ruby extension fails to build with Ruby 1.9.1 (Rajesh Malepati) THRIFT-699 Ruby Excise unused "native protocol method table" stuff from thrift_native (Bryan Duxbury) THRIFT-767 Ruby ruby compiler does not keep comments for enum values (Bryan Duxbury) THRIFT-811 Ruby http_client_transport.rb: allow custom http headers (Tony Kamenick) THRIFT-459 Ruby Ruby installation always tries to write to /Library/Ruby/site (Matthieu Imbert) Thrift 0.1.0) - Incubating (not released) -------------------------------------------------------------------------------- Compatibility Breaking Changes: C++: - It's quite possible that regenerating code and rebuilding will be required. Make sure your headers match your libs! Java: Python: Ruby: - Generated files now have underscored names [THRIFT-421] - The library has been rearranged to be more Ruby-like [THRIFT-276] Erlang: - Generated code will have to be regenerated, and the new code will have to be deployed atomically with the new library code [THRIFT-136] New Features and Bug Fixes: C++: - Support for TCompactProtocol [THRIFT-333] Java: - Support for TCompactProtocol [THRIFT-110] Python: - Support for Twisted [THRIFT-148] Ruby: - Support for TCompactProtocol [THRIFT-332] thrift-0.16.0/CMakeLists.txt000066400000000000000000000074011420101504100156240ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # cmake_minimum_required(VERSION 3.4) if(POLICY CMP0048) cmake_policy(SET CMP0048 NEW) # package version behavior added in cmake 3.0 endif() if(POLICY CMP0074) cmake_policy(SET CMP0074 NEW) # find_package behavior added in cmake 3.12 endif() # PACKAGE_VERSION is used by cpack scripts currently # Both thrift_VERSION and PACKAGE_VERSION should be the same for now set(thrift_VERSION "0.16.0") set(PACKAGE_VERSION ${thrift_VERSION}) project("thrift" VERSION ${PACKAGE_VERSION}) message(STATUS "Configuring ${CMAKE_PROJECT_NAME} ${thrift_VERSION}") set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake") # Some default settings include(DefineCMakeDefaults) # Build time options are defined here include(DefineOptions) include(DefineInstallationPaths) # Based on the options set some platform specifics include(DefinePlatformSpecifc) # Add CMake targets for static code analysis include(StaticCodeAnalysis) # Generate the config.h file include(ConfigureChecks) # Generate the ThriftConfig.cmake module include(GenerateConfigModule) # Packaging include(CPackConfig) # Dependencies include(BoostMacros) find_package(Threads) include(CTest) if(BUILD_TESTING) message(STATUS "Building with unittests") enable_testing() # Define "make check" as alias for "make test" add_custom_target(check COMMAND ctest) else () message(STATUS "Building without tests") endif () if(BUILD_COMPILER) if(NOT EXISTS ${THRIFT_COMPILER}) set(THRIFT_COMPILER $) endif() add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/compiler/cpp) elseif(EXISTS ${THRIFT_COMPILER}) add_executable(thrift-compiler IMPORTED) set_property(TARGET thrift-compiler PROPERTY IMPORTED_LOCATION ${THRIFT_COMPILER}) endif() if(BUILD_CPP) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/cpp) if(BUILD_TUTORIALS) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tutorial/cpp) endif() if(BUILD_TESTING) if(WITH_LIBEVENT AND WITH_ZLIB AND WITH_OPENSSL) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/cpp) else() message(WARNING "libevent and/or ZLIB and/or OpenSSL not found or disabled; will not build some tests") endif() endif() endif() if(BUILD_C_GLIB) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/c_glib) if(BUILD_TESTING) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/c_glib) endif() endif() if(BUILD_JAVA) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/java) endif() if(BUILD_JAVASCRIPT) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/js) endif() if(BUILD_NODEJS) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/nodejs) endif() if(BUILD_PYTHON) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/py) if(BUILD_TESTING) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/py) endif() endif() # Create the uninstall target add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${PROJECT_SOURCE_DIR}/build/cmake/uninstall.cmake") PRINT_CONFIG_SUMMARY() thrift-0.16.0/CONTRIBUTING.md000066400000000000000000000164721420101504100153250ustar00rootroot00000000000000# How to Contribute # Thank you for your interest in contributing to the Apache Thrift project! Information on why and how to contribute is available on the Apache Software Foundation (ASF) web site. In particular, we recommend the following to become acquainted with Apache Contributions: * [Contributors Tech Guide](http://www.apache.org/dev/contributors) * [Get involved!](http://www.apache.org/foundation/getinvolved.html) * [Legal aspects on Submission of Contributions (Patches)](http://www.apache.org/licenses/LICENSE-2.0.html#contributions) ## GitHub pull requests ## This is the preferred method of submitting changes. When you submit a pull request through github, it activates the continuous integration (CI) build systems at Appveyor and Travis to build your changesxi on a variety of Linux and Windows configurations and run all the test suites. Follow these requirements for a successful pull request: 1. All significant changes require an [Apache Jira THRIFT Issue](http://issues.apache.org/jira/browse/THRIFT) ticket. Trivial changes such as fixing a typo or a compiler warning do not. 1. All pull requests should contain a single commit per issue, or we will ask you to squash it. 1. The pull request title must begin with the Jira THRIFT ticket identifier if it has an associated ticket, for example: THRIFT-9999: an example pull request title 1. Commit messages must follow this pattern for code changes (deviations will not be merged): THRIFT-9999: [summary of fix, one line if possible] Client: [language(s) affected, comma separated, for example: "cpp,erl,perl"] Instructions: 1. Create a fork in your GitHub account of http://github.com/apache/thrift 1. Clone the fork to your development system. 1. Create a branch for your changes (best practice is issue as branch name, e.g. THRIFT-9999). 1. Modify the source to include the improvement/bugfix, and: * Remember to provide *tests* for all submitted changes! * Use test-driven development (TDD): add a test that will isolate the bug *before* applying the change that fixes it. * Verify that you follow [Thrift Coding Standards](/docs/coding_standards) (you can run 'make style', which ensures proper format for some languages). * [*optional*] Verify that your change works on other platforms by adding a GitHub service hook to [Travis CI](http://docs.travis-ci.com/user/getting-started/#Step-one%3A-Sign-in) and [AppVeyor](http://www.appveyor.com/docs). You can use this technique to run the Thrift CI jobs in your account to check your changes before they are made public. Every GitHub pull request into Thrift will run the full CI build and test suite on your changes. 1. Squash your changes to a single commit. This maintains clean change history. 1. Commit and push changes to your branch (please use issue name and description as commit title, e.g. "THRIFT-9999: make it perfect"), with the affected languages on the next line of the description. 1. Use GitHub to create a pull request going from your branch to apache:master. Ensure that the Jira ticket number is at the beginning of the title of your pull request, same as the commit title. 1. Wait for other contributors or committers to review your new addition, and for a CI build to complete. 1. Wait for a committer to commit your patch. You can nudge the committers if necessary by sending a message to the [Apache Thrift mailing list](https://thrift.apache.org/mailing). ## If you want to build the project locally ## For Windows systems, see our detailed instructions on the [CMake README](/build/cmake/README.md). For Windows Native C++ builds, see our detailed instructions on the [WinCPP README](/build/wincpp/README.md). For unix systems, see our detailed instructions on the [Docker README](/build/docker/README.md). ## If you want to review open issues... ## 1. Review the [GitHub Pull Request Backlog](https://github.com/apache/thrift/pulls). Code reviews are open to all. 2. Review the [Jira issue tracker](http://issues.apache.org/jira/browse/THRIFT). You can search for tickets relating to languages you are interested in or currently using with thrift, for example a Jira search (Issues -> Search For Issues) query of ``project = THRIFT AND component in ("Erlang - Library") and status not in (resolved, closed)`` will locate all the open Erlang Library issues. ## If you discovered a defect... ## 1. Check to see if the issue is already in the [Jira issue tracker](http://issues.apache.org/jira/browse/THRIFT). 1. If not, create a ticket describing the change you're proposing in the Jira issue tracker. 1. Contribute your code changes using the GitHub pull request method: ## Contributing via Patch ## To create a patch from changes in your local directory: git diff > ../THRIFT-NNNN.patch then wait for contributors or committers to review your changes, and then for a committer to apply your patch. This is not the preferred way to submit changes and incurs additional overhead for committers who must then create a pull request for you. ## GitHub recipes for Pull Requests ## Sometimes commmitters may ask you to take actions in your pull requests. Here are some recipes that will help you accomplish those requests. These examples assume you are working on Jira issue THRIFT-9999. You should also be familiar with the [upstream](https://help.github.com/articles/syncing-a-fork/) repository concept. ### Squash your changes ### If you have not submitted a pull request yet, or if you have not yet rebased your existing pull request, you can squash all your commits down to a single commit. This makes life easier for the committers. If your pull request on GitHub has more than one commit, you should do this. 1. Use the command ``git log`` to identify how many commits you made since you began. 2. Use the command ``git rebase -i HEAD~N`` where N is the number of commits. 3. Leave "pull" in the first line. 4. Change all other lines from "pull" to "fixup". 5. All your changes are now in a single commit. If you already have a pull request outstanding, you will need to do a "force push" to overwrite it since you changed your commit history: git push -u origin THRIFT-9999 --force A more detailed walkthrough of a squash can be found at [Git Ready](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html). ### Rebase your pull request ### If your pull request has a conflict with master, it needs to be rebased: git checkout THRIFT-9999 git rebase upstream master (resolve any conflicts, make sure it builds) git push -u origin THRIFT-9999 --force ### Fix a bad merge ### If your pull request contains commits that are not yours, then you should use the following technique to fix the bad merge in your branch: git checkout master git pull upstream master git checkout -b THRIFT-9999-take-2 git cherry-pick ... (pick only your commits from your original pull request in ascending chronological order) squash your changes to a single commit if there is more than one (see above) git push -u origin THRIFT-9999-take-2:THRIFT-9999 This procedure will apply only your commits in order to the current master, then you will squash them to a single commit, and then you force push your local THRIFT-9999-take-2 into remote THRIFT-9999 which represents your pull request, replacing all the commits with the new one. thrift-0.16.0/LANGUAGES.md000066400000000000000000001276751420101504100147340ustar00rootroot00000000000000# Apache Thrift Language Support # Guidance For: 0.15.0 | [0.14.0](https://github.com/apache/thrift/blob/v0.14.0/LANGUAGES.md) | [0.13.0](https://github.com/apache/thrift/blob/v0.13.0/LANGUAGES.md) | [0.12.0](https://github.com/apache/thrift/blob/v0.12.0/LANGUAGES.md) | [0.11.0](https://github.com/apache/thrift/blob/0.11.0/LANGUAGES.md) Thrift supports many programming languages and has an impressive test suite that exercises most of the languages, protocols, and transports. Each build exercises a matrix of thousands of possible combinations. Each language typically has a minimum required version as well as support libraries - some mandatory and some optional. The information provided below will help you assess whether you can use Apache Thrift with your project. Obviously this is a complex matrix to maintain and may not be correct in all cases - if you spot an error please inform the developers using the mailing list, or better yet, [Edit on GitHub](https://github.com/apache/thrift/edit/master/LANGUAGES.md). Apache Thrift currently uses two build systems. The `autoconf` build system is the most complete and builds all supported languages, however it does not support Windows.. The `cmake` build system works on Linux and Windows, and has been designated by the project to replace `autoconf` however this transition will take quite some time to complete. During that transition, the cmake build will not support all languages. The Language/Library Levels indicate the minimum and maximum versions that are used in the [continuous integration environments](build/docker/README.md) (Appveyor, Travis) for Apache Thrift. Other language levels may be supported for each language, however tested less thoroughly; check the README file inside each lib directory for additional details. Note: while a language may contain support for protocols, transports, and servers, the extent to which each is tested as part of the overall build process varies. The definitive integration test for the project is called the "cross" test which executes a test matrix with clients and servers communicating across languages. Thrift's core transport (supported by all languages) is TSocket. Thrift's core protocol is TBinary, supported by all languages except for JavaScript. thrift-0.16.0/LICENSE000066400000000000000000000361601420101504100140750ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------- SOFTWARE DISTRIBUTED WITH THRIFT: The Apache Thrift software includes a number of subcomponents with separate copyright notices and license terms. Your use of the source code for the these subcomponents is subject to the terms and conditions of the following licenses. -------------------------------------------------- Portions of the following files are licensed under the MIT License: lib/erl/src/Makefile.am Please see doc/otp-base-license.txt for the full terms of this license. -------------------------------------------------- For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components: # Copyright (c) 2007 Thomas Porschberg # # Copying and distribution of this file, with or without # modification, are permitted in any medium without royalty provided # the copyright notice and this notice are preserved. -------------------------------------------------- For the lib/nodejs/lib/thrift/json_parse.js: /* json_parse.js 2015-05-02 Public Domain. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. */ (By Douglas Crockford ) -------------------------------------------------- For lib/cpp/src/thrift/windows/SocketPair.cpp /* socketpair.c * Copyright 2007 by Nathan C. Myers ; some rights reserved. * This code is Free Software. It may be copied freely, in original or * modified form, subject only to the restrictions that (1) the author is * relieved from all responsibilities for any use for any purpose, and (2) * this copyright notice must be retained, unchanged, in its entirety. If * for any reason the author might be held responsible for any consequences * of copying or use, license is withheld. */ -------------------------------------------------- For lib/py/compat/win32/stdint.h // ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2008 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. 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. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. // /////////////////////////////////////////////////////////////////////////////// -------------------------------------------------- Codegen template in t_html_generator.h * Bootstrap v2.0.3 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. --------------------------------------------------- For t_cl_generator.cc * Copyright (c) 2008- Patrick Collison * Copyright (c) 2006- Facebook --------------------------------------------------- thrift-0.16.0/Makefile.am000077500000000000000000000073631420101504100151320ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ACLOCAL_AMFLAGS = -I ./aclocal SUBDIRS = compiler/cpp lib if WITH_TESTS SUBDIRS += test endif if WITH_TUTORIAL SUBDIRS += tutorial endif clean-local: $(RM) -r vendor/ distclean-local: $(RM) -r .dub/ $(RM) -r autom4te.cache/ CLEANFILES = \ composer.lock \ dub.selections.json DISTCLEANFILES = \ Makefile \ Makefile.in \ aclocal.m4 \ apache-thrift-test-library \ autoscan.log \ compile \ config.guess \ config.hin \ config.hin~ \ config.log \ config.status \ config.sub \ configure \ configure.scan \ debcomp \ install-sh \ ltmain.sh \ missing \ ylwrap dist-hook: find $(distdir) -type f \( -iname ".DS_Store" -or -iname "._*" -or -iname ".gitignore" \) | xargs rm -f find $(distdir) -type d \( -iname ".deps" -or -iname ".libs" \) | xargs rm -rf find $(distdir) -type d \( -iname ".svn" -or -iname ".git" \) | xargs rm -rf print-version: @echo $(PACKAGE_VERSION) .PHONY: precross cross precross-%: all $(MAKE) -C $* precross precross: all precross-test precross-lib empty := space := $(empty) $(empty) comma := , CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_CL@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_NETSTD@ @MAYBE_NODETS@ CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS)) if WITH_PY3 CROSS_PY=$(PYTHON3) else CROSS_PY=$(PYTHON) endif if WITH_PYTHON crossfeature: precross $(CROSS_PY) test/test.py --retry-count 5 --features .* --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED) else # feature test needs python build crossfeature: endif cross-%: precross crossfeature $(CROSS_PY) test/test.py --retry-count 5 --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED) --client $(CROSS_LANGS_COMMA_SEPARATED) --regex "$*" cross: cross-.* TIMES = 1 2 3 fail: precross $(CROSS_PY) test/test.py || true $(CROSS_PY) test/test.py --update-expected-failures=overwrite $(foreach var,$(TIMES),test/test.py -s || true;test/test.py --update-expected-failures=merge;) codespell_skip_files = \ *.jar \ *.class \ *.so \ *.a \ *.la \ *.o \ *.p12 \ *OCamlMakefile \ .keystore \ .truststore \ CHANGES \ config.sub \ configure \ depcomp \ libtool.m4 \ output.* \ rebar \ thrift skipped_files = $(subst $(space),$(comma),$(codespell_skip_files)) style-local: codespell --write-changes --skip=$(skipped_files) --disable-colors EXTRA_DIST = \ .asf.yaml \ .clang-format \ .dockerignore \ .editorconfig \ .eslintignore \ .eslintrc.json \ .flake8 \ .gitattributes \ .gitignore \ .travis.yml \ ApacheThrift.nuspec \ appveyor.yml \ bootstrap.sh \ bower.json \ build \ CHANGES.md \ CMakeLists.txt \ composer.json \ contrib \ CONTRIBUTING.md \ debian \ doap.rdf \ doc \ dub.json \ go.mod \ go.sum \ jitpack.yml \ LANGUAGES.md \ LICENSE \ NOTICE \ package.json \ package-lock.json \ phpcs.xml.dist \ README.md \ rust-toolchain \ sonar-project.properties \ Thrift.podspec thrift-0.16.0/NOTICE000066400000000000000000000002561420101504100137710ustar00rootroot00000000000000Apache Thrift Copyright (C) 2006 - 2019, The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). thrift-0.16.0/README.md000066400000000000000000000157261420101504100143540ustar00rootroot00000000000000Apache Thrift ============= Introduction ============ Thrift is a lightweight, language-independent software stack for point-to-point RPC implementation. Thrift provides clean abstractions and implementations for data transport, data serialization, and application level processing. The code generation system takes a simple definition language as input and generates code across programming languages that uses the abstracted stack to build interoperable RPC clients and servers. ![Apache Thrift Layered Architecture](doc/images/thrift-layers.png) Thrift makes it easy for programs written in different programming languages to share data and call remote procedures. With support for [28 programming languages](LANGUAGES.md), chances are Thrift supports the languages that you currently use. Thrift is specifically designed to support non-atomic version changes across client and server code. This allows you to upgrade your server while still being able to service older clients; or have newer clients issue requests to older servers. An excellent community-provided write-up about thrift and compatibility when versioning an API can be found in the [Thrift Missing Guide](https://diwakergupta.github.io/thrift-missing-guide/#_versioning_compatibility). For more details on Thrift's design and implementation, see the Thrift whitepaper included in this distribution, or at the README.md file in your particular subdirectory of interest. Status ====== | Branch | Travis | Appveyor | Coverity Scan | codecov.io | Website | | :----- | :----- | :------- | :------------ | :--------- | :------ | | [`master`](https://github.com/apache/thrift/tree/master) | [![Build Status](https://travis-ci.org/apache/thrift.svg?branch=master)](https://travis-ci.org/apache/thrift/branches) | [![Build status](https://ci.appveyor.com/api/projects/status/github/apache/thrift?branch=master&svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/thrift/history) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/1345/badge.svg)](https://scan.coverity.com/projects/thrift) | | [![Website](https://img.shields.io/badge/official-website-brightgreen.svg)](https://thrift.apache.org/) | | [`0.14.0`](https://github.com/apache/thrift/tree/0.14.0) | [![Build Status](https://travis-ci.org/apache/thrift.svg?branch=0.14.0)](https://travis-ci.org/apache/thrift/branches) | | | | | Releases ======== Thrift does not maintain a specific release calendar at this time. We strive to release twice yearly. Download the [current release](http://thrift.apache.org/download). License ======= Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Project Hierarchy ================= thrift/ compiler/ Contains the Thrift compiler, implemented in C++. lib/ Contains the Thrift software library implementation, subdivided by language of implementation. cpp/ go/ java/ php/ py/ rb/ ... test/ Contains sample Thrift files and test code across the target programming languages. tutorial/ Contains a basic tutorial that will teach you how to develop software using Thrift. Development =========== To build the same way Travis CI builds the project you should use docker. We have [comprehensive building instructions for docker](build/docker/README.md). Requirements ============ See http://thrift.apache.org/docs/install for a list of build requirements (may be stale). Alternatively, see the docker build environments for a list of prerequisites. Resources ========= More information about Thrift can be obtained on the Thrift webpage at: http://thrift.apache.org Acknowledgments =============== Thrift was inspired by pillar, a lightweight RPC tool written by Adam D'Angelo, and also by Google's protocol buffers. Installation ============ If you are building from the first time out of the source repository, you will need to generate the configure scripts. (This is not necessary if you downloaded a tarball.) From the top directory, do: ./bootstrap.sh Once the configure scripts are generated, thrift can be configured. From the top directory, do: ./configure You may need to specify the location of the boost files explicitly. If you installed boost in `/usr/local`, you would run configure as follows: ./configure --with-boost=/usr/local Note that by default the thrift C++ library is typically built with debugging symbols included. If you want to customize these options you should use the CXXFLAGS option in configure, as such: ./configure CXXFLAGS='-g -O2' ./configure CFLAGS='-g -O2' ./configure CPPFLAGS='-DDEBUG_MY_FEATURE' To enable gcov required options -fprofile-arcs -ftest-coverage enable them: ./configure --enable-coverage Run ./configure --help to see other configuration options Please be aware that the Python library will ignore the --prefix option and just install wherever Python's distutils puts it (usually along the lines of `/usr/lib/pythonX.Y/site-packages/`). If you need to control where the Python modules are installed, set the PY_PREFIX variable. (DESTDIR is respected for Python and C++.) Make thrift: make From the top directory, become superuser and do: make install Uninstall thrift: make uninstall Note that some language packages must be installed manually using build tools better suited to those languages (at the time of this writing, this applies to Java, Ruby, PHP). Look for the README.md file in the lib// folder for more details on the installation of each language library package. Package Managers ================ Apache Thrift is available via a number of package managers, a list which is is steadily growing. A more detailed overview can be found [at the Apache Thrift web site under "Libraries"](http://thrift.apache.org/lib/) and/or in the respective READMEs for each language under /lib Testing ======= There are a large number of client library tests that can all be run from the top-level directory. make -k check This will make all of the libraries (as necessary), and run through the unit tests defined in each of the client libraries. If a single language fails, the make check will continue on and provide a synopsis at the end. To run the cross-language test suite, please run: make cross This will run a set of tests that use different language clients and servers. thrift-0.16.0/Thrift.podspec000066400000000000000000000017171420101504100157070ustar00rootroot00000000000000Pod::Spec.new do |s| s.name = 'Thrift' s.version = '0.16.0' s.summary = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC." s.description = <<-DESC The Apache Thrift scalable cross-language software framework for networked services development combines a software stack with a code generation engine to build services that work efficiently and seamlessly between many programming languages. DESC s.homepage = 'https://thrift.apache.org' s.license = { :type => 'Apache License, Version 2.0', :url => 'https://www.apache.org/licenses/LICENSE-2.0' } s.author = { 'Apache Thrift Developers' => 'dev@thrift.apache.org' } s.ios.deployment_target = '9.0' s.osx.deployment_target = '10.10' s.source = { :git => 'https://github.com/apache/thrift.git', :tag => 'v0.16.0' } s.source_files = 'lib/swift/Sources/*.swift' end thrift-0.16.0/aclocal/000077500000000000000000000000001420101504100144605ustar00rootroot00000000000000thrift-0.16.0/aclocal/ac_prog_bison.m4000066400000000000000000000033131420101504100175260ustar00rootroot00000000000000dnl dnl Check Bison version dnl AC_PROG_BISON([MIN_VERSION=2.4]) dnl dnl Will define BISON_USE_PARSER_H_EXTENSION if Automake is < 1.11 dnl for use with .h includes. dnl AC_DEFUN([AC_PROG_BISON], [ if test "x$1" = "x" ; then bison_required_version="2.4" else bison_required_version="$1" fi AC_CHECK_PROG(have_prog_bison, [bison], [yes],[no]) AC_DEFINE_UNQUOTED([BISON_VERSION], [0.0], [Bison version if bison is not available]) #Do not use *.h extension for parser header files, use newer *.hh bison_use_parser_h_extension=false if test "$have_prog_bison" = "yes" ; then AC_MSG_CHECKING([for bison version >= $bison_required_version]) bison_version=`bison --version | head -n 1 | cut '-d ' -f 4` AC_DEFINE_UNQUOTED([BISON_VERSION], [$bison_version], [Defines bison version]) if test "$bison_version" \< "$bison_required_version" ; then BISON=: AC_MSG_RESULT([no]) AC_MSG_ERROR([Bison version $bison_required_version or higher must be installed on the system!]) else AC_MSG_RESULT([yes]) BISON=bison AC_SUBST(BISON) #Verify automake version 1.11 headers for yy files are .h, > 1.12 uses .hh automake_version=`automake --version | head -n 1 | cut '-d ' -f 4` AC_DEFINE_UNQUOTED([AUTOMAKE_VERSION], [$automake_version], [Defines automake version]) if test "$automake_version" \< "1.12" ; then #Use *.h extension for parser header file bison_use_parser_h_extension=true echo "Automake version < 1.12" AC_DEFINE([BISON_USE_PARSER_H_EXTENSION], [1], [Use *.h extension for parser header file]) fi fi else BISON=: AC_MSG_RESULT([NO]) fi AM_CONDITIONAL([BISON_USE_PARSER_H_EXTENSION], [test x$bison_use_parser_h_extension = xtrue]) AC_SUBST(BISON) ]) thrift-0.16.0/aclocal/ax_boost_base.m4000066400000000000000000000326241420101504100175410ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_boost_base.html # =========================================================================== # # SYNOPSIS # # AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # DESCRIPTION # # Test for the Boost C++ libraries of a particular version (or newer) # # If no path to the installed boost library is given the macro searchs # under /usr, /usr/local, /opt and /opt/local and evaluates the # $BOOST_ROOT environment variable. Further documentation is available at # . # # This macro calls: # # AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) # # And sets: # # HAVE_BOOST # # LICENSE # # Copyright (c) 2008 Thomas Porschberg # Copyright (c) 2009 Peter Adolphs # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 45 # example boost program (need to pass version) m4_define([_AX_BOOST_BASE_PROGRAM], [AC_LANG_PROGRAM([[ #include ]],[[ (void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))])); ]])]) AC_DEFUN([AX_BOOST_BASE], [ AC_ARG_WITH([boost], [AS_HELP_STRING([--with-boost@<:@=ARG@:>@], [use Boost library from a standard location (ARG=yes), from the specified location (ARG=), or disable it (ARG=no) @<:@ARG=yes@:>@ ])], [ AS_CASE([$withval], [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""], [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""], [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"]) ], [want_boost="yes"]) AC_ARG_WITH([boost-libdir], [AS_HELP_STRING([--with-boost-libdir=LIB_DIR], [Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.])], [ AS_IF([test -d "$withval"], [_AX_BOOST_BASE_boost_lib_path="$withval"], [AC_MSG_ERROR([--with-boost-libdir expected directory name])]) ], [_AX_BOOST_BASE_boost_lib_path=""]) BOOST_LDFLAGS="" BOOST_CPPFLAGS="" AS_IF([test "x$want_boost" = "xyes"], [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])]) AC_SUBST(BOOST_CPPFLAGS) AC_SUBST(BOOST_LDFLAGS) ]) # convert a version string in $2 to numeric and affect to polymorphic var $1 AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[ AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"]) _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'` _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'` AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"], [AC_MSG_ERROR([You should at least specify libboost major version])]) _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'` AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"], [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"]) _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"], [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"]) _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET) ]) dnl Run the detection of boost should be run only if $want_boost AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1]) succeeded=no AC_REQUIRE([AC_CANONICAL_HOST]) dnl On 64-bit systems check for system libraries in both lib64 and lib. dnl The former is specified by FHS, but e.g. Debian does not adhere to dnl this (as it rises problems for generic multi-arch support). dnl The last entry in the list is chosen by default when no libraries dnl are found, e.g. when only header-only libraries are installed! AS_CASE([${host_cpu}], [x86_64],[libsubdirs="lib64 libx32 lib lib64"], [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64],[libsubdirs="lib64 lib lib64"], [libsubdirs="lib"] ) dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give dnl them priority over the other paths since, if libs are found there, they dnl are almost assuredly the ones desired. AS_CASE([${host_cpu}], [i?86],[multiarch_libsubdir="lib/i386-${host_os}"], [multiarch_libsubdir="lib/${host_cpu}-${host_os}"] ) dnl first we check the system location for boost libraries dnl this location ist chosen if boost libraries are installed with the --layout=system option dnl or if you install boost with RPM AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[ AC_MSG_RESULT([yes]) BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"]) AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[ AC_MSG_RESULT([yes]) BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; break; ], [AC_MSG_RESULT([no])]) done],[ AC_MSG_RESULT([no])]) ],[ if test X"$cross_compiling" = Xyes; then search_libsubdirs=$multiarch_libsubdir else search_libsubdirs="$multiarch_libsubdir $libsubdirs" fi for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then for libsubdir in $search_libsubdirs ; do if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir" BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" break; fi done ]) dnl overwrite ld flags if we have required special directory with dnl --with-boost-libdir parameter AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"], [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"]) AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)]) CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" export CPPFLAGS LDFLAGS_SAVED="$LDFLAGS" LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" export LDFLAGS AC_REQUIRE([AC_PROG_CXX]) AC_LANG_PUSH(C++) AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ AC_MSG_RESULT(yes) succeeded=yes found_system=yes ],[ ]) AC_LANG_POP([C++]) dnl if we found no boost with system layout we search for boost libraries dnl built and installed without the --layout=system option or for a staged(not installed) version if test "x$succeeded" != "xyes" ; then CPPFLAGS="$CPPFLAGS_SAVED" LDFLAGS="$LDFLAGS_SAVED" BOOST_CPPFLAGS= if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then BOOST_LDFLAGS= fi _version=0 if test -n "$_AX_BOOST_BASE_boost_path" ; then if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` V_CHECK=`expr $_version_tmp \> $_version` if test "x$V_CHECK" = "x1" ; then _version=$_version_tmp fi VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" done dnl if nothing found search for layout used in Windows distributions if test -z "$BOOST_CPPFLAGS"; then if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" fi fi dnl if we found something and BOOST_LDFLAGS was unset before dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here. if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then for libsubdir in $libsubdirs ; do if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir" fi fi else if test "x$cross_compiling" != "xyes" ; then for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` V_CHECK=`expr $_version_tmp \> $_version` if test "x$V_CHECK" = "x1" ; then _version=$_version_tmp best_path=$_AX_BOOST_BASE_boost_path fi done fi done VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then for libsubdir in $libsubdirs ; do if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done BOOST_LDFLAGS="-L$best_path/$libsubdir" fi fi if test -n "$BOOST_ROOT" ; then for libsubdir in $libsubdirs ; do if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` V_CHECK=`expr $stage_version_shorten \>\= $_version` if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) BOOST_CPPFLAGS="-I$BOOST_ROOT" BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" fi fi fi fi CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" export CPPFLAGS LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" export LDFLAGS AC_LANG_PUSH(C++) AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ AC_MSG_RESULT(yes) succeeded=yes found_system=yes ],[ ]) AC_LANG_POP([C++]) fi if test "x$succeeded" != "xyes" ; then if test "x$_version" = "x0" ; then AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) else AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) fi # execute ACTION-IF-NOT-FOUND (if present): ifelse([$3], , :, [$3]) else AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) # execute ACTION-IF-FOUND (if present): ifelse([$2], , :, [$2]) fi CPPFLAGS="$CPPFLAGS_SAVED" LDFLAGS="$LDFLAGS_SAVED" ]) thrift-0.16.0/aclocal/ax_check_openssl.m4000066400000000000000000000101351420101504100202320ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_openssl.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) # # DESCRIPTION # # Look for OpenSSL in a number of default spots, or in a user-selected # spot (via --with-openssl). Sets # # OPENSSL_INCLUDES to the include directives required # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required # # and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately # # This macro sets OPENSSL_INCLUDES such that source files should use the # openssl/ directory in include directives: # # #include # # LICENSE # # Copyright (c) 2009,2010 Zmanda Inc. # Copyright (c) 2009,2010 Dustin J. Mitchell # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 10 AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) AC_DEFUN([AX_CHECK_OPENSSL], [ found=false AC_ARG_WITH([openssl], [AS_HELP_STRING([--with-openssl=DIR], [root of the OpenSSL directory])], [ case "$withval" in "" | y | ye | yes | n | no) AC_MSG_ERROR([Invalid --with-openssl value]) ;; *) ssldirs="$withval" ;; esac ], [ # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs AC_CHECK_TOOL([PKG_CONFIG], [pkg-config]) if test x"$PKG_CONFIG" != x""; then OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` if test $? = 0; then OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` found=true fi fi # no such luck; use some default ssldirs if ! $found; then ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" fi ] ) # note that we #include , so the OpenSSL headers have to be in # an 'openssl' subdirectory if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" OPENSSL_LIBS="-lssl -lcrypto" found=true AC_MSG_RESULT([yes]) break else AC_MSG_RESULT([no]) fi done # if the file wasn't found, well, go ahead and try the link anyway -- maybe # it will just work! fi # try the preprocessor and linker with our new flags, # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" LIBS="$OPENSSL_LIBS $LIBS" CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" AC_LINK_IFELSE( [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], [ AC_MSG_RESULT([yes]) $1 ], [ AC_MSG_RESULT([no]) $2 ]) CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" AC_SUBST([OPENSSL_INCLUDES]) AC_SUBST([OPENSSL_LIBS]) AC_SUBST([OPENSSL_LDFLAGS]) ]) thrift-0.16.0/aclocal/ax_compare_version.m4000066400000000000000000000146531420101504100206160ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_compare_version.html # =========================================================================== # # SYNOPSIS # # AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # # DESCRIPTION # # This macro compares two version strings. Due to the various number of # minor-version numbers that can exist, and the fact that string # comparisons are not compatible with numeric comparisons, this is not # necessarily trivial to do in a autoconf script. This macro makes doing # these comparisons easy. # # The six basic comparisons are available, as well as checking equality # limited to a certain number of minor-version levels. # # The operator OP determines what type of comparison to do, and can be one # of: # # eq - equal (test A == B) # ne - not equal (test A != B) # le - less than or equal (test A <= B) # ge - greater than or equal (test A >= B) # lt - less than (test A < B) # gt - greater than (test A > B) # # Additionally, the eq and ne operator can have a number after it to limit # the test to that number of minor versions. # # eq0 - equal up to the length of the shorter version # ne0 - not equal up to the length of the shorter version # eqN - equal up to N sub-version levels # neN - not equal up to N sub-version levels # # When the condition is true, shell commands ACTION-IF-TRUE are run, # otherwise shell commands ACTION-IF-FALSE are run. The environment # variable 'ax_compare_version' is always set to either 'true' or 'false' # as well. # # Examples: # # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) # # would both be true. # # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) # # would both be false. # # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) # # would be true because it is only comparing two minor versions. # # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) # # would be true because it is only comparing the lesser number of minor # versions of the two values. # # Note: The characters that separate the version numbers do not matter. An # empty string is the same as version 0. OP is evaluated by autoconf, not # configure, so must be a string, not a variable. # # The author would like to acknowledge Guido Draheim whose advice about # the m4_case and m4_ifvaln functions make this macro only include the # portions necessary to perform the specific comparison specified by the # OP argument in the final configure script. # # LICENSE # # Copyright (c) 2008 Tim Toolan # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 12 dnl ######################################################################### AC_DEFUN([AX_COMPARE_VERSION], [ AC_REQUIRE([AC_PROG_AWK]) # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. AS_VAR_PUSHDEF([A],[ax_compare_version_A]) A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` AS_VAR_PUSHDEF([B],[ax_compare_version_B]) B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary dnl # then the first line is used to determine if the condition is true. dnl # The sed right after the echo is to remove any indented white space. m4_case(m4_tolower($2), [lt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [gt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [le],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` ], [ge],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` ],[ dnl Split the operator from the subversion count if present. m4_bmatch(m4_substr($2,2), [0],[ # A count of zero means use the length of the shorter version. # Determine the number of characters in A and B. ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` # Set A to no more than B's length and B to no more than A's length. A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` ], [[0-9]+],[ # A count greater than zero means use only that many subversions A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` ], [.+],[ AC_WARNING( [illegal OP numeric parameter: $2]) ],[]) # Pad zeros at end of numbers to make same length. ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" B="$B`echo $A | sed 's/./0/g'`" A="$ax_compare_version_tmp_A" # Check for equality or inequality as necessary. m4_case(m4_tolower(m4_substr($2,0,2)), [eq],[ test "x$A" = "x$B" && ax_compare_version=true ], [ne],[ test "x$A" != "x$B" && ax_compare_version=true ],[ AC_WARNING([illegal OP parameter: $2]) ]) ]) AS_VAR_POPDEF([A])dnl AS_VAR_POPDEF([B])dnl dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. if test "$ax_compare_version" = "true" ; then m4_ifvaln([$4],[$4],[:])dnl m4_ifvaln([$5],[else $5])dnl fi ]) dnl AX_COMPARE_VERSION thrift-0.16.0/aclocal/ax_cxx_compile_stdcxx.m4000066400000000000000000000454561420101504100213370ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html # =========================================================================== # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and # CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) # or '14' (for the C++14 standard). # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is # required and that the macro should error out if no mode with that # support is found. If specified 'optional', then configuration proceeds # regardless, after defining HAVE_CXX${VERSION} if and only if a # supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 10 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], [$2], [noext], [], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$3], [optional], [ax_cxx_compile_cxx$1_required=false], [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do switch="-std=gnu++${alternative}" cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done fi]) m4_if([$2], [ext], [], [dnl if test x$ac_success = xno; then dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx$1_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) fi fi if test x$ac_success = xno; then HAVE_CXX$1=0 AC_MSG_NOTICE([No compiler with C++$1 support was found]) else HAVE_CXX$1=1 AC_DEFINE(HAVE_CXX$1,1, [define if the compiler supports basic C++$1 syntax]) fi AC_SUBST(HAVE_CXX$1) ]) dnl Test body for checking C++11 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 ) dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 ) m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 ) dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201103L #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual void f() {} }; struct Derived : public Base { virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L ]]) dnl Tests for new features in C++14 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L ]]) dnl Tests for new features in C++17 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // __cplusplus < 201703L ]]) thrift-0.16.0/aclocal/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000032151420101504100216230ustar00rootroot00000000000000# ============================================================================= # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================= # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXX and CXXCPP to enable # support. # # This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX # macro with the version set to C++11. The two optional arguments are # forwarded literally as the second and third argument respectively. # Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for # more information. If you want to use this macro, you also need to # download the ax_cxx_compile_stdcxx.m4 file. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 18 AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) thrift-0.16.0/aclocal/ax_dmd.m4000066400000000000000000000065631420101504100161700ustar00rootroot00000000000000dnl @synopsis AX_DMD dnl dnl Test for the presence of a DMD-compatible D2 compiler, and (optionally) dnl specified modules on the import path. dnl dnl If "DMD" is defined in the environment, that will be the only dnl dmd command tested. Otherwise, a hard-coded list will be used. dnl dnl After AX_DMD runs, the shell variables "success" and "ax_dmd" are set to dnl "yes" or "no", and "DMD" is set to the appropriate command. Furthermore, dnl "dmd_optlink" will be set to "yes" or "no" depending on whether OPTLINK is dnl used as the linker (DMD/Windows), and "dmd_of_dirsep" will be set to the dnl directory separator to use when passing -of to DMD (OPTLINK requires a dnl backslash). dnl dnl AX_CHECK_D_MODULE must be run after AX_DMD. It tests for the presence of a dnl module in the import path of the chosen compiler, and sets the shell dnl variable "success" to "yes" or "no". dnl dnl @category D dnl @version 2011-05-31 dnl @license AllPermissive dnl dnl Copyright (C) 2009 David Reiss dnl Copyright (C) 2011 David Nadlinger dnl Copying and distribution of this file, with or without modification, dnl are permitted in any medium without royalty provided the copyright dnl notice and this notice are preserved. AC_DEFUN([AX_DMD], [ dnl Hard-coded default commands to test. DMD_PROGS="dmd,gdmd,ldmd" dnl Allow the user to specify an alternative. if test -n "$DMD" ; then DMD_PROGS="$DMD" fi AC_MSG_CHECKING(for DMD) # std.algorithm as a quick way to check for D2/Phobos. echo "import std.algorithm; void main() {}" > configtest_ax_dmd.d success=no oIFS="$IFS" IFS="," for DMD in $DMD_PROGS ; do IFS="$oIFS" echo "Running \"$DMD configtest_ax_dmd.d\"" >&AS_MESSAGE_LOG_FD if $DMD configtest_ax_dmd.d >&AS_MESSAGE_LOG_FD 2>&1 ; then success=yes break fi done if test "$success" != "yes" ; then AC_MSG_RESULT(no) DMD="" else AC_MSG_RESULT(yes) fi ax_dmd="$success" # Test whether OPTLINK is used by trying if DMD accepts -L/? without # erroring out. if test "$success" == "yes" ; then AC_MSG_CHECKING(whether DMD uses OPTLINK) echo "Running \”$DMD -L/? configtest_ax_dmd.d\"" >&AS_MESSAGE_LOG_FD if $DMD -L/? configtest_ax_dmd.d >&AS_MESSAGE_LOG_FD 2>&1 ; then AC_MSG_RESULT(yes) dmd_optlink="yes" # This actually produces double slashes in the final configure # output, but at least it works. dmd_of_dirsep="\\\\" else AC_MSG_RESULT(no) dmd_optlink="no" dmd_of_dirsep="/" fi fi rm -f configtest_ax_dmd* ]) AC_DEFUN([AX_CHECK_D_MODULE], [ AC_MSG_CHECKING(for D module [$1]) echo "import $1; void main() {}" > configtest_ax_dmd.d echo "Running \"$DMD configtest_ax_dmd.d\"" >&AS_MESSAGE_LOG_FD if $DMD -c configtest_ax_dmd.d >&AS_MESSAGE_LOG_FD 2>&1 ; then AC_MSG_RESULT(yes) success=yes else AC_MSG_RESULT(no) success=no fi rm -f configtest_ax_dmd* ]) thrift-0.16.0/aclocal/ax_javac_and_java.m4000066400000000000000000000100451420101504100203210ustar00rootroot00000000000000dnl @synopsis AX_JAVAC_AND_JAVA dnl @synopsis AX_CHECK_JAVA_CLASS(CLASSNAME) dnl dnl Test for the presence of a JDK, and (optionally) specific classes. dnl dnl If "JAVA" is defined in the environment, that will be the only dnl java command tested. Otherwise, a hard-coded list will be used. dnl Similarly for "JAVAC". dnl dnl AX_JAVAC_AND_JAVA does not currently support testing for a particular dnl Java version, testing for only one of "java" and "javac", or dnl compiling or running user-provided Java code. dnl dnl After AX_JAVAC_AND_JAVA runs, the shell variables "success" and dnl "ax_javac_and_java" are set to "yes" or "no", and "JAVAC" and dnl "JAVA" are set to the appropriate commands. dnl dnl AX_CHECK_JAVA_CLASS must be run after AX_JAVAC_AND_JAVA. dnl It tests for the presence of a class based on a fully-qualified name. dnl It sets the shell variable "success" to "yes" or "no". dnl dnl @category Java dnl @version 2009-02-09 dnl @license AllPermissive dnl dnl Copyright (C) 2009 David Reiss dnl Copying and distribution of this file, with or without modification, dnl are permitted in any medium without royalty provided the copyright dnl notice and this notice are preserved. AC_DEFUN([AX_JAVAC_AND_JAVA], [ dnl Hard-coded default commands to test. JAVAC_PROGS="javac,jikes,gcj -C" JAVA_PROGS="java,kaffe" dnl Allow the user to specify an alternative. if test -n "$JAVAC" ; then JAVAC_PROGS="$JAVAC" fi if test -n "$JAVA" ; then JAVA_PROGS="$JAVA" fi AC_MSG_CHECKING(for javac and java) echo "public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java success=no oIFS="$IFS" IFS="," for JAVAC in $JAVAC_PROGS ; do IFS="$oIFS" echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then # prevent $JAVA VM issues with UTF-8 path names (THRIFT-3271) oLC_ALL="$LC_ALL" LC_ALL="" IFS="," for JAVA in $JAVA_PROGS ; do IFS="$oIFS" echo "Running \"$JAVA configtest_ax_javac_and_java\"" >&AS_MESSAGE_LOG_FD if $JAVA configtest_ax_javac_and_java >&AS_MESSAGE_LOG_FD 2>&1 ; then success=yes break 2 fi done # restore LC_ALL LC_ALL="$oLC_ALL" oLC_ALL="" fi done rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class if test "$success" != "yes" ; then AC_MSG_RESULT(no) JAVAC="" JAVA="" else AC_MSG_RESULT(yes) fi ax_javac_and_java="$success" ]) AC_DEFUN([AX_CHECK_JAVA_CLASS], [ AC_MSG_CHECKING(for Java class [$1]) echo "import $1; public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then AC_MSG_RESULT(yes) success=yes else AC_MSG_RESULT(no) success=no fi rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class ]) AC_DEFUN([AX_CHECK_ANT_VERSION], [ AC_MSG_CHECKING(for ant version > $2) ANT_VALID=`expr "x$(printf "$2\n$($1 -version 2>/dev/null | sed -n 's/.*version \(@<:@0-9\.@:>@*\).*/\1/p')" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -g | sed -n 1p)" = "x$2"` if test "x$ANT_VALID" = "x1" ; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) ANT="" fi ]) thrift-0.16.0/aclocal/ax_lib_event.m4000066400000000000000000000152451420101504100173700ustar00rootroot00000000000000dnl @synopsis AX_LIB_EVENT([MINIMUM-VERSION]) dnl dnl Test for the libevent library of a particular version (or newer). dnl dnl If no path to the installed libevent is given, the macro will first try dnl using no -I or -L flags, then searches under /usr, /usr/local, /opt, dnl and /opt/libevent. dnl If these all fail, it will try the $LIBEVENT_ROOT environment variable. dnl dnl This macro requires that #include works and defines u_char. dnl dnl This macro calls: dnl AC_SUBST(LIBEVENT_CPPFLAGS) dnl AC_SUBST(LIBEVENT_LDFLAGS) dnl AC_SUBST(LIBEVENT_LIBS) dnl dnl And (if libevent is found): dnl AC_DEFINE(HAVE_LIBEVENT) dnl dnl It also leaves the shell variables "success" and "ax_have_libevent" dnl set to "yes" or "no". dnl dnl NOTE: This macro does not currently work for cross-compiling, dnl but it can be easily modified to allow it. (grep "cross"). dnl dnl @category InstalledPackages dnl @category C dnl @version 2007-09-12 dnl @license AllPermissive dnl dnl Copyright (C) 2009 David Reiss dnl Copying and distribution of this file, with or without modification, dnl are permitted in any medium without royalty provided the copyright dnl notice and this notice are preserved. dnl Input: ax_libevent_path, WANT_LIBEVENT_VERSION dnl Output: success=yes/no AC_DEFUN([AX_LIB_EVENT_DO_CHECK], [ # Save our flags. CPPFLAGS_SAVED="$CPPFLAGS" LDFLAGS_SAVED="$LDFLAGS" LIBS_SAVED="$LIBS" LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" # Set our flags if we are checking a specific directory. if test -n "$ax_libevent_path" ; then LIBEVENT_CPPFLAGS="-I$ax_libevent_path/include" LIBEVENT_LDFLAGS="-L$ax_libevent_path/lib" LD_LIBRARY_PATH="$ax_libevent_path/lib:$LD_LIBRARY_PATH" else LIBEVENT_CPPFLAGS="" LIBEVENT_LDFLAGS="" fi # Required flag for libevent. LIBEVENT_LIBS="-levent" # Prepare the environment for compilation. CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS" LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS" LIBS="$LIBS $LIBEVENT_LIBS" export CPPFLAGS export LDFLAGS export LIBS export LD_LIBRARY_PATH success=no # Compile, link, and run the program. This checks: # - event.h is available for including. # - event_get_version() is available for linking. # - The event version string is lexicographically greater # than the required version. AC_LANG_PUSH([C]) dnl This can be changed to AC_LINK_IFELSE if you are cross-compiling, dnl but then the version cannot be checked. AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ const char* lib_version = event_get_version(); const char* wnt_version = "$WANT_LIBEVENT_VERSION"; int lib_digits; int wnt_digits; for (;;) { /* If we reached the end of the want version. We have it. */ if (*wnt_version == '\0' || *wnt_version == '-') { return 0; } /* If the want version continues but the lib version does not, */ /* we are missing a letter. We don't have it. */ if (*lib_version == '\0' || *lib_version == '-') { return 1; } /* In the 1.4 version numbering style, if there are more digits */ /* in one version than the other, that one is higher. */ for (lib_digits = 0; lib_version[lib_digits] >= '0' && lib_version[lib_digits] <= '9'; lib_digits++) ; for (wnt_digits = 0; wnt_version[wnt_digits] >= '0' && wnt_version[wnt_digits] <= '9'; wnt_digits++) ; if (lib_digits > wnt_digits) { return 0; } if (lib_digits < wnt_digits) { return 1; } /* If we have greater than what we want. We have it. */ if (*lib_version > *wnt_version) { return 0; } /* If we have less, we don't. */ if (*lib_version < *wnt_version) { return 1; } lib_version++; wnt_version++; } return 0; ]])], [ success=yes ]) AC_LANG_POP([C]) # Restore flags. CPPFLAGS="$CPPFLAGS_SAVED" LDFLAGS="$LDFLAGS_SAVED" LIBS="$LIBS_SAVED" LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" ]) AC_DEFUN([AX_LIB_EVENT], [ dnl Allow search path to be overridden on the command line. AC_ARG_WITH([libevent], AS_HELP_STRING([--with-libevent@<:@=DIR@:>@], [use libevent [default=yes]. Optionally specify the root prefix dir where libevent is installed]), [ if test "x$withval" = "xno"; then want_libevent="no" elif test "x$withval" = "xyes"; then want_libevent="yes" ax_libevent_path="" else want_libevent="yes" ax_libevent_path="$withval" fi ], [ want_libevent="yes" ; ax_libevent_path="" ]) if test "$want_libevent" = "yes"; then WANT_LIBEVENT_VERSION=ifelse([$1], ,1.2,$1) AC_MSG_CHECKING(for libevent >= $WANT_LIBEVENT_VERSION) # Run tests. if test -n "$ax_libevent_path"; then AX_LIB_EVENT_DO_CHECK else for ax_libevent_path in "" $lt_sysroot/usr $lt_sysroot/usr/local $lt_sysroot/opt $lt_sysroot/opt/local $lt_sysroot/opt/libevent "$LIBEVENT_ROOT" ; do AX_LIB_EVENT_DO_CHECK if test "$success" = "yes"; then break; fi done fi if test "$success" != "yes" ; then AC_MSG_RESULT(no) LIBEVENT_CPPFLAGS="" LIBEVENT_LDFLAGS="" LIBEVENT_LIBS="" else AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LIBEVENT,,[define if libevent is available]) ax_have_libevent_[]m4_translit([$1], [.], [_])="yes" fi ax_have_libevent="$success" AC_SUBST(LIBEVENT_CPPFLAGS) AC_SUBST(LIBEVENT_LDFLAGS) AC_SUBST(LIBEVENT_LIBS) fi ]) thrift-0.16.0/aclocal/ax_lib_zlib.m4000066400000000000000000000133771420101504100172130ustar00rootroot00000000000000dnl @synopsis AX_LIB_ZLIB([MINIMUM-VERSION]) dnl dnl Test for the libz library of a particular version (or newer). dnl dnl If no path to the installed zlib is given, the macro will first try dnl using no -I or -L flags, then searches under /usr, /usr/local, /opt, dnl and /opt/zlib. dnl If these all fail, it will try the $ZLIB_ROOT environment variable. dnl dnl This macro calls: dnl AC_SUBST(ZLIB_CPPFLAGS) dnl AC_SUBST(ZLIB_LDFLAGS) dnl AC_SUBST(ZLIB_LIBS) dnl dnl And (if zlib is found): dnl AC_DEFINE(HAVE_ZLIB) dnl dnl It also leaves the shell variables "success" and "ax_have_zlib" dnl set to "yes" or "no". dnl dnl NOTE: This macro does not currently work for cross-compiling, dnl but it can be easily modified to allow it. (grep "cross"). dnl dnl @category InstalledPackages dnl @category C dnl @version 2007-09-12 dnl @license AllPermissive dnl dnl Copyright (C) 2009 David Reiss dnl Copying and distribution of this file, with or without modification, dnl are permitted in any medium without royalty provided the copyright dnl notice and this notice are preserved. dnl Input: ax_zlib_path, WANT_ZLIB_VERSION dnl Output: success=yes/no AC_DEFUN([AX_LIB_ZLIB_DO_CHECK], [ # Save our flags. CPPFLAGS_SAVED="$CPPFLAGS" LDFLAGS_SAVED="$LDFLAGS" LIBS_SAVED="$LIBS" LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" # Set our flags if we are checking a specific directory. if test -n "$ax_zlib_path" ; then ZLIB_CPPFLAGS="-I$ax_zlib_path/include" ZLIB_LDFLAGS="-L$ax_zlib_path/lib" LD_LIBRARY_PATH="$ax_zlib_path/lib:$LD_LIBRARY_PATH" else ZLIB_CPPFLAGS="" ZLIB_LDFLAGS="" fi # Required flag for zlib. ZLIB_LIBS="-lz" # Prepare the environment for compilation. CPPFLAGS="$CPPFLAGS $ZLIB_CPPFLAGS" LDFLAGS="$LDFLAGS $ZLIB_LDFLAGS" LIBS="$LIBS $ZLIB_LIBS" export CPPFLAGS export LDFLAGS export LIBS export LD_LIBRARY_PATH success=no # Compile, link, and run the program. This checks: # - zlib.h is available for including. # - zlibVersion() is available for linking. # - ZLIB_VERNUM is greater than or equal to the desired version. # - ZLIB_VERSION (defined in zlib.h) matches zlibVersion() # (defined in the library). AC_LANG_PUSH([C]) dnl This can be changed to AC_LINK_IFELSE if you are cross-compiling. AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #if ZLIB_VERNUM >= 0x$WANT_ZLIB_VERSION #else # error zlib is too old #endif ]], [[ const char* lib_version = zlibVersion(); const char* hdr_version = ZLIB_VERSION; for (;;) { if (*lib_version != *hdr_version) { /* If this happens, your zlib header doesn't match your zlib */ /* library. That is really bad. */ return 1; } if (*lib_version == '\0') { break; } lib_version++; hdr_version++; } return 0; ]])], [ success=yes ]) AC_LANG_POP([C]) # Restore flags. CPPFLAGS="$CPPFLAGS_SAVED" LDFLAGS="$LDFLAGS_SAVED" LIBS="$LIBS_SAVED" LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" ]) AC_DEFUN([AX_LIB_ZLIB], [ dnl Allow search path to be overridden on the command line. AC_ARG_WITH([zlib], AS_HELP_STRING([--with-zlib@<:@=DIR@:>@], [use zlib (default is yes) - it is possible to specify an alternate root directory for zlib]), [ if test "x$withval" = "xno"; then want_zlib="no" elif test "x$withval" = "xyes"; then want_zlib="yes" ax_zlib_path="" else want_zlib="yes" ax_zlib_path="$withval" fi ], [want_zlib="yes" ; ax_zlib_path="" ]) if test "$want_zlib" = "yes"; then # Parse out the version. zlib_version_req=ifelse([$1], ,1.2.3,$1) zlib_version_req_major=`expr $zlib_version_req : '\([[0-9]]*\)'` zlib_version_req_minor=`expr $zlib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` zlib_version_req_patch=`expr $zlib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` if test -z "$zlib_version_req_patch" ; then zlib_version_req_patch="0" fi WANT_ZLIB_VERSION=`expr $zlib_version_req_major \* 1000 \+ $zlib_version_req_minor \* 100 \+ $zlib_version_req_patch \* 10` AC_MSG_CHECKING(for zlib >= $zlib_version_req) # Run tests. if test -n "$ax_zlib_path"; then AX_LIB_ZLIB_DO_CHECK else for ax_zlib_path in "" /usr /usr/local /opt /opt/zlib "$ZLIB_ROOT" ; do AX_LIB_ZLIB_DO_CHECK if test "$success" = "yes"; then break; fi done fi if test "$success" != "yes" ; then AC_MSG_RESULT(no) ZLIB_CPPFLAGS="" ZLIB_LDFLAGS="" ZLIB_LIBS="" else AC_MSG_RESULT(yes) AC_DEFINE(HAVE_ZLIB,,[define if zlib is available]) fi ax_have_zlib="$success" AC_SUBST(ZLIB_CPPFLAGS) AC_SUBST(ZLIB_LDFLAGS) AC_SUBST(ZLIB_LIBS) fi ]) thrift-0.16.0/aclocal/ax_lua.m4000066400000000000000000000636031420101504100162030ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_lua.html # =========================================================================== # # SYNOPSIS # # AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] # AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] # AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] # AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] # # DESCRIPTION # # Detect a Lua interpreter, optionally specifying a minimum and maximum # version number. Set up important Lua paths, such as the directories in # which to install scripts and modules (shared libraries). # # Also detect Lua headers and libraries. The Lua version contained in the # header is checked to match the Lua interpreter version exactly. When # searching for Lua libraries, the version number is used as a suffix. # This is done with the goal of supporting multiple Lua installs (5.1, # 5.2, and 5.3 side-by-side). # # A note on compatibility with previous versions: This file has been # mostly rewritten for serial 18. Most developers should be able to use # these macros without needing to modify configure.ac. Care has been taken # to preserve each macro's behavior, but there are some differences: # # 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as # AX_PROG_LUA with no arguments. # # 2) AX_LUA_HEADERS now checks that the version number defined in lua.h # matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore # unnecessary, so it is deprecated and does not expand to anything. # # 3) The configure flag --with-lua-suffix no longer exists; the user # should instead specify the LUA precious variable on the command line. # See the AX_PROG_LUA description for details. # # Please read the macro descriptions below for more information. # # This file was inspired by Andrew Dalke's and James Henstridge's # python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 # (serial 17). Basically, this file is a mash-up of those two files. I # like to think it combines the best of the two! # # AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua # paths. Adds precious variable LUA, which may contain the path of the Lua # interpreter. If LUA is blank, the user's path is searched for an # suitable interpreter. # # If MINIMUM-VERSION is supplied, then only Lua interpreters with a # version number greater or equal to MINIMUM-VERSION will be accepted. If # TOO-BIG-VERSION is also supplied, then only Lua interpreters with a # version number greater or equal to MINIMUM-VERSION and less than # TOO-BIG-VERSION will be accepted. # # The Lua version number, LUA_VERSION, is found from the interpreter, and # substituted. LUA_PLATFORM is also found, but not currently supported (no # standard representation). # # Finally, the macro finds four paths: # # luadir Directory to install Lua scripts. # pkgluadir $luadir/$PACKAGE # luaexecdir Directory to install Lua modules. # pkgluaexecdir $luaexecdir/$PACKAGE # # These paths are found based on $prefix, $exec_prefix, Lua's # package.path, and package.cpath. The first path of package.path # beginning with $prefix is selected as luadir. The first path of # package.cpath beginning with $exec_prefix is used as luaexecdir. This # should work on all reasonable Lua installations. If a path cannot be # determined, a default path is used. Of course, the user can override # these later when invoking make. # # luadir Default: $prefix/share/lua/$LUA_VERSION # luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION # # These directories can be used by Automake as install destinations. The # variable name minus 'dir' needs to be used as a prefix to the # appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. # # If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is # performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- # FOUND is blank, then it will default to printing an error. To prevent # the default behavior, give ':' as an action. # # AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be # expanded before this macro. Adds precious variable LUA_INCLUDE, which # may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If # LUA_INCLUDE is blank, then this macro will attempt to find suitable # flags. # # LUA_INCLUDE can be used by Automake to compile Lua modules or # executables with embedded interpreters. The *_CPPFLAGS variables should # be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). # # This macro searches for the header lua.h (and others). The search is # performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. # If the search is unsuccessful, then some common directories are tried. # If the headers are then found, then LUA_INCLUDE is set accordingly. # # The paths automatically searched are: # # * /usr/include/luaX.Y # * /usr/include/lua/X.Y # * /usr/include/luaXY # * /usr/local/include/luaX.Y # * /usr/local/include/lua-X.Y # * /usr/local/include/lua/X.Y # * /usr/local/include/luaXY # # (Where X.Y is the Lua version number, e.g. 5.1.) # # The Lua version number found in the headers is always checked to match # the Lua interpreter's version number. Lua headers with mismatched # version numbers are not accepted. # # If headers are found, then ACTION-IF-FOUND is performed, otherwise # ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then # it will default to printing an error. To prevent the default behavior, # set the action to ':'. # # AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be # expanded before this macro. Adds precious variable LUA_LIB, which may # contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, # then this macro will attempt to find suitable flags. # # LUA_LIB can be used by Automake to link Lua modules or executables with # embedded interpreters. The *_LIBADD and *_LDADD variables should be used # for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). # # This macro searches for the Lua library. More technically, it searches # for a library containing the function lua_load. The search is performed # with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. # # If the search determines that some linker flags are missing, then those # flags will be added to LUA_LIB. # # If libraries are found, then ACTION-IF-FOUND is performed, otherwise # ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then # it will default to printing an error. To prevent the default behavior, # set the action to ':'. # # AX_LUA_READLINE: Search for readline headers and libraries. Requires the # AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the # Autoconf Archive. # # If a readline compatible library is found, then ACTION-IF-FOUND is # performed, otherwise ACTION-IF-NOT-FOUND is performed. # # LICENSE # # Copyright (c) 2015 Reuben Thomas # Copyright (c) 2014 Tim Perkins # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 40 dnl ========================================================================= dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION], dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ========================================================================= AC_DEFUN([AX_PROG_LUA], [ dnl Check for required tools. AC_REQUIRE([AC_PROG_GREP]) AC_REQUIRE([AC_PROG_SED]) dnl Make LUA a precious variable. AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1]) dnl Find a Lua interpreter. m4_define_default([_AX_LUA_INTERPRETER_LIST], [lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50]) m4_if([$1], [], [ dnl No version check is needed. Find any Lua interpreter. AS_IF([test "x$LUA" = 'x'], [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])]) ax_display_LUA='lua' AS_IF([test "x$LUA" != 'x:'], [ dnl At least check if this is a Lua interpreter. AC_MSG_CHECKING([if $LUA is a Lua interpreter]) _AX_LUA_CHK_IS_INTRP([$LUA], [AC_MSG_RESULT([yes])], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([not a Lua interpreter]) ]) ]) ], [ dnl A version check is needed. AS_IF([test "x$LUA" != 'x'], [ dnl Check if this is a Lua interpreter. AC_MSG_CHECKING([if $LUA is a Lua interpreter]) _AX_LUA_CHK_IS_INTRP([$LUA], [AC_MSG_RESULT([yes])], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([not a Lua interpreter]) ]) dnl Check the version. m4_if([$2], [], [_ax_check_text="whether $LUA version >= $1"], [_ax_check_text="whether $LUA version >= $1, < $2"]) AC_MSG_CHECKING([$_ax_check_text]) _AX_LUA_CHK_VER([$LUA], [$1], [$2], [AC_MSG_RESULT([yes])], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([version is out of range for specified LUA])]) ax_display_LUA=$LUA ], [ dnl Try each interpreter until we find one that satisfies VERSION. m4_if([$2], [], [_ax_check_text="for a Lua interpreter with version >= $1"], [_ax_check_text="for a Lua interpreter with version >= $1, < $2"]) AC_CACHE_CHECK([$_ax_check_text], [ax_cv_pathless_LUA], [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do test "x$ax_cv_pathless_LUA" = 'xnone' && break _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue]) _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break]) done ]) dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA. AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'], [LUA=':'], [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])]) ax_display_LUA=$ax_cv_pathless_LUA ]) ]) AS_IF([test "x$LUA" = 'x:'], [ dnl Run any user-specified action, or abort. m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])]) ], [ dnl Query Lua for its version number. AC_CACHE_CHECK([for $ax_display_LUA version], [ax_cv_lua_version], [ dnl Get the interpreter version in X.Y format. This should work for dnl interpreters version 5.0 and beyond. ax_cv_lua_version=[`$LUA -e ' -- return a version number in X.Y format local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)") print(ver)'`] ]) AS_IF([test "x$ax_cv_lua_version" = 'x'], [AC_MSG_ERROR([invalid Lua version number])]) AC_SUBST([LUA_VERSION], [$ax_cv_lua_version]) AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`]) dnl The following check is not supported: dnl At times (like when building shared libraries) you may want to know dnl which OS platform Lua thinks this is. AC_CACHE_CHECK([for $ax_display_LUA platform], [ax_cv_lua_platform], [ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]]) AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct dnl variables so they can be overridden if need be. However, the general dnl consensus is that you shouldn't need this ability. AC_SUBST([LUA_PREFIX], ['${prefix}']) AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}']) dnl Lua provides no way to query the script directory, and instead dnl provides LUA_PATH. However, we should be able to make a safe educated dnl guess. If the built-in search path contains a directory which is dnl prefixed by $prefix, then we can store scripts there. The first dnl matching path will be used. AC_CACHE_CHECK([for $ax_display_LUA script directory], [ax_cv_lua_luadir], [ AS_IF([test "x$prefix" = 'xNONE'], [ax_lua_prefix=$ac_default_prefix], [ax_lua_prefix=$prefix]) dnl Initialize to the default path. ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" dnl Try to find a path with the prefix. _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script]) AS_IF([test "x$ax_lua_prefixed_path" != 'x'], [ dnl Fix the prefix. _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'` ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"` ]) ]) AC_SUBST([luadir], [$ax_cv_lua_luadir]) AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE]) dnl Lua provides no way to query the module directory, and instead dnl provides LUA_PATH. However, we should be able to make a safe educated dnl guess. If the built-in search path contains a directory which is dnl prefixed by $exec_prefix, then we can store modules there. The first dnl matching path will be used. AC_CACHE_CHECK([for $ax_display_LUA module directory], [ax_cv_lua_luaexecdir], [ AS_IF([test "x$exec_prefix" = 'xNONE'], [ax_lua_exec_prefix=$ax_lua_prefix], [ax_lua_exec_prefix=$exec_prefix]) dnl Initialize to the default path. ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" dnl Try to find a path with the prefix. _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_exec_prefix], [module]) AS_IF([test "x$ax_lua_prefixed_path" != 'x'], [ dnl Fix the prefix. _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'` ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"` ]) ]) AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir]) AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE]) dnl Run any user specified action. $3 ]) ]) dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA. AC_DEFUN([AX_WITH_LUA], [ AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]]) AX_PROG_LUA ]) dnl ========================================================================= dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) dnl ========================================================================= AC_DEFUN([_AX_LUA_CHK_IS_INTRP], [ dnl A minimal Lua factorial to prove this is an interpreter. This should work dnl for Lua interpreters version 5.0 and beyond. _ax_lua_factorial=[`$1 2>/dev/null -e ' -- a simple factorial function fact (n) if n == 0 then return 1 else return n * fact(n-1) end end print("fact(5) is " .. fact(5))'`] AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'], [$2], [$3]) ]) dnl ========================================================================= dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION], dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE]) dnl ========================================================================= AC_DEFUN([_AX_LUA_CHK_VER], [ dnl Check that the Lua version is within the bounds. Only the major and minor dnl version numbers are considered. This should work for Lua interpreters dnl version 5.0 and beyond. _ax_lua_good_version=[`$1 -e ' -- a script to compare versions function verstr2num(verstr) local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)") if majorver and minorver then return tonumber(majorver) * 100 + tonumber(minorver) end end local minver = verstr2num("$2") local _, _, trimver = string.find(_VERSION, "^Lua (.*)") local ver = verstr2num(trimver) local maxver = verstr2num("$3") or 1e9 if minver <= ver and ver < maxver then print("yes") else print("no") end'`] AS_IF([test "x$_ax_lua_good_version" = "xyes"], [$4], [$5]) ]) dnl ========================================================================= dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR) dnl ========================================================================= AC_DEFUN([_AX_LUA_FND_PRFX_PTH], [ dnl Get the script or module directory by querying the Lua interpreter, dnl filtering on the given prefix, and selecting the shallowest path. If no dnl path is found matching the prefix, the result will be an empty string. dnl The third argument determines the type of search, it can be 'script' or dnl 'module'. Supplying 'script' will perform the search with package.path dnl and LUA_PATH, and supplying 'module' will search with package.cpath and dnl LUA_CPATH. This is done for compatibility with Lua 5.0. ax_lua_prefixed_path=[`$1 -e ' -- get the path based on search type local searchtype = "$3" local paths = "" if searchtype == "script" then paths = (package and package.path) or LUA_PATH elseif searchtype == "module" then paths = (package and package.cpath) or LUA_CPATH end -- search for the prefix local prefix = "'$2'" local minpath = "" local mindepth = 1e9 string.gsub(paths, "(@<:@^;@:>@+)", function (path) path = string.gsub(path, "%?.*$", "") path = string.gsub(path, "/@<:@^/@:>@*$", "") if string.find(path, prefix) then local depth = string.len(string.gsub(path, "@<:@^/@:>@", "")) if depth < mindepth then minpath = path mindepth = depth end end end) print(minpath)'`] ]) dnl ========================================================================= dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ========================================================================= AC_DEFUN([AX_LUA_HEADERS], [ dnl Check for LUA_VERSION. AC_MSG_CHECKING([if LUA_VERSION is defined]) AS_IF([test "x$LUA_VERSION" != 'x'], [AC_MSG_RESULT([yes])], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION]) ]) dnl Make LUA_INCLUDE a precious variable. AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1]) dnl Some default directories to search. LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'` m4_define_default([_AX_LUA_INCLUDE_LIST], [ /usr/include/lua$LUA_VERSION \ /usr/include/lua-$LUA_VERSION \ /usr/include/lua/$LUA_VERSION \ /usr/include/lua$LUA_SHORT_VERSION \ /usr/local/include/lua$LUA_VERSION \ /usr/local/include/lua-$LUA_VERSION \ /usr/local/include/lua/$LUA_VERSION \ /usr/local/include/lua$LUA_SHORT_VERSION \ ]) dnl Try to find the headers. _ax_lua_saved_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) CPPFLAGS=$_ax_lua_saved_cppflags dnl Try some other directories if LUA_INCLUDE was not set. AS_IF([test "x$LUA_INCLUDE" = 'x' && test "x$ac_cv_header_lua_h" != 'xyes'], [ dnl Try some common include paths. for _ax_include_path in _AX_LUA_INCLUDE_LIST; do test ! -d "$_ax_include_path" && continue AC_MSG_CHECKING([for Lua headers in]) AC_MSG_RESULT([$_ax_include_path]) AS_UNSET([ac_cv_header_lua_h]) AS_UNSET([ac_cv_header_lualib_h]) AS_UNSET([ac_cv_header_lauxlib_h]) AS_UNSET([ac_cv_header_luaconf_h]) _ax_lua_saved_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS -I$_ax_include_path" AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) CPPFLAGS=$_ax_lua_saved_cppflags AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], [ LUA_INCLUDE="-I$_ax_include_path" break ]) done ]) AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], [ dnl Make a program to print LUA_VERSION defined in the header. dnl TODO It would be really nice if we could do this without compiling a dnl program, then it would work when cross compiling. But I'm not sure how dnl to do this reliably. For now, assume versions match when cross compiling. AS_IF([test "x$cross_compiling" != 'xyes'], [ AC_CACHE_CHECK([for Lua header version], [ax_cv_lua_header_version], [ _ax_lua_saved_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" AC_RUN_IFELSE( [ AC_LANG_SOURCE([[ #include #include #include int main(int argc, char ** argv) { if(argc > 1) printf("%s", LUA_VERSION); exit(EXIT_SUCCESS); } ]]) ], [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"` ], [ax_cv_lua_header_version='unknown']) CPPFLAGS=$_ax_lua_saved_cppflags ]) dnl Compare this to the previously found LUA_VERSION. AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], [ AC_MSG_RESULT([yes]) ax_header_version_match='yes' ], [ AC_MSG_RESULT([no]) ax_header_version_match='no' ]) ], [ AC_MSG_WARN([cross compiling so assuming header version number matches]) ax_header_version_match='yes' ]) ]) dnl Was LUA_INCLUDE specified? AS_IF([test "x$ax_header_version_match" != 'xyes' && test "x$LUA_INCLUDE" != 'x'], [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])]) dnl Test the final result and run user code. AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1], [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])]) ]) dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS. AC_DEFUN([AX_LUA_HEADERS_VERSION], [ AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]]) ]) dnl ========================================================================= dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ========================================================================= AC_DEFUN([AX_LUA_LIBS], [ dnl TODO Should this macro also check various -L flags? dnl Check for LUA_VERSION. AC_MSG_CHECKING([if LUA_VERSION is defined]) AS_IF([test "x$LUA_VERSION" != 'x'], [AC_MSG_RESULT([yes])], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION]) ]) dnl Make LUA_LIB a precious variable. AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1]) AS_IF([test "x$LUA_LIB" != 'x'], [ dnl Check that LUA_LIBS works. _ax_lua_saved_libs=$LIBS LIBS="$LIBS $LUA_LIB" AC_SEARCH_LIBS([lua_load], [], [_ax_found_lua_libs='yes'], [_ax_found_lua_libs='no']) LIBS=$_ax_lua_saved_libs dnl Check the result. AS_IF([test "x$_ax_found_lua_libs" != 'xyes'], [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])]) ], [ dnl First search for extra libs. _ax_lua_extra_libs='' _ax_lua_saved_libs=$LIBS LIBS="$LIBS $LUA_LIB" AC_SEARCH_LIBS([exp], [m]) AC_SEARCH_LIBS([dlopen], [dl]) LIBS=$_ax_lua_saved_libs AS_IF([test "x$ac_cv_search_exp" != 'xno' && test "x$ac_cv_search_exp" != 'xnone required'], [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"]) AS_IF([test "x$ac_cv_search_dlopen" != 'xno' && test "x$ac_cv_search_dlopen" != 'xnone required'], [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"]) dnl Try to find the Lua libs. _ax_lua_saved_libs=$LIBS LIBS="$LIBS $LUA_LIB" AC_SEARCH_LIBS([lua_load], [ lua$LUA_VERSION \ lua$LUA_SHORT_VERSION \ lua-$LUA_VERSION \ lua-$LUA_SHORT_VERSION \ lua \ ], [_ax_found_lua_libs='yes'], [_ax_found_lua_libs='no'], [$_ax_lua_extra_libs]) LIBS=$_ax_lua_saved_libs AS_IF([test "x$ac_cv_search_lua_load" != 'xno' && test "x$ac_cv_search_lua_load" != 'xnone required'], [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"]) ]) dnl Test the result and run user code. AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1], [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])]) ]) dnl ========================================================================= dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ========================================================================= AC_DEFUN([AX_LUA_READLINE], [ AX_LIB_READLINE AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' && test "x$ac_cv_header_readline_history_h" != 'x'], [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS" $1 ], [$2]) ]) thrift-0.16.0/aclocal/ax_prog_dotnetcore_version.m4000066400000000000000000000036151420101504100223610ustar00rootroot00000000000000# =============================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prog_dotnetcore_version.html # =============================================================================== # # SYNOPSIS # # AX_PROG_DOTNETCORE_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE]) # # DESCRIPTION # # Makes sure that .NET Core supports the version indicated. If true the # shell commands in ACTION-IF-TRUE are executed. If not the shell commands # in ACTION-IF-FALSE are run. The $dotnetcore_version variable will be # filled with the detected version. # # This macro uses the $DOTNETCORE variable to perform the check. If # $DOTNETCORE is not set prior to calling this macro, the macro will fail. # # Example: # # AC_PATH_PROG([DOTNETCORE],[dotnet]) # AC_PROG_DOTNETCORE_VERSION([1.0.2],[ ... ],[ ... ]) # # Searches for .NET Core, then checks if at least version 1.0.2 is # present. # # LICENSE # # Copyright (c) 2016 Jens Geyer # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 2 AC_DEFUN([AX_PROG_DOTNETCORE_VERSION],[ AC_REQUIRE([AC_PROG_SED]) AS_IF([test -n "$DOTNETCORE"],[ ax_dotnetcore_version="$1" AC_MSG_CHECKING([for .NET Core version]) dotnetcore_version=`$DOTNETCORE --version 2>&1 | $SED -e 's/\(@<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\)\(.*\)/\1/'` AC_MSG_RESULT($dotnetcore_version) AC_SUBST([DOTNETCORE_VERSION],[$dotnetcore_version]) AX_COMPARE_VERSION([$ax_dotnetcore_version],[le],[$dotnetcore_version],[ : $2 ],[ : $3 ]) ],[ AC_MSG_WARN([could not find .NET Core]) $3 ]) ]) thrift-0.16.0/aclocal/ax_prog_haxe_version.m4000066400000000000000000000034071420101504100211370ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prog_haxe_version.html # =========================================================================== # # SYNOPSIS # # AX_PROG_HAXE_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE]) # # DESCRIPTION # # Makes sure that haxe supports the version indicated. If true the shell # commands in ACTION-IF-TRUE are executed. If not the shell commands in # ACTION-IF-FALSE are run. The $HAXE_VERSION variable will be filled with # the detected version. # # This macro uses the $HAXE variable to perform the check. If $HAXE is not # set prior to calling this macro, the macro will fail. # # Example: # # AC_PATH_PROG([HAXE],[haxe]) # AC_PROG_HAXE_VERSION([3.1.3],[ ... ],[ ... ]) # # Searches for Haxe, then checks if at least version 3.1.3 is present. # # LICENSE # # Copyright (c) 2015 Jens Geyer # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 2 AC_DEFUN([AX_PROG_HAXE_VERSION],[ AC_REQUIRE([AC_PROG_SED]) AS_IF([test -n "$HAXE"],[ ax_haxe_version="$1" AC_MSG_CHECKING([for haxe version]) haxe_version=`$HAXE -version 2>&1 | $SED -e 's/^.* \( @<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\) .*/\1/'` AC_MSG_RESULT($haxe_version) AC_SUBST([HAXE_VERSION],[$haxe_version]) AX_COMPARE_VERSION([$ax_haxe_version],[le],[$haxe_version],[ : $2 ],[ : $3 ]) ],[ AC_MSG_WARN([could not find Haxe]) $3 ]) ]) thrift-0.16.0/aclocal/ax_prog_perl_modules.m4000066400000000000000000000043141420101504100211350ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prog_perl_modules.html # =========================================================================== # # SYNOPSIS # # AX_PROG_PERL_MODULES([MODULES], [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # # DESCRIPTION # # Checks to see if the given perl modules are available. If true the shell # commands in ACTION-IF-TRUE are executed. If not the shell commands in # ACTION-IF-FALSE are run. Note if $PERL is not set (for example by # calling AC_CHECK_PROG, or AC_PATH_PROG), AC_CHECK_PROG(PERL, perl, perl) # will be run. # # MODULES is a space separated list of module names. To check for a # minimum version of a module, append the version number to the module # name, separated by an equals sign. # # Example: # # AX_PROG_PERL_MODULES( Text::Wrap Net::LDAP=1.0.3, , # AC_MSG_WARN(Need some Perl modules) # # LICENSE # # Copyright (c) 2009 Dean Povey # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 AU_ALIAS([AC_PROG_PERL_MODULES], [AX_PROG_PERL_MODULES]) AC_DEFUN([AX_PROG_PERL_MODULES],[dnl m4_define([ax_perl_modules]) m4_foreach([ax_perl_module], m4_split(m4_normalize([$1])), [ m4_append([ax_perl_modules], [']m4_bpatsubst(ax_perl_module,=,[ ])[' ]) ]) # Make sure we have perl if test -z "$PERL"; then AC_CHECK_PROG(PERL,perl,perl) fi if test "x$PERL" != x; then ax_perl_modules_failed=0 for ax_perl_module in ax_perl_modules; do AC_MSG_CHECKING(for perl module $ax_perl_module) # Would be nice to log result here, but can't rely on autoconf internals $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1 if test $? -ne 0; then AC_MSG_RESULT(no); ax_perl_modules_failed=1 else AC_MSG_RESULT(ok); fi done # Run optional shell commands if test "$ax_perl_modules_failed" = 0; then : $2 else : $3 fi else AC_MSG_WARN(could not find perl) fi])dnl thrift-0.16.0/aclocal/ax_signed_right_shift.m4000066400000000000000000000126471420101504100212670ustar00rootroot00000000000000dnl @synopsis AX_SIGNED_RIGHT_SHIFT dnl dnl Tests the behavior of a right shift on a negative signed int. dnl dnl This macro calls: dnl AC_DEFINE(SIGNED_RIGHT_SHIFT_IS) dnl AC_DEFINE(ARITHMETIC_RIGHT_SHIFT) dnl AC_DEFINE(LOGICAL_RIGHT_SHIFT) dnl AC_DEFINE(UNKNOWN_RIGHT_SHIFT) dnl dnl SIGNED_RIGHT_SHIFT_IS will be equal to one of the other macros. dnl It also leaves the shell variables "ax_signed_right_shift" dnl set to "arithmetic", "logical", or "unknown". dnl dnl NOTE: This macro does not work for cross-compiling. dnl dnl @category C dnl @version 2009-03-25 dnl @license AllPermissive dnl dnl Copyright (C) 2009 David Reiss dnl Copying and distribution of this file, with or without modification, dnl are permitted in any medium without royalty provided the copyright dnl notice and this notice are preserved. AC_DEFUN([AX_SIGNED_RIGHT_SHIFT], [ AC_MSG_CHECKING(the behavior of a signed right shift) success_arithmetic=no AC_RUN_IFELSE([AC_LANG_PROGRAM([[]], [[ return /* 0xffffffff */ -1 >> 1 != -1 || -1 >> 2 != -1 || -1 >> 3 != -1 || -1 >> 4 != -1 || -1 >> 8 != -1 || -1 >> 16 != -1 || -1 >> 24 != -1 || -1 >> 31 != -1 || /* 0x80000000 */ (-2147483647 - 1) >> 1 != -1073741824 || (-2147483647 - 1) >> 2 != -536870912 || (-2147483647 - 1) >> 3 != -268435456 || (-2147483647 - 1) >> 4 != -134217728 || (-2147483647 - 1) >> 8 != -8388608 || (-2147483647 - 1) >> 16 != -32768 || (-2147483647 - 1) >> 24 != -128 || (-2147483647 - 1) >> 31 != -1 || /* 0x90800000 */ -1870659584 >> 1 != -935329792 || -1870659584 >> 2 != -467664896 || -1870659584 >> 3 != -233832448 || -1870659584 >> 4 != -116916224 || -1870659584 >> 8 != -7307264 || -1870659584 >> 16 != -28544 || -1870659584 >> 24 != -112 || -1870659584 >> 31 != -1 || 0; ]])], [ success_arithmetic=yes ]) success_logical=no AC_RUN_IFELSE([AC_LANG_PROGRAM([[]], [[ return /* 0xffffffff */ -1 >> 1 != (signed)((unsigned)-1 >> 1) || -1 >> 2 != (signed)((unsigned)-1 >> 2) || -1 >> 3 != (signed)((unsigned)-1 >> 3) || -1 >> 4 != (signed)((unsigned)-1 >> 4) || -1 >> 8 != (signed)((unsigned)-1 >> 8) || -1 >> 16 != (signed)((unsigned)-1 >> 16) || -1 >> 24 != (signed)((unsigned)-1 >> 24) || -1 >> 31 != (signed)((unsigned)-1 >> 31) || /* 0x80000000 */ (-2147483647 - 1) >> 1 != (signed)((unsigned)(-2147483647 - 1) >> 1) || (-2147483647 - 1) >> 2 != (signed)((unsigned)(-2147483647 - 1) >> 2) || (-2147483647 - 1) >> 3 != (signed)((unsigned)(-2147483647 - 1) >> 3) || (-2147483647 - 1) >> 4 != (signed)((unsigned)(-2147483647 - 1) >> 4) || (-2147483647 - 1) >> 8 != (signed)((unsigned)(-2147483647 - 1) >> 8) || (-2147483647 - 1) >> 16 != (signed)((unsigned)(-2147483647 - 1) >> 16) || (-2147483647 - 1) >> 24 != (signed)((unsigned)(-2147483647 - 1) >> 24) || (-2147483647 - 1) >> 31 != (signed)((unsigned)(-2147483647 - 1) >> 31) || /* 0x90800000 */ -1870659584 >> 1 != (signed)((unsigned)-1870659584 >> 1) || -1870659584 >> 2 != (signed)((unsigned)-1870659584 >> 2) || -1870659584 >> 3 != (signed)((unsigned)-1870659584 >> 3) || -1870659584 >> 4 != (signed)((unsigned)-1870659584 >> 4) || -1870659584 >> 8 != (signed)((unsigned)-1870659584 >> 8) || -1870659584 >> 16 != (signed)((unsigned)-1870659584 >> 16) || -1870659584 >> 24 != (signed)((unsigned)-1870659584 >> 24) || -1870659584 >> 31 != (signed)((unsigned)-1870659584 >> 31) || 0; ]])], [ success_logical=yes ]) AC_DEFINE([ARITHMETIC_RIGHT_SHIFT], 1, [Possible value for SIGNED_RIGHT_SHIFT_IS]) AC_DEFINE([LOGICAL_RIGHT_SHIFT], 2, [Possible value for SIGNED_RIGHT_SHIFT_IS]) AC_DEFINE([UNKNOWN_RIGHT_SHIFT], 3, [Possible value for SIGNED_RIGHT_SHIFT_IS]) if test "$success_arithmetic" = "yes" && test "$success_logical" = "yes" ; then AC_MSG_ERROR("Right shift appears to be both arithmetic and logical!") elif test "$success_arithmetic" = "yes" ; then ax_signed_right_shift=arithmetic AC_DEFINE([SIGNED_RIGHT_SHIFT_IS], 1, [Indicates the effect of the right shift operator on negative signed integers]) elif test "$success_logical" = "yes" ; then ax_signed_right_shift=logical AC_DEFINE([SIGNED_RIGHT_SHIFT_IS], 2, [Indicates the effect of the right shift operator on negative signed integers]) else ax_signed_right_shift=unknown AC_DEFINE([SIGNED_RIGHT_SHIFT_IS], 3, [Indicates the effect of the right shift operator on negative signed integers]) fi AC_MSG_RESULT($ax_signed_right_shift) ]) thrift-0.16.0/aclocal/ax_thrift_internal.m4000066400000000000000000000021051420101504100206040ustar00rootroot00000000000000dnl @synopsis AX_THRIFT_GEN(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) dnl @synopsis AX_THRIFT_LIB(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) dnl dnl Allow a particular language generator to be disabled. dnl Allow a particular language library to be disabled. dnl dnl These macros have poor error handling and are poorly documented. dnl They are intended only for internal use by the Thrift compiler. dnl dnl @version 2008-02-20 dnl @license AllPermissive dnl dnl Copyright (C) 2009 David Reiss dnl Copying and distribution of this file, with or without modification, dnl are permitted in any medium without royalty provided the copyright dnl notice and this notice are preserved. AC_DEFUN([AX_THRIFT_LIB], [ AC_ARG_WITH($1, AC_HELP_STRING([--with-$1], [build the $2 library @<:@default=$3@:>@]), [with_$1="$withval"], [with_$1=$3] ) have_$1=no dnl What we do here is going to vary from library to library, dnl so we can't really generalize (yet!). ]) thrift-0.16.0/aclocal/tar.m4000066400000000000000000000107031420101504100155110ustar00rootroot00000000000000# Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --hard-dereference --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --hard-dereference --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf --hard-dereference - "$$tardir"' am__tar_='tar chf --hard-dereference - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR thrift-0.16.0/appveyor.yml000077500000000000000000000065341420101504100154650ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # build Apache Thrift on AppVeyor - https://ci.appveyor.com version: '0.16.0.{build}' shallow_clone: true branches: only: - master - /^(release/)?\d+\.\d+\.\d+$/ # Note: We could abort all jobs on the first error, but then it # becomes hard to learn from the other jobs results. Therefore disabled: #matrix: # fast_finish: true environment: matrix: - PROFILE: MSVC2017 PROFILE_CLASS: MSVC APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PLATFORM: x64 CONFIGURATION: Release BUILD_SHARED_LIBS: ON BOOST_VERSION: 1.67.0 LIBEVENT_VERSION: 2.1.8 PYTHON_VERSION: 3.6 QT_VERSION: 5.10 ZLIB_VERSION: 1.2.11 - PROFILE: MSVC2015 PROFILE_CLASS: MSVC APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PLATFORM: x86 CONFIGURATION: Debug BUILD_SHARED_LIBS: OFF BOOST_VERSION: 1.62.0 LIBEVENT_VERSION: 2.0.22 PYTHON_VERSION: 3.5 QT_VERSION: 5.8 ZLIB_VERSION: 1.2.8 - PROFILE: MINGW PROFILE_CLASS: MINGW # Currently the the latest MSYS2 is in the following image: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 PLATFORM: x64 CONFIGURATION: RelWithDebInfo DISABLED_TESTS: (StalenessCheckTest) # As of 2021.08.06, the Cygwin build is broken with a missing dll exception. # See for an example https://ci.appveyor.com/project/ApacheSoftwareFoundation/thrift/builds/40263513/job/a69xt6m4o0y9x1bw?fullLog=true # - PROFILE: CYGWIN # PROFILE_CLASS: CYGWIN # PLATFORM: x64 # CONFIGURATION: RelWithDebInfo # DISABLED_TESTS: (ZlibTest|OpenSSLManualInitTest|TNonblockingServerTest) build_script: - cd %APPVEYOR_BUILD_FOLDER% - call build\appveyor\%PROFILE_CLASS%-appveyor-full.bat # artifact capture disabled as it might increase service cost for little gain: # # artifacts: # - path: local-thrift-inst # name: cmake installed content # type: zip # # - path: local-thrift-build\Testing # name: ctest output # type: zip # RDP support: use one or the other... # # enables RDP for each build job so you can inspect the environment at the beginning of the job: # init: # - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) # # enables RDP at the end of the build job so you can login and re-run # commands to see why something failed... # on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) # # also need: # environment: # APPVEYOR_RDP_PASSWORD: thr1FT2345$xyzZ thrift-0.16.0/bootstrap.sh000077500000000000000000000036111420101504100154370ustar00rootroot00000000000000#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # echo -n "make distclean... " make -k distclean >/dev/null 2>&1 echo "ok" if test -d lib/php/src/ext/thrift_protocol ; then if phpize -v >/dev/null 2>/dev/null ; then (cd lib/php/src/ext/thrift_protocol && phpize) fi fi set -e # libtoolize is called "glibtoolize" on OSX. if libtoolize --version 1 >/dev/null 2>/dev/null; then LIBTOOLIZE=libtoolize elif glibtoolize --version 1 >/dev/null 2>/dev/null; then LIBTOOLIZE=glibtoolize else echo >&2 "Couldn't find libtoolize!" exit 1 fi format_version () { printf "%03d%03d%03d%03d" $(echo $1 | tr '.' ' '); } # we require automake 1.13 or later # check must happen externally due to use of newer macro AUTOMAKE_VERSION=`automake --version | grep automake | egrep -o '([0-9]{1,}\.)+[0-9]{1,}'` if [ $(format_version $AUTOMAKE_VERSION) -lt $(format_version 1.13) ]; then echo >&2 "automake version $AUTOMAKE_VERSION is too old (need 1.13 or later)" exit 1 fi set -e autoscan $LIBTOOLIZE --copy --automake aclocal -I ./aclocal autoheader sed '/undef VERSION/d' config.hin > config.hin2 mv config.hin2 config.hin autoconf automake --copy --add-missing thrift-0.16.0/bower.json000066400000000000000000000004641420101504100150770ustar00rootroot00000000000000{ "name": "thrift", "version": "0.16.0", "homepage": "https://github.com/apache/thrift.git", "authors": [ "Apache Thrift " ], "description": "Apache Thrift", "main": "lib/js/src/thrift.js", "keywords": [ "thrift" ], "license": "Apache v2", "ignore": [] } thrift-0.16.0/build/000077500000000000000000000000001420101504100141615ustar00rootroot00000000000000thrift-0.16.0/build/appveyor/000077500000000000000000000000001420101504100160265ustar00rootroot00000000000000thrift-0.16.0/build/appveyor/CYGWIN-appveyor-full.bat000066400000000000000000000051671420101504100223320ustar00rootroot00000000000000:: :: 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. :: :: :: Appveyor script for CYGWIN :: :: :: Installs third party packages we need for a cmake build :: @ECHO ON SETLOCAL EnableDelayedExpansion CD build\appveyor || EXIT /B SET APPVEYOR_SCRIPTS=%APPVEYOR_BUILD_FOLDER%\build\appveyor SET BUILDDIR=%APPVEYOR_BUILD_FOLDER%\..\build\%PROFILE%\%PLATFORM% SET INSTDIR=%APPVEYOR_BUILD_FOLDER%\..\install\%PROFILE%\%PLATFORM% SET SRCDIR=%APPVEYOR_BUILD_FOLDER% :: compiler and generator detection SET COMPILER=gcc SET GENERATOR=Unix Makefiles IF "%PLATFORM%" == "x64" ( SET CYGWINROOT=C:\cygwin64 ) ELSE ( SET CYGWINROOT=C:\cygwin ) IF "%PLATFORM%" == "x64" ( SET SETUP=!CYGWINROOT!\setup-x86_64.exe ) ELSE ( SET SETUP=!CYGWINROOT!\setup-x86.exe ) SET BASH=!CYGWINROOT!\bin\bash.exe SET BUILDDIR=%BUILDDIR:\=/% SET BUILDDIR=/cygdrive/c!BUILDDIR:~2! SET INSTDIR=%INSTDIR:\=/% SET INSTDIR=/cygdrive/c!INSTDIR:~2! SET SRCDIR=%SRCDIR:\=/% SET SRCDIR=/cygdrive/c!SRCDIR:~2! CALL win_showenv.bat || EXIT /B :: :: Install apt-cyg for package management because its easier to use :: than Cygwins setup.exe. But both are possible to use. :: %BASH% -lc "wget https://rawgit.com/transcode-open/apt-cyg/master/apt-cyg && install apt-cyg /bin && rm -f apt-cyg" || EXIT /B %BASH% -lc "apt-cyg update" || EXIT /B %BASH% -lc "apt-cyg install unzip xz cmake make bison flex gcc-g++ libboost-devel libevent-devel openssl-devel zlib-devel" || EXIT /B :: :: Configure and build our software with cmake :: SET CMAKEARGS=^ -G'%GENERATOR%' ^ -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^ -DCMAKE_INSTALL_PREFIX=%INSTDIR% ^ -DCMAKE_CXX_FLAGS="-D_GNU_SOURCE" ^ -DWITH_JAVA=OFF ^ -DWITH_PYTHON=OFF :: -DCMAKE_CXX_EXTENSIONS=ON ^ :: -DCMAKE_CXX_STANDARD=11 ^ %BASH% -lc "mkdir -p %BUILDDIR% && cd %BUILDDIR% && cmake.exe %SRCDIR% %CMAKEARGS% && cmake --build . --config %CONFIGURATION% && cmake --install . --config %CONFIGURATION%" || EXIT /B :: :: Execute our tests :: SET DISABLED_TESTS_COMMAND=--exclude-regex '%DISABLED_TESTS%' %BASH% -lc "cd %BUILDDIR% && ctest.exe --build-config %CONFIGURATION% --timeout 300 --extra-verbose %DISABLED_TESTS_COMMAND%" || EXIT /B thrift-0.16.0/build/appveyor/MINGW-appveyor-full.bat000066400000000000000000000077571420101504100222220ustar00rootroot00000000000000:: :: 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. :: :: :: Appveyor script for MINGW on MSYS2 :: :: :: Installs third party packages we need for a cmake build :: @ECHO ON SETLOCAL EnableDelayedExpansion CD build\appveyor || EXIT /B SET APPVEYOR_SCRIPTS=%APPVEYOR_BUILD_FOLDER%\build\appveyor SET BUILDDIR=%APPVEYOR_BUILD_FOLDER%\..\build\%PROFILE%\%PLATFORM% SET INSTDIR=%APPVEYOR_BUILD_FOLDER%\..\install\%PROFILE%\%PLATFORM% SET SRCDIR=%APPVEYOR_BUILD_FOLDER% :: PLATFORM is x86 or x64 :: NORM_PLATFORM is 32 or 64 IF "%PLATFORM%" == "x86" ( SET NORM_PLATFORM=32 ) ELSE ( SET NORM_PLATFORM=64 ) :: PLATFORM = x86 means MINGWPLAT i686 :: PLATFORM = x64 means MINGWPLAT x86_64 IF "%PLATFORM%" == "x86" ( SET MINGWPLAT=i686 ) ELSE ( SET MINGWPLAT=x86_64 ) :: compiler and generator detection SET COMPILER=gcc SET GENERATOR=MinGW Makefiles SET BASH=C:\msys64\usr\bin\bash.exe !BASH! -lc "sed -i '/export PATH=\/mingw32\/bin/d' ~/.bash_profile && sed -i '/export PATH=\/mingw64\/bin/d' ~/.bash_profile && echo 'export PATH=/mingw%NORM_PLATFORM%/bin:$PATH' >> ~/.bash_profile" || EXIT /B SET BUILDDIR=%BUILDDIR:\=/% SET BUILDDIR=/c!BUILDDIR:~2! SET INSTDIR=%INSTDIR:\=/% SET INSTDIR=/c!INSTDIR:~2! SET SRCDIR=%SRCDIR:\=/% SET SRCDIR=/c!SRCDIR:~2! CALL win_showenv.bat || EXIT /B SET PACKAGES=^ base-devel ^ mingw-w64-x86_64-toolchain ^ bison ^ flex ^ make ^ mingw-w64-%MINGWPLAT%-boost ^ mingw-w64-%MINGWPLAT%-cmake ^ mingw-w64-%MINGWPLAT%-libevent ^ mingw-w64-%MINGWPLAT%-openssl ^ mingw-w64-%MINGWPLAT%-toolchain ^ mingw-w64-%MINGWPLAT%-zlib ::mingw-w64-%MINGWPLAT%-qt5 : WAY too large (1GB download!) - tested in cygwin builds anyway :: Upgrade things %BASH% -lc "pacman --noconfirm -Syu %IGNORE%" || EXIT /B %BASH% -lc "pacman --noconfirm -Su %IGNORE%" || EXIT /B %BASH% -lc "pacman --noconfirm --needed -S %PACKAGES%" || EXIT /B :: These instructions are for a manual update of specific package versions. :: Fall back to this in case the above does not work anymore (broken upstream). :::: Updata the new key ::%BASH% -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-1~20210213-2-any.pkg.tar.xz" || EXIT /B ::%BASH% -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-1~20210213-2-any.pkg.tar.xz.sig" || EXIT /B ::%BASH% -lc "pacman-key --verify msys2-keyring-1~20210213-2-any.pkg.tar.xz.sig" || EXIT /B ::%BASH% -lc "pacman --noconfirm -U --config <(echo) msys2-keyring-1~20210213-2-any.pkg.tar.xz" || EXIT /B :::: Upgrade things ::%BASH% -lc "pacman --noconfirm -Sy" || EXIT /B ::%BASH% -lc "pacman --noconfirm -Udd https://repo.msys2.org/msys/x86_64/pacman-5.2.2-5-x86_64.pkg.tar.xz" || EXIT /B ::%BASH% -lc "pacman --noconfirm --needed -S %PACKAGES%" || EXIT /B :: :: Configure and build our software with cmake :: SET CMAKEARGS=^ -G'%GENERATOR%' ^ -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^ -DCMAKE_INSTALL_PREFIX=%INSTDIR% ^ -DCMAKE_MAKE_PROGRAM=/mingw%NORM_PLATFORM%/bin/mingw32-make ^ -DCMAKE_C_COMPILER=/mingw%NORM_PLATFORM%/bin/gcc.exe ^ -DCMAKE_CXX_COMPILER=/mingw%NORM_PLATFORM%/bin/g++.exe ^ -DOPENSSL_ROOT_DIR=/mingw%NORM_PLATFORM% ^ -DWITH_PYTHON=OFF %BASH% -lc "mkdir -p %BUILDDIR% && cd %BUILDDIR% && cmake.exe %SRCDIR% %CMAKEARGS% && cmake --build . --config %CONFIGURATION% && cmake --install . --config %CONFIGURATION%" || EXIT /B :: :: Execute our tests :: SET DISABLED_TESTS_COMMAND=--exclude-regex '%DISABLED_TESTS%' %BASH% -lc "cd %BUILDDIR% && ctest.exe --build-config %CONFIGURATION% --timeout 300 --extra-verbose %DISABLED_TESTS_COMMAND%" || EXIT /B thrift-0.16.0/build/appveyor/MSVC-appveyor-full.bat000066400000000000000000000145151420101504100220770ustar00rootroot00000000000000:: :: 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. :: :: :: Appveyor script for MSVC :: :: :: Installs (or builds) third party packages we need :: @ECHO ON SETLOCAL EnableDelayedExpansion CD build\appveyor || EXIT /B SET APPVEYOR_SCRIPTS=%APPVEYOR_BUILD_FOLDER%\build\appveyor SET BUILDDIR=%APPVEYOR_BUILD_FOLDER%\..\build\%PROFILE%\%PLATFORM% SET INSTDIR=%APPVEYOR_BUILD_FOLDER%\..\install\%PROFILE%\%PLATFORM% SET SRCDIR=%APPVEYOR_BUILD_FOLDER% IF "%PROFILE%" == "MSVC2015" ( IF "%PLATFORM%" == "x86" ( CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 || EXIT /B ) ELSE ( CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 || EXIT /B CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 || EXIT /B ) ) ELSE IF "%PROFILE%" == "MSVC2017" ( IF "%PLATFORM%" == "x86" ( CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" || EXIT /B ) ELSE ( CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" || EXIT /B ) ) ELSE IF "%PROFILE%" == "MSVC2019" ( IF "%PLATFORM%" == "x86" ( CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat" || EXIT /B ) ELSE ( CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" || EXIT /B ) ) ELSE ( ECHO Unsupported PROFILE=%PROFILE% or PLATFORM=%PLATFORM% EXIT /B 1 ) :: compiler and generator detection IF /i "%PLATFORM%" == "x64" SET GENARCH= Win64 IF "%PROFILE%" == "MSVC2015" ( SET GENERATOR=Visual Studio 14 2015!GENARCH! SET COMPILER=vc140 ) ELSE IF "%PROFILE%" == "MSVC2017" ( SET GENERATOR=Visual Studio 15 2017!GENARCH! SET COMPILER=vc141 ) ELSE IF "%PROFILE%" == "MSVC2019" ( SET GENERATOR=Visual Studio 16 2019!GENARCH! SET COMPILER=vc142 ) ELSE ( ECHO [error] unable to determine the CMake generator and compiler to use from MSVC profile %PROFILE% EXIT /B 1 ) :: PLATFORM is x86 or x64 :: NORM_PLATFORM is 32 or 64 IF "%PLATFORM%" == "x86" ( SET NORM_PLATFORM=32 ) ELSE ( SET NORM_PLATFORM=64 ) :: FindBoost needs forward slashes so cmake doesn't see something as an escaped character SET BOOST_ROOT=C:/Libraries/boost_%BOOST_VERSION:.=_% SET BOOST_LIBRARYDIR=!BOOST_ROOT!/lib%NORM_PLATFORM%-msvc-%COMPILER:~-3,2%.%COMPILER:~-1,1% SET OPENSSL_ROOT=C:\OpenSSL-Win%NORM_PLATFORM% SET WIN3P=%APPVEYOR_BUILD_FOLDER%\thirdparty IF "%PYTHON_VERSION%" == "" ( SET WITH_PYTHON=OFF ) ELSE ( SET WITH_PYTHON=ON IF /i "%PLATFORM%" == "x64" (SET PTEXT=-x64) SET PATH=C:\Python%PYTHON_VERSION:.=%!PTEXT!\scripts;C:\Python%PYTHON_VERSION:.=%!PTEXT!;!PATH! ) IF "%CONFIGURATION%" == "Debug" (SET ZLIB_LIB_SUFFIX=d) IF NOT "%QT_VERSION%" == "" ( IF /i "%PLATFORM%" == "x64" (SET QTEXT=_64) SET PATH=C:\Qt\%QT_VERSION%\%PROFILE%!QTEXT!\bin;!PATH! ) CALL win_showenv.bat || EXIT /B MKDIR "%WIN3P%" || EXIT /B choco feature enable -n allowGlobalConfirmation || EXIT /B :: Things to install when NOT running in appveyor: IF "%APPVEYOR_BUILD_ID%" == "" ( cup -y chocolatey || EXIT /B cinst -y curl || EXIT /B cinst -y 7zip || EXIT /B cinst -y python3 || EXIT /B cinst -y openssl.light || EXIT /B ) cinst -y jdk8 || EXIT /B cinst -y winflexbison3 || EXIT /B :: zlib - not available through chocolatey CD "%APPVEYOR_SCRIPTS%" || EXIT /B call build-zlib.bat || EXIT /B :: libevent - not available through chocolatey CD "%APPVEYOR_SCRIPTS%" || EXIT /B call build-libevent.bat || EXIT /B :: python packages (correct path to pip set above) pip.exe ^ install backports.ssl_match_hostname ^ ipaddress ^ six ^ tornado ^ twisted || EXIT /B :: Adobe Flex SDK 4.6 for ActionScript MKDIR "C:\Adobe\Flex\SDK\4.6" || EXIT /B appveyor DownloadFile http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip -FileName C:\Adobe\Flex\SDK\4.6\SDK.zip || EXIT /B CD "C:\Adobe\Flex\SDK\4.6" || EXIT /B 7z x SDK.zip || EXIT /B SETX FLEX_HOME "C:\Adobe\Flex\SDK\4.6" :: :: Configure and build our software with cmake :: MKDIR "%BUILDDIR%" || EXIT /B CD "%BUILDDIR%" || EXIT /B :: When libraries cannot be found, things might have been updated :: so uncomment this and submit a pull request to see what's there :: now... :: DIR C:\Libraries :: DIR C:\Libraries\boost_1_69_0\lib* :: DIR C:\Libraries\boost_1_68_0\lib* :: DIR C:\Libraries\boost_1_67_0\lib* :: DIR C:\Libraries\boost_1_66_0\lib* :: DIR C:\Libraries\boost_1_65_0\lib* :: DIR C:\Libraries\boost_1_64_0\lib* :: DIR C:\Libraries\boost_1_63_0\lib* :: DIR C:\Libraries\boost_1_62_0\lib* :: DIR C:\Libraries\boost_1_61_0\lib* :: DIR C:\Libraries\boost_1_60_0\lib* cmake.exe "%SRCDIR%" ^ -G"%GENERATOR%" ^ -DBISON_EXECUTABLE="C:\ProgramData\chocolatey\lib\winflexbison3\tools\win_bison.exe" ^ -DBOOST_ROOT="%BOOST_ROOT%" ^ -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" ^ -DBUILD_SHARED_LIBS="%BUILD_SHARED_LIBS%" ^ -DCMAKE_BUILD_TYPE="%CONFIGURATION%" ^ -DCMAKE_INSTALL_PREFIX="%INSTDIR%" ^ -DFLEX_EXECUTABLE="C:\ProgramData\chocolatey\lib\winflexbison3\tools\win_flex.exe" ^ -DLIBEVENT_ROOT="%WIN3P%\libevent-%LIBEVENT_VERSION%-stable" ^ -DOPENSSL_ROOT_DIR="%OPENSSL_ROOT%" ^ -DOPENSSL_USE_STATIC_LIBS=OFF ^ -DZLIB_LIBRARY="%WIN3P%\zlib-inst\lib\zlib%ZLIB_LIB_SUFFIX%.lib" ^ -DZLIB_ROOT="%WIN3P%\zlib-inst" ^ -DWITH_PYTHON=%WITH_PYTHON% || EXIT /B cmake.exe --build . --config "%CONFIGURATION%" || EXIT /B cmake.exe --install . --config "%CONFIGURATION%" || EXIT /B :: :: Execute our tests :: :: Add directories to the path to find DLLs of third party libraries so tests run properly! SET PATH=%BOOST_LIBRARYDIR:/=\%;%OPENSSL_ROOT%\bin;%WIN3P%\zlib-inst\bin;%PATH% SET DISABLED_TESTS_COMMAND=--exclude-regex '%DISABLED_TESTS%' ctest.exe --build-config %CONFIGURATION% --timeout 300 --extra-verbose %DISABLED_TESTS_COMMAND% || EXIT /B thrift-0.16.0/build/appveyor/MSYS-appveyor-full.bat000066400000000000000000000053211420101504100221150ustar00rootroot00000000000000:: :: 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. :: :: :: Appveyor script for MSYS :: :: :: Installs third party packages we need for a cmake build :: @ECHO ON SETLOCAL EnableDelayedExpansion CD build\appveyor || EXIT /B SET APPVEYOR_SCRIPTS=%APPVEYOR_BUILD_FOLDER%\build\appveyor SET BUILDDIR=%APPVEYOR_BUILD_FOLDER%\..\build\%PROFILE%\%PLATFORM% SET INSTDIR=%APPVEYOR_BUILD_FOLDER%\..\install\%PROFILE%\%PLATFORM% SET SRCDIR=%APPVEYOR_BUILD_FOLDER% ECHO Unsupported PROFILE=%PROFILE% or PLATFORM=%PLATFORM% EXIT /B 1 SET BASH=C:\msys64\usr\bin\bash SET CMAKE=/c/msys64/mingw64/bin/cmake.exe CALL win_showenv.bat || EXIT /B SET PACKAGES=^ base-devel ^ mingw-w64-x86_64-toolchain ^ bison ^ flex ^ make ^ mingw-w64-x86_64-cmake ^ mingw-w64-x86_64-libevent ^ mingw-w64-x86_64-openssl ^ mingw-w64-x86_64-zlib :: Upgrade things %BASH% -lc "pacman --noconfirm -Syu %IGNORE%" || EXIT /B %BASH% -lc "pacman --noconfirm -Su %IGNORE%" || EXIT /B %BASH% -lc "pacman --noconfirm --needed -S %PACKAGES%" || EXIT /B :: :: Configure and build our software with cmake :: SET CMAKEARGS=^ -G'%GENERATOR%' ^ -DBoost_DEBUG=ON ^ -DBoost_NAMESPACE=libboost ^ -DBOOST_INCLUDEDIR=%BOOST_INCLUDEDIR% ^ -DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% ^ -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^ -DCMAKE_C_COMPILER=gcc.exe ^ -DCMAKE_CXX_COMPILER=g++.exe ^ -DCMAKE_MAKE_PROGRAM=make.exe ^ -DCMAKE_INSTALL_PREFIX=%INSTDIR_MSYS% ^ -DLIBEVENT_ROOT=%LIBEVENT_ROOT% ^ -DOPENSSL_LIBRARIES=%OPENSSL_LIBRARIES% ^ -DOPENSSL_ROOT_DIR=%OPENSSL_ROOT% ^ -DOPENSSL_USE_STATIC_LIBS=ON ^ -DWITH_BOOST_STATIC=ON ^ -DWITH_JAVA=OFF ^ -DWITH_LIBEVENT=ON ^ -DWITH_PYTHON=%WITH_PYTHON% ^ -DWITH_SHARED_LIB=OFF ^ -DWITH_STATIC_LIB=ON %BASH% -lc "mkdir %BUILDDIR% && cd %BUILDDIR% && %CMAKE% %SRCDIR_MSYS% %CMAKEARGS% && %CMAKE% --build . --config %CONFIGURATION% && %CMAKE% --install . --config %CONFIGURATION%" || EXIT /B :: :: Execute our tests :: :: This test randomly fails on mingw; see Jira THRIFT-4106 SET DISABLED_TESTS=(concurrency_test) SET DISABLED_TESTS_COMMAND=--exclude-regex '%DISABLED_TESTS%' %BASH% -lc "cd %BUILDDIR% && ctest.exe --build-config %CONFIGURATION% --timeout 300 --extra-verbose %DISABLED_TESTS_COMMAND%" || EXIT /B thrift-0.16.0/build/appveyor/README.md000066400000000000000000000016051420101504100173070ustar00rootroot00000000000000 # AppVeyor Build AppVeyor is capable of building MSVC as well as MSYS2, MinGW and Cygwin builds targeting the MS Windows platform. It has many versions of boost and python installed as well. See what appveyor has [installed on build workers](https://www.appveyor.com/docs/installed-software/). We run a matrix build on AppVeyor. See appveyor.yml for more details. thrift-0.16.0/build/appveyor/build-libevent.bat000066400000000000000000000025701420101504100214270ustar00rootroot00000000000000:: :: 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. :: SETLOCAL EnableDelayedExpansion SET URLFILE=libevent-%LIBEVENT_VERSION%-stable.tar.gz SET URL=https://github.com/libevent/libevent/releases/download/release-%LIBEVENT_VERSION%-stable/%URLFILE% :: Download - support running a local build or a build in appveyor CD "%WIN3P%" || EXIT /B IF "%APPVEYOR_BUILD_ID%" == "" ( curl -L -f -o "%URLFILE%" "%URL%" ) ELSE ( appveyor DownloadFile "%URL%" ) 7z x "%URLFILE%" -so | 7z x -si -ttar > nul || EXIT /B CD "libevent-%LIBEVENT_VERSION%-stable" || EXIT /B nmake -f Makefile.nmake static_libs || EXIT /B :: in libevent 2.0 there is no nmake subdirectory in WIN32-Code, but in 2.1 there is mkdir lib || EXIT /B move *.lib lib\ || EXIT /B move WIN32-Code\event2\* include\event2\ || move WIN32-Code\nmake\event2\* include\event2\ || EXIT /B move *.h include\ || EXIT /B ENDLOCAL thrift-0.16.0/build/appveyor/build-zlib.bat000066400000000000000000000032061420101504100205540ustar00rootroot00000000000000:: :: 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. :: SETLOCAL EnableDelayedExpansion SET PACKAGE=zlib-%ZLIB_VERSION% SET BUILDDIR=%WIN3P%\zlib-build SET INSTDIR=%WIN3P%\zlib-inst SET SRCDIR=%WIN3P%\%PACKAGE% SET URLFILE=%PACKAGE%.tar.gz :: This allows us to tolerate when the current version is archived SET URL=http://zlib.net/%URLFILE% SET FURL=http://zlib.net/fossils/%URLFILE% :: Download - support running a local build or a build in appveyor CD "%WIN3P%" || EXIT /B IF "%APPVEYOR_BUILD_ID%" == "" ( curl -L -f -o "%URLFILE%" "%URL%" IF ERRORLEVEL 1 ( curl -L -f -o "%URLFILE%" "%FURL%" ) ) ELSE ( appveyor DownloadFile "%URL%" IF ERRORLEVEL 1 ( appveyor DownloadFile "%FURL%" || EXIT /B ) ) 7z x "%URLFILE%" -so | 7z x -si -ttar > nul || EXIT /B :: Generate MKDIR "%BUILDDIR%" || EXIT /B CD "%BUILDDIR%" || EXIT /B cmake "%SRCDIR%" ^ -G"NMake Makefiles" ^ -DCMAKE_INSTALL_PREFIX="%INSTDIR%" ^ -DCMAKE_BUILD_TYPE="%CONFIGURATION%" || EXIT /B :: Build nmake /fMakefile install || EXIT /B IF "%CONFIGURATION%" == "Debug" ( COPY "%BUILDDIR%\zlibd.pdb" "%INSTDIR%\bin\" || EXIT /B ) ENDLOCAL thrift-0.16.0/build/appveyor/simulate-appveyor.bat000066400000000000000000000016611420101504100222100ustar00rootroot00000000000000:: :: 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. :: :: :: Helps build thrift by pretending to be appveyor :: Usage: :: cd build\appveyor :: simulate-appveyor.bat [Debug|Release] [x86|x64] [CYGWIN|MINGW|MSVC201?] :: SETLOCAL EnableDelayedExpansion SET APPVEYOR_BUILD_FOLDER=%~dp0..\.. SET CONFIGURATION=%1 SET PLATFORM=%2 SET PROFILE=%3 CD %APPVEYOR_BUILD_FOLDER% CALL build\appveyor\%PROFILE_CLASS%-appveyor-full.bat || EXIT /B thrift-0.16.0/build/appveyor/win_showenv.bat000066400000000000000000000046541420101504100210750ustar00rootroot00000000000000:: :: 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. :: ECHO/ ECHO =============================================================================== IF "%PROFILE_CLASS%" == "MSVC" ( ECHO Versions ECHO ------------------------------------------------------------------------------- ECHO boost = %BOOST_VERSION% ECHO libevent = %LIBEVENT_VERSION% ECHO python = %PYTHON_VERSION% ECHO qt = %QT_VERSION% ECHO zlib = %ZLIB_VERSION% ECHO/ ) ECHO Appveyor Variables ECHO ------------------------------------------------------------------------------- ECHO APPVEYOR_BUILD_FOLDER = %APPVEYOR_BUILD_FOLDER% ECHO CONFIGURATION = %CONFIGURATION% ECHO PLATFORM = %PLATFORM% ECHO PROFILE = %PROFILE% ECHO/ ECHO Our Variables ECHO ------------------------------------------------------------------------------- ECHO APPVEYOR_SCRIPTS = %APPVEYOR_SCRIPTS% ECHO BASH = %BASH% ECHO BOOST_ROOT = %BOOST_ROOT% ECHO BOOST_INCLUDEDIR = %BOOST_INCLUDEDIR% ECHO BOOST_LIBRARYDIR = %BOOST_LIBRARYDIR% ECHO BUILDDIR = %BUILDDIR% ECHO COMPILER = %COMPILER% ECHO GENERATOR = %GENERATOR% ECHO INSTDIR = %INSTDIR% ECHO JAVA_HOME = %JAVA_HOME% ECHO OPENSSL_ROOT = %OPENSSL_ROOT% ECHO SETUP = %SETUP% ECHO SRCDIR = %SRCDIR% ECHO WIN3P = %WIN3P% ECHO WITH_PYTHON = %WITH_PYTHON% ECHO ZLIB_STATIC_SUFFIX = %ZLIB_STATIC_SUFFIX% IF NOT "%PROFILE_CLASS%" == "MSVC" ( ECHO/ ECHO UNIXy PATH ECHO ------------------------------------------------------------------------------- %BASH% -lc "echo $PATH" ) ECHO/ ECHO Windows PATH ECHO ------------------------------------------------------------------------------- ECHO %PATH% ECHO =============================================================================== ECHO/ thrift-0.16.0/build/cmake/000077500000000000000000000000001420101504100152415ustar00rootroot00000000000000thrift-0.16.0/build/cmake/BoostMacros.cmake000066400000000000000000000031141420101504100204750ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # set(BOOST_MINREV 1.56) macro(REQUIRE_BOOST_HEADERS) find_package(Boost ${BOOST_MINREV} QUIET REQUIRED) if (NOT Boost_FOUND) message(FATAL_ERROR "Boost ${BOOST_MINREV} or later is required to build sources in ${CMAKE_CURRENT_SOURCE_DIR}") endif() if (DEFINED Boost_INCLUDE_DIRS) # pre-boost 1.70.0 aware cmake, otherwise it is using targets include_directories(SYSTEM "${Boost_INCLUDE_DIRS}") endif() endmacro() macro(REQUIRE_BOOST_LIBRARIES libs) message(STATUS "Locating boost libraries required by sources in ${CMAKE_CURRENT_SOURCE_DIR}") find_package(Boost ${BOOST_MINREV} REQUIRED COMPONENTS ${${libs}}) if (NOT Boost_FOUND) message(FATAL_ERROR "Boost ${BOOST_MINREV} or later is required to build sources in ${CMAKE_CURRENT_SOURCE_DIR}, or use -DBUILD_TESTING=OFF") endif() endmacro() thrift-0.16.0/build/cmake/BuildType.cmake000066400000000000000000000027141420101504100201500ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # originally from: # https://raw.githubusercontent.com/OpenChemistry/tomviz/master/cmake/BuildType.cmake # Set a default build type if none was specified set(default_build_type "RelWithDebInfo") if(EXISTS "${CMAKE_SOURCE_DIR}/.git") set(default_build_type "Debug") endif() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${default_build_type}' as none was specified.") set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() thrift-0.16.0/build/cmake/CPackConfig.cmake000066400000000000000000000050251420101504100203540ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #TODO: Should we bundle system libraries for DLLs? #include(InstallRequiredSystemLibraries) # For help take a look at: # http://www.cmake.org/Wiki/CMake:CPackConfiguration ### general settings set(CPACK_PACKAGE_NAME "thrift") set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Thrift") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set(CPACK_PACKAGE_VENDOR "Apache Software Foundation") set(CPACK_PACKAGE_CONTACT "dev@thrift.apache.org") set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}") ### versions set(CPACK_PACKAGE_VERSION_MAJOR ${thrift_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${thrift_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${thrift_VERSION_PATCH}) ### source generator set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") ### zip generator set(CPACK_GENERATOR "ZIP") set(CPACK_PACKAGE_INSTALL_DIRECTORY "thrift") if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set(CPACK_GENERATOR "NSIS") set(CPACK_NSIS_HELP_LINK "http://thrift.apache.org") set(CPACK_NSIS_MENU_LINKS "http://thrift.apache.org" "Apache Thrift - Web Site" "https://issues.apache.org/jira/browse/THRIFT" "Apache Thrift - Issues") set(CPACK_NSIS_CONTACT ${CPACK_PACKAGE_CONTACT}) set(CPACK_NSIS_MODIFY_PATH "ON") set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") else() set(CPACK_GENERATOR "DEB" ) set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT}) endif() include(CPack) thrift-0.16.0/build/cmake/ConfigureChecks.cmake000066400000000000000000000064141420101504100213120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # include(CheckFunctionExists) include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckSymbolExists) include(CheckStructHasMember) include(CheckCSourceCompiles) include(CheckCXXSourceCompiles) if (Inttypes_FOUND) # This allows the inttypes.h and stdint.h checks to succeed on platforms that # do not natively provide there. set (CMAKE_REQUIRED_INCLUDES ${INTTYPES_INCLUDE_DIRS}) endif () check_include_file(arpa/inet.h HAVE_ARPA_INET_H) check_include_file(fcntl.h HAVE_FCNTL_H) check_include_file(getopt.h HAVE_GETOPT_H) check_include_file(inttypes.h HAVE_INTTYPES_H) check_include_file(netdb.h HAVE_NETDB_H) check_include_file(netinet/in.h HAVE_NETINET_IN_H) check_include_file(signal.h HAVE_SIGNAL_H) check_include_file(stdint.h HAVE_STDINT_H) check_include_file(unistd.h HAVE_UNISTD_H) check_include_file(pthread.h HAVE_PTHREAD_H) check_include_file(sys/ioctl.h HAVE_SYS_IOCTL_H) check_include_file(sys/param.h HAVE_SYS_PARAM_H) check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) check_include_file(sys/socket.h HAVE_SYS_SOCKET_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(sys/time.h HAVE_SYS_TIME_H) check_include_file(sys/un.h HAVE_SYS_UN_H) check_include_file(poll.h HAVE_POLL_H) check_include_file(sys/poll.h HAVE_SYS_POLL_H) check_include_file(sys/select.h HAVE_SYS_SELECT_H) check_include_file(sched.h HAVE_SCHED_H) check_include_file(string.h HAVE_STRING_H) check_include_file(strings.h HAVE_STRINGS_H) # Check for afunix.h on Windows (since Windows 10 Insider Build 17063): check_cxx_source_compiles( " #define WIN32_LEAN_AND_MEAN #include #include #include int main(){(void)sizeof(((struct sockaddr_un *)0)->sun_path); return 0;} " HAVE_AF_UNIX_H) check_function_exists(gethostbyname HAVE_GETHOSTBYNAME) check_function_exists(gethostbyname_r HAVE_GETHOSTBYNAME_R) check_function_exists(strerror_r HAVE_STRERROR_R) check_function_exists(sched_get_priority_max HAVE_SCHED_GET_PRIORITY_MAX) check_function_exists(sched_get_priority_min HAVE_SCHED_GET_PRIORITY_MIN) check_cxx_source_compiles( " #include int main(){char b;char *a = strerror_r(0, &b, 0); static_cast(a); return(0);} " STRERROR_R_CHAR_P) set(PACKAGE ${PACKAGE_NAME}) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(VERSION ${thrift_VERSION}) # generate a config.h file configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/thrift/config.h") include_directories("${CMAKE_CURRENT_BINARY_DIR}") thrift-0.16.0/build/cmake/DefineCMakeDefaults.cmake000066400000000000000000000065161420101504100220360ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Always include srcdir and builddir in include path # This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in # about every subdir # since cmake 2.4.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # Put the include dirs which are in the source or build tree # before all other include dirs, so the headers in the sources # are preferred over the already installed ones # since cmake 2.4.1 set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) # Use colored output # since cmake 2.4.0 set(CMAKE_COLOR_MAKEFILE ON) # Create the compile command database for clang by default set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Set the CMAKE_BUILD_TYPE if it is not already defined include(BuildType) # Put the libraries and binaries that get built into directories at the # top of the build tree rather than in hard-to-find leaf # directories. This simplifies manual testing and the use of the build # tree rather than installed thrift libraries. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # # "rpath" support. # See http://www.itk.org/Wiki/index.php?title=CMake_RPATH_handling # # On MacOSX, for shared libraries, enable rpath support. set(CMAKE_MACOSX_RPATH TRUE) # # On any OS, for executables, allow linking with shared libraries in non-system # locations and running the executables without LD_PRELOAD or similar. # This requires the library to be built with rpath support. set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # # C++ Language Level Defaults - this depends on the compiler capabilities # if (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) # C++11 message(STATUS "Setting C++11 as the default language level.") message(STATUS "To specify a different C++ language level, set CMAKE_CXX_STANDARD") endif() if (CMAKE_CXX_STANDARD EQUAL 98) message(FATAL_ERROR "only C++11 or above C++ standard is supported") elseif (CMAKE_CXX_STANDARD EQUAL 11) # should not fallback to C++98 set(CMAKE_CXX_STANDARD_REQUIRED ON) endif() if (NOT DEFINED CMAKE_CXX_EXTENSIONS) set(CMAKE_CXX_EXTENSIONS OFF) # use standards compliant language level for portability endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") include(CheckCXXCompilerFlag) set(CMAKE_REQUIRED_QUIET ON) check_cxx_compiler_flag("/Zc:__cplusplus" res_var) if (res_var) # Make MSVC reporting correct value for __cplusplus # See https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/ add_compile_options("/Zc:__cplusplus") endif() endif() thrift-0.16.0/build/cmake/DefineInstallationPaths.cmake000066400000000000000000000034461420101504100230260ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Define the default install paths set(BIN_INSTALL_DIR "bin" CACHE PATH "The binary install dir (default: bin)") if(MSVC) set(LIB_INSTALL_DIR "bin${LIB_SUFFIX}" CACHE PATH "The library install dir (default: bin${LIB_SUFFIX})") else() set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The library install dir (default: lib${LIB_SUFFIX})") endif() set(INCLUDE_INSTALL_DIR "include" CACHE PATH "The library install dir (default: include)") set(CMAKE_INSTALL_DIR "lib/cmake" CACHE PATH "The subdirectory to install cmake config files (default: cmake)") set(PKGCONFIG_INSTALL_DIR "lib/pkgconfig" CACHE PATH "The subdirectory to install pkgconfig config files (default: lib/pkgconfig)") set(DOC_INSTALL_DIR "share/doc" CACHE PATH "The subdirectory to install documentation files (default: share/doc)") set(prefix "${CMAKE_INSTALL_PREFIX}") set(exec_prefix "${CMAKE_INSTALL_PREFIX}/bin") set(libdir "${CMAKE_INSTALL_PREFIX}/lib") set(includedir "${CMAKE_INSTALL_PREFIX}/include") set(cmakedir "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DIR}") thrift-0.16.0/build/cmake/DefineOptions.cmake000066400000000000000000000215401420101504100210130ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # include(CMakeDependentOption) set(THRIFT_COMPILER "" CACHE FILEPATH "External Thrift compiler to use during build") # Additional components option(BUILD_COMPILER "Build Thrift compiler" ON) if(BUILD_COMPILER OR EXISTS ${THRIFT_COMPILER}) set(HAVE_COMPILER ON) endif() CMAKE_DEPENDENT_OPTION(BUILD_TESTING "Build with unit tests" ON "HAVE_COMPILER" OFF) CMAKE_DEPENDENT_OPTION(BUILD_TUTORIALS "Build Thrift tutorials" ON "HAVE_COMPILER" OFF) option(BUILD_LIBRARIES "Build Thrift libraries" ON) # Libraries to build # Each language library can be enabled or disabled using the WITH_ flag. # By default CMake checks if the required dependencies for a language are present # and enables the library if all are found. This means the default is to build as # much as possible but leaving out libraries if their dependencies are not met. if (NOT Boost_USE_STATIC_LIBS) add_definitions(-DBOOST_ALL_DYN_LINK) add_definitions(-DBOOST_TEST_DYN_LINK) endif() # as3 option(WITH_AS3 "Build ActionScript 3 Thrift Library" ON) if (WITH_AS3) set(POSSIBLE_PATHS "${FLEX_HOME}/bin" "$ENV{FLEX_HOME}/bin") find_program(HAVE_COMPC NAMES compc HINTS ${POSSIBLE_PATHS}) endif () CMAKE_DEPENDENT_OPTION(BUILD_AS3 "Build as3 library" ON "BUILD_LIBRARIES;WITH_AS3;HAVE_COMPC" OFF) # C++ option(WITH_CPP "Build C++ Thrift library" ON) if(WITH_CPP) # NOTE: Currently the following options are C++ specific, # but in future other libraries might reuse them. # So they are not dependent on WITH_CPP but setting them without WITH_CPP currently # has no effect. if(ZLIB_LIBRARY) # FindZLIB.cmake does not normalize path so we need to do it ourselves. file(TO_CMAKE_PATH ${ZLIB_LIBRARY} ZLIB_LIBRARY) endif() find_package(ZLIB QUIET) CMAKE_DEPENDENT_OPTION(WITH_ZLIB "Build with ZLIB support" ON "ZLIB_FOUND" OFF) find_package(Libevent QUIET) CMAKE_DEPENDENT_OPTION(WITH_LIBEVENT "Build with libevent support" ON "Libevent_FOUND" OFF) find_package(Qt5 QUIET COMPONENTS Core Network) CMAKE_DEPENDENT_OPTION(WITH_QT5 "Build with Qt5 support" ON "Qt5_FOUND" OFF) endif() CMAKE_DEPENDENT_OPTION(BUILD_CPP "Build C++ library" ON "BUILD_LIBRARIES;WITH_CPP" OFF) # C GLib option(WITH_C_GLIB "Build C (GLib) Thrift library" ON) if(WITH_C_GLIB) find_package(GLIB QUIET COMPONENTS gobject) endif() CMAKE_DEPENDENT_OPTION(BUILD_C_GLIB "Build C (GLib) library" ON "BUILD_LIBRARIES;WITH_C_GLIB;GLIB_FOUND" OFF) # OpenSSL if(WITH_CPP OR WITH_C_GLIB) find_package(OpenSSL QUIET) CMAKE_DEPENDENT_OPTION(WITH_OPENSSL "Build with OpenSSL support" ON "OPENSSL_FOUND" OFF) endif() # Java option(WITH_JAVA "Build Java Thrift library" ON) if(ANDROID) find_package(Gradle QUIET) CMAKE_DEPENDENT_OPTION(BUILD_JAVA "Build Java library" ON "BUILD_LIBRARIES;WITH_JAVA;GRADLE_FOUND" OFF) else() find_package(Gradlew QUIET) find_package(Java QUIET) CMAKE_DEPENDENT_OPTION(BUILD_JAVA "Build Java library" ON "BUILD_LIBRARIES;WITH_JAVA;JAVA_FOUND;GRADLEW_FOUND" OFF) endif() # Javascript option(WITH_JAVASCRIPT "Build Javascript Thrift library" ON) CMAKE_DEPENDENT_OPTION(BUILD_JAVASCRIPT "Build Javascript library" ON "BUILD_LIBRARIES;WITH_JAVASCRIPT;NOT WIN32; NOT CYGWIN" OFF) # NodeJS option(WITH_NODEJS "Build NodeJS Thrift library" ON) CMAKE_DEPENDENT_OPTION(BUILD_NODEJS "Build NodeJS library" ON "BUILD_LIBRARIES;WITH_NODEJS" OFF) # Python option(WITH_PYTHON "Build Python Thrift library" ON) find_package(PythonInterp QUIET) # for Python executable find_package(PythonLibs QUIET) # for Python.h CMAKE_DEPENDENT_OPTION(BUILD_PYTHON "Build Python library" ON "BUILD_LIBRARIES;WITH_PYTHON;PYTHONINTERP_FOUND;PYTHONLIBS_FOUND" OFF) # Common library options # https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html # Default on Windows is static, shared mode library support needs work... if(WIN32) set(DEFAULT_BUILD_SHARED_LIBS ON) else() set(DEFAULT_BUILD_SHARED_LIBS OFF) endif() option(BUILD_SHARED_LIBS "Build shared libraries" ${DEFAULT_BUILD_SHARED_LIBS}) if (WITH_SHARED_LIB) message(WARNING "WITH_SHARED_LIB is deprecated; use -DBUILD_SHARED_LIBS=ON instead") set(BUILD_SHARED_LIBS ON) elseif (WITH_STATIC_LIB) if (WITH_SHARED_LIB) message(FATAL_ERROR "Cannot build shared and static together; set BUILD_SHARED_LIBS instead.") endif () message(WARNING "WITH_STATIC_LIB is deprecated; use -DBUILD_SHARED_LIBS=OFF instead") set(BUILD_SHARED_LIBS OFF) endif () # Visual Studio only options if(MSVC) option(WITH_MT "Build using the static runtime 'MT' instead of the shared DLL-specific runtime 'MD' (MSVC only)" OFF) endif(MSVC) macro(MESSAGE_DEP flag summary) if(NOT ${flag}) message(STATUS " - ${summary}") endif() endmacro(MESSAGE_DEP flag summary) macro(PRINT_CONFIG_SUMMARY) message(STATUS "----------------------------------------------------------") message(STATUS "Thrift version: ${thrift_VERSION} (${thrift_VERSION_MAJOR}.${thrift_VERSION_MINOR}.${thrift_VERSION_PATCH})") message(STATUS "Thrift package version: ${PACKAGE_VERSION}") message(STATUS) message(STATUS "Build configuration summary") message(STATUS " Build compiler: ${BUILD_COMPILER}") message(STATUS " Build libraries: ${BUILD_LIBRARIES}") message(STATUS " Build tests: ${BUILD_TESTING}") MESSAGE_DEP(HAVE_COMPILER "Disabled because BUILD_COMPILER=OFF and no valid THRIFT_COMPILER is given") message(STATUS " Build type: ${CMAKE_BUILD_TYPE}") message(STATUS) message(STATUS "Language libraries:") message(STATUS) message(STATUS " Build as3 library: ${BUILD_AS3}") MESSAGE_DEP(WITH_AS3 "Disabled by WITH_AS3=OFF") MESSAGE_DEP(HAVE_COMPC "Adobe Flex compc was not found - did you set env var FLEX_HOME?") message(STATUS) message(STATUS " Build with OpenSSL: ${WITH_OPENSSL}") if(WITH_OPENSSL) message(STATUS " Version: ${OPENSSL_VERSION}") endif() message(STATUS) message(STATUS " Build C++ library: ${BUILD_CPP}") MESSAGE_DEP(WITH_CPP "Disabled by WITH_CPP=OFF") if (BUILD_CPP) message(STATUS " C++ Language Level: ${CXX_LANGUAGE_LEVEL}") message(STATUS " Build shared libraries: ${BUILD_SHARED_LIBS}") message(STATUS " Build with libevent support: ${WITH_LIBEVENT}") message(STATUS " Build with Qt5 support: ${WITH_QT5}") message(STATUS " Build with ZLIB support: ${WITH_ZLIB}") endif () message(STATUS) message(STATUS " Build C (GLib) library: ${BUILD_C_GLIB}") MESSAGE_DEP(WITH_C_GLIB "Disabled by WITH_C_GLIB=OFF") MESSAGE_DEP(GLIB_FOUND "GLib missing") message(STATUS) message(STATUS " Build Java library: ${BUILD_JAVA}") MESSAGE_DEP(WITH_JAVA "Disabled by WITH_JAVA=OFF") if(ANDROID) MESSAGE_DEP(GRADLE_FOUND "Gradle missing") else() MESSAGE_DEP(JAVA_FOUND "Java Runtime missing") MESSAGE_DEP(GRADLEW_FOUND "Gradle Wrapper missing") endif() message(STATUS " Build Javascript library: ${BUILD_JAVASCRIPT}") MESSAGE_DEP(WITH_JAVASCRIPT "Disabled by WITH_JAVASCRIPT=OFF") message(STATUS " Build NodeJS library: ${BUILD_NODEJS}") MESSAGE_DEP(WITH_NODEJS "Disabled by WITH_NODEJS=OFF") message(STATUS) message(STATUS " Build Python library: ${BUILD_PYTHON}") MESSAGE_DEP(WITH_PYTHON "Disabled by WITH_PYTHON=OFF") MESSAGE_DEP(PYTHONLIBS_FOUND "Python libraries missing") if(MSVC) message(STATUS " Using static runtime library: ${WITH_MT}") endif(MSVC) message(STATUS) message(STATUS) message(STATUS "----------------------------------------------------------") endmacro(PRINT_CONFIG_SUMMARY) thrift-0.16.0/build/cmake/DefinePlatformSpecifc.cmake000066400000000000000000000110011420101504100224300ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Uncomment this to show some basic cmake variables about platforms # include (NewPlatformDebug) # For Debug build types, default to "d"-suffix in library names. set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Set debug library postfix") # basic options foreach(lang IN ITEMS C CXX) if("CMAKE_${lang}_COMPILER_ID" STREQUAL "MSVC" OR "${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "MSVC") set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} /MP") # parallel build set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} /W3") # warning level 3 include(CheckCXXCompilerFlag) set(CMAKE_REQUIRED_QUIET ON) check_cxx_compiler_flag("/source-charset:utf-8" res_var) if (res_var) set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} /source-charset:utf-8") endif() check_cxx_compiler_flag("/execution-charset:utf-8" res_var) if (res_var) set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} /execution-charset:utf-8") endif() add_definitions("-DUNICODE -D_UNICODE") elseif("CMAKE_${lang}_COMPILER_ID" STREQUAL "Clang") set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} -Wall") set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} -ferror-limit=1") elseif("CMAKE_${lang}_COMPILER_ID" STREQUAL "GNU") set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} -Wall -Wextra") set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} -fmax-errors=1") endif() endforeach() # Visual Studio specific options if(MSVC) # Allow for shared library builds if(BUILD_SHARED_LIBS) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON CACHE TYPE BOOL FORCE) endif() #For visual studio the library naming is as following: # Dynamic libraries: # - thrift.dll for release library # - thriftd.dll for debug library # # Static libraries: # - thriftmd.lib for /MD release build # - thriftmt.lib for /MT release build # # - thriftmdd.lib for /MD debug build # - thriftmtd.lib for /MT debug build # # the same holds for other libraries like libthriftz etc. # Build using /MT option instead of /MD if the WITH_MT options is set if(WITH_MT) set(CompilerFlags CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO ) foreach(CompilerFlag ${CompilerFlags}) string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") endforeach() set(THRIFT_RUNTIME_POSTFIX "mt" CACHE STRING "Set runtime library postfix" FORCE) else(WITH_MT) set(THRIFT_RUNTIME_POSTFIX "md" CACHE STRING "Set runtime library postfix" FORCE) endif(WITH_MT) # Disable boost auto linking pragmas - cmake includes the right files add_definitions("-DBOOST_ALL_NO_LIB") elseif(UNIX) find_program( MEMORYCHECK_COMMAND valgrind ) set( MEMORYCHECK_COMMAND_OPTIONS "--gen-suppressions=all --leak-check=full" ) set( MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/test/valgrind.suppress" ) endif() add_definitions("-D__STDC_FORMAT_MACROS") add_definitions("-D__STDC_LIMIT_MACROS") # C++ Language Level set(CXX_LANGUAGE_LEVEL "C++${CMAKE_CXX_STANDARD}") if (CMAKE_CXX_STANDARD_REQUIRED) string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [compiler must support it]") else() string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [fallback to earlier if compiler does not support it]") endif() if (CMAKE_CXX_EXTENSIONS) string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [with compiler-specific extensions]") endif() if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register") endif() thrift-0.16.0/build/cmake/FindAnt.cmake000066400000000000000000000021461420101504100175710ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # ANT_FOUND - system has Ant # Ant_EXECUTABLE - the Ant executable # # It will search the environment variable ANT_HOME if it is set include(FindPackageHandleStandardArgs) find_program(Ant_EXECUTABLE NAMES ant PATHS $ENV{ANT_HOME}/bin) find_package_handle_standard_args(Ant DEFAULT_MSG Ant_EXECUTABLE) mark_as_advanced(Ant_EXECUTABLE) thrift-0.16.0/build/cmake/FindClangTools.cmake000066400000000000000000000024211420101504100211100ustar00rootroot00000000000000# - Try to find Clang tools # # The following are set after configuration is done: # clang-tidy_FOUND # ClangTools::clang-tidy # clang-apply-replacements_FOUND # ClangTools::clang-apply-replacements # run-clang-tidy_FOUND # ClangTools::run-clang-tidy include_guard() include(FindPackageHandleStandardArgs) foreach(program_name IN ITEMS clang-tidy clang-apply-replacements) find_program(${program_name}_BINARY NAMES ${program_name}-devel ${program_name}-8 ${program_name} PATH_SUFFIXES "LLVM/bin") find_package_handle_standard_args(${program_name} DEFAULT_MSG ${program_name}_BINARY) if(${program_name}_FOUND AND NOT TARGET ClangTools::${program_name}) add_executable(ClangTools::${program_name} IMPORTED) set_property(TARGET ClangTools::${program_name} PROPERTY IMPORTED_LOCATION "${${program_name}_BINARY}") endif() endforeach() find_program(run-clang-tidy_BINARY NAMES run-clang-tidy run-clang-tidy.py PATH_SUFFIXES "LLVM/bin" "llvm-devel/share/clang") find_package_handle_standard_args(run-clang-tidy DEFAULT_MSG run-clang-tidy_BINARY) if(run-clang-tidy_FOUND AND NOT TARGET ClangTools::run-clang-tidy) add_executable(ClangTools::run-clang-tidy IMPORTED) set_property(TARGET ClangTools::run-clang-tidy PROPERTY IMPORTED_LOCATION "${run-clang-tidy_BINARY}") endif() thrift-0.16.0/build/cmake/FindGLIB.cmake000066400000000000000000000125621420101504100175670ustar00rootroot00000000000000# - Try to find Glib and its components (gio, gobject etc) # Once done, this will define # # GLIB_FOUND - system has Glib # GLIB_INCLUDE_DIRS - the Glib include directories # GLIB_LIBRARIES - link these to use Glib # # Optionally, the COMPONENTS keyword can be passed to find_package() # and Glib components can be looked for. Currently, the following # components can be used, and they define the following variables if # found: # # gio: GLIB_GIO_LIBRARIES # gobject: GLIB_GOBJECT_LIBRARIES # gmodule: GLIB_GMODULE_LIBRARIES # gthread: GLIB_GTHREAD_LIBRARIES # # Note that the respective _INCLUDE_DIR variables are not set, since # all headers are in the same directory as GLIB_INCLUDE_DIRS. # # Copyright (C) 2012 Raphael Kubo da Costa # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. 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. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS 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 HOLDER OR ITS # 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. find_package(PkgConfig) pkg_check_modules(PC_GLIB QUIET glib-2.0) find_library(GLIB_LIBRARIES NAMES glib-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS} ) # Files in glib's main include path may include glibconfig.h, which, # for some odd reason, is normally in $LIBDIR/glib-2.0/include. get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH) find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR} ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0/include ) find_path(GLIB_INCLUDE_DIR NAMES glib.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0 ) set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR}) if(GLIBCONFIG_INCLUDE_DIR) # Version detection file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS) string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}") set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}") endif() # Additional Glib components. We only look for libraries, as not all of them # have corresponding headers and all headers are installed alongside the main # glib ones. foreach (_component ${GLIB_FIND_COMPONENTS}) if (${_component} STREQUAL "gio") find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES) elseif (${_component} STREQUAL "gobject") find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES) elseif (${_component} STREQUAL "gmodule") find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES) elseif (${_component} STREQUAL "gthread") find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES) elseif (${_component} STREQUAL "gio-unix") # gio-unix is compiled as part of the gio library, but the include paths # are separate from the shared glib ones. Since this is currently only used # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config. pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0) endif () endforeach () include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS} VERSION_VAR GLIB_VERSION) mark_as_advanced( GLIBCONFIG_INCLUDE_DIR GLIB_GIO_LIBRARIES GLIB_GIO_UNIX_LIBRARIES GLIB_GMODULE_LIBRARIES GLIB_GOBJECT_LIBRARIES GLIB_GTHREAD_LIBRARIES GLIB_INCLUDE_DIR GLIB_INCLUDE_DIRS GLIB_LIBRARIES ) thrift-0.16.0/build/cmake/FindGradle.cmake000066400000000000000000000022341420101504100202430ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # GRADLE_FOUND - system has Gradle # GRADLE_EXECUTABLE - the Gradle executable # # It will search the environment variable ANT_HOME if it is set include(FindPackageHandleStandardArgs) find_program(GRADLE_EXECUTABLE NAMES gradle PATHS $ENV{GRADLE_HOME}/bin NO_CMAKE_FIND_ROOT_PATH) find_package_handle_standard_args(Gradle DEFAULT_MSG GRADLE_EXECUTABLE) mark_as_advanced(GRADLE_EXECUTABLE) thrift-0.16.0/build/cmake/FindGradlew.cmake000066400000000000000000000027231420101504100204350ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # GRADLEW_FOUND - system has Gradlew # GRADLEW_EXECUTABLE - the Gradlew executable # # It will search the location CMAKE_SOURCE_DIR/lib/java include(FindPackageHandleStandardArgs) find_program(GRADLEW_EXECUTABLE gradlew PATHS ${CMAKE_SOURCE_DIR}/lib/java NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) find_package_handle_standard_args(Gradlew DEFAULT_MSG GRADLEW_EXECUTABLE) mark_as_advanced(GRADLEW_EXECUTABLE) # Buggy find_program cannot find gradlew.bat when gradlew is at the same path # and even buggier ctest will not execute gradlew.bat when gradlew is given. if(CMAKE_HOST_WIN32) string(REGEX REPLACE "(.+gradlew)$" "\\1.bat" GRADLEW_EXECUTABLE ${GRADLEW_EXECUTABLE}) endif(CMAKE_HOST_WIN32) thrift-0.16.0/build/cmake/FindInttypes.cmake000066400000000000000000000025431420101504100206670ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # find msinttypes on compilers that don't provide it, for example # VS2010 # Usage: # Provide INTTYPES_ROOT if you need it # Result: INTTYPES_INCLUDE_DIRS, where to find inttypes.h # Result: Inttypes_FOUND, If false, inttypes.h was not found find_path(INTTYPES_INCLUDE_DIRS inttypes.h HINTS ${INTTYPES_ROOT}) if (INTTYPES_INCLUDE_DIRS) set(Inttypes_FOUND TRUE) else () set(Inttypes_FOUND FALSE) if (Inttypes_FIND_REQUIRED) message(FATAL_ERROR "Could NOT find inttypes.h") endif () message(STATUS "inttypes.h NOT found") endif () mark_as_advanced( INTTYPES_INCLUDE_DIRS ) thrift-0.16.0/build/cmake/FindLibevent.cmake000066400000000000000000000027551420101504100206250ustar00rootroot00000000000000# find LibEvent # an event notification library (http://libevent.org/) # # Usage: # LIBEVENT_INCLUDE_DIRS, where to find LibEvent headers # LIBEVENT_LIBRARIES, LibEvent libraries # Libevent_FOUND, If false, do not try to use libevent set(LIBEVENT_ROOT CACHE PATH "Root directory of libevent installation") set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}" ${LIBEVENT_ROOT}) foreach(prefix ${LibEvent_EXTRA_PREFIXES}) list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include") list(APPEND LibEvent_LIBRARIES_PATHS "${prefix}/lib") endforeach() # Looking for "event.h" will find the Platform SDK include dir on windows # so we also look for a peer header like evhttp.h to get the right path find_path(LIBEVENT_INCLUDE_DIRS evhttp.h event.h PATHS ${LibEvent_INCLUDE_PATHS}) # "lib" prefix is needed on Windows in some cases # newer versions of libevent use three libraries find_library(LIBEVENT_LIBRARIES NAMES event event_core event_extra libevent PATHS ${LibEvent_LIBRARIES_PATHS}) if (LIBEVENT_LIBRARIES AND LIBEVENT_INCLUDE_DIRS) set(Libevent_FOUND TRUE) set(LIBEVENT_LIBRARIES ${LIBEVENT_LIBRARIES}) else () set(Libevent_FOUND FALSE) endif () if (Libevent_FOUND) if (NOT Libevent_FIND_QUIETLY) message(STATUS "Found libevent: ${LIBEVENT_LIBRARIES}") endif () else () if (LibEvent_FIND_REQUIRED) message(FATAL_ERROR "Could NOT find libevent.") endif () message(STATUS "libevent NOT found.") endif () mark_as_advanced( LIBEVENT_LIBRARIES LIBEVENT_INCLUDE_DIRS ) thrift-0.16.0/build/cmake/GenerateConfigModule.cmake000066400000000000000000000033741420101504100223000ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # include(CMakePackageConfigHelpers) set(PACKAGE_INCLUDE_INSTALL_DIR "${includedir}/thrift") set(PACKAGE_CMAKE_INSTALL_DIR "${cmakedir}/thrift") set(PACKAGE_BIN_INSTALL_DIR "${exec_prefix}") # In CYGWIN enviroment below commands does not work properly if (NOT CYGWIN) configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/ThriftConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/ThriftConfig.cmake" INSTALL_DESTINATION "${CMAKE_INSTALL_DIR}/thrift" PATH_VARS PACKAGE_INCLUDE_INSTALL_DIR PACKAGE_CMAKE_INSTALL_DIR PACKAGE_BIN_INSTALL_DIR ) write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/ThriftConfigVersion.cmake" VERSION ${thrift_VERSION_MAJOR}.${thrift_VERSION_MINOR}.${thrift_VERSION_PATCH} COMPATIBILITY SameMajorVersion ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ThriftConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/ThriftConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_DIR}/thrift") endif() thrift-0.16.0/build/cmake/NewPlatformDebug.cmake000066400000000000000000000025401420101504100214510ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # For debugging new platforms, just to see what some environment flags are... # macro(SHOWFLAG flag) message(STATUS "${flag} = ${${flag}}") endmacro(SHOWFLAG) set(NEWPLATFORMDEBUG ON) if(NEWPLATFORMDEBUG) SHOWFLAG("APPLE") SHOWFLAG("BORLAND") SHOWFLAG("CMAKE_C_COMPILER_ID") SHOWFLAG("CMAKE_CXX_COMPILER_ID") SHOWFLAG("CMAKE_COMPILER_IS_GNUCC") SHOWFLAG("CMAKE_COMPILER_IS_GNUCXX") SHOWFLAG("CYGWIN") SHOWFLAG("MINGW") SHOWFLAG("MSVC") SHOWFLAG("MSVC_VERSION") SHOWFLAG("MSYS") SHOWFLAG("UNIX") SHOWFLAG("WATCOM") SHOWFLAG("WIN32") endif(NEWPLATFORMDEBUG) thrift-0.16.0/build/cmake/README-MSYS2.md000066400000000000000000000047231420101504100174010ustar00rootroot00000000000000 # Building thrift on Windows (MinGW64/MSYS2) Thrift uses cmake to make it easier to build the project on multiple platforms, however to build a fully functional and production ready thrift on Windows requires a number of third party libraries to be obtained. Once third party libraries are ready, the right combination of options must be passed to cmake in order to generate the correct environment. > Note: libevent and libevent-devel do not work with this toolchain as they do not properly detect mingw64 and expect some headers to exist that do not, so the non-blocking server is not currently built into this solution. ## MSYS2 Download and fully upgrade msys2 following the instructions at: https://msys2.github.io/ Install the necessary toolchain items for C++: $ pacman --needed -S bison flex make mingw-w64-x86_64-openssl \ mingw-w64-x86_64-boost mingw-w64-x86_64-cmake \ mingw-w64-x86_64-toolchain mingw-w64-x86_64-zlib Update your msys2 bash path to include /mingw64/bin by adding a line to your ~/.bash_profiles using this command: echo "export PATH=/mingw64/bin:\$PATH" >> ~/.bash_profile After that, close your shell and open a new one. Use cmake to create a MinGW makefile, out of tree (assumes you are in the top level of the thrift source tree): mkdir ../thrift-build cd ../thrift-build cmake -G"MinGW Makefiles" -DCMAKE_MAKE_PROGRAM=/mingw64/bin/mingw32-make \ -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc.exe \ -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++.exe \ -DWITH_LIBEVENT=OFF \ -DWITH_SHARED_LIB=OFF -DWITH_STATIC_LIB=ON \ -DWITH_JAVA=OFF -DWITH_PYTHON=OFF -DWITH_PERL=OFF \ ../thrift Build thrift (inside thrift-build): cmake --build . Run the tests (inside thrift-build): ctest > If you run into issues, check Apache Jira THRIFT-4046 for patches relating to MinGW64/MSYS2 builds. ## Tested With msys2 64-bit 2016-10-26 distribution thrift-0.16.0/build/cmake/README.md000066400000000000000000000036351420101504100165270ustar00rootroot00000000000000# Apache Thrift - CMake Build ## Goal Extend Apache Thrift's *make cross* approach to the build system. Due to growing the field of operating system support, a proper executable and library detection mechanism running on as much platforms as possible becomes required. The other aspect to simplify the release process and package generation process. As nice side benefit of CMake is the generation of development environment specific soultion files. => No solution files within source tree. ## Prerequisites These are language-specific, however for C++ you must provide: - Boost - OpenSSL You may optionally provide: - libevent - zlib ## Usage To use CMake you first create an out-of-tree build directory, then use CMake to generate a build framework, then build: mkdir /tmp/build cd /tmp/build cmake /location/to/thrift if you use a specific toolchain pass it to cmake, the same for options: cmake -DCMAKE_TOOLCHAIN_FILE=../build/cmake/mingw32-toolchain.cmake .. cmake -DCMAKE_C_COMPILER=clang-3.5 -DCMAKE_CXX_COMPILER=clang++-3.5 .. cmake -DTHRIFT_COMPILER_HS=OFF .. cmake -DWITH_ZLIB=ON .. and open the development environment you like with the solution or do this: make make check make cross make dist or on Windows, the following will produce a solution file you can use inside Visual Studio: cmake -G "Visual Studio 15 2017 Win64" \ -DBOOST_ROOT=C:/3rdparty/boost_1_69_0 \ -DBOOST_LIBRARYDIR=C:/3rdparty/boost_1_69_0/lib64-msvc-14.1^ -DZLIB_ROOT=C:/3rdparty/zlib-1.2.11 ## TODO * git hash or tag based versioning depending on source state * build tutorial * build test * enable/disable * make cross * make dist (create an alias to make package_source) * make doc * cpack (C++ and make dist only ?) * thrift-compiler * libthrift * tutorial * test * merge into /README.mdthrift-0.16.0/build/cmake/StaticCodeAnalysis.cmake000066400000000000000000000006541420101504100217760ustar00rootroot00000000000000find_package(ClangTools QUIET) if(clang-tidy_FOUND AND run-clang-tidy_FOUND AND NOT TARGET do_run_clang_tidy) add_custom_target( do_run_clang_tidy COMMAND ClangTools::run-clang-tidy -clang-tidy-binary "$" -p ${CMAKE_BINARY_DIR} "-quiet" > ./run-clang-tidy.txt DEPENDS ${CMAKE_BINARY_DIR}/compile_commands.json WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) endif() thrift-0.16.0/build/cmake/ThriftConfig.cmake.in000066400000000000000000000036031420101504100212400ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # set(THRIFT_VERSION @thrift_VERSION@) @PACKAGE_INIT@ set_and_check(THRIFT_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") set_and_check(THRIFT_CMAKE_DIR "@PACKAGE_CMAKE_INSTALL_DIR@") set_and_check(THRIFT_BIN_DIR "@PACKAGE_BIN_INSTALL_DIR@") set(THRIFT_COMPILER "${THRIFT_BIN_DIR}/thrift@CMAKE_EXECUTABLE_SUFFIX@") if (NOT TARGET thrift::thrift) include("${THRIFT_CMAKE_DIR}/thriftTargets.cmake") endif() set(THRIFT_LIBRARIES thrift::thrift) if(@ZLIB_FOUND@ AND @WITH_ZLIB@) if (NOT TARGET thriftz::thriftz) include("${THRIFT_CMAKE_DIR}/thriftzTargets.cmake") endif() set(THRIFT_LIBRARIES thriftz::thriftz) endif() if ("${THRIFT_LIBRARIES}" STREQUAL "") message(FATAL_ERROR "thrift libraries were not found") endif() if (NOT Thrift_FIND_QUIETLY) message(STATUS "Found thrift: ${PACKAGE_PREFIX_DIR}") endif() include(CMakeFindDependencyMacro) if(@ZLIB_FOUND@ AND @WITH_ZLIB@) find_dependency(ZLIB) endif() if(@OPENSSL_FOUND@ AND @WITH_OPENSSL@) find_dependency(OpenSSL) endif() if(@Libevent_FOUND@ AND @WITH_LIBEVENT@) find_dependency(Libevent) endif() check_required_components(Thrift) thrift-0.16.0/build/cmake/ThriftMacros.cmake000066400000000000000000000037161420101504100206570ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # macro(ADD_PKGCONFIG_THRIFT name) configure_file("${name}.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/${name}.pc" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${name}.pc" DESTINATION "${PKGCONFIG_INSTALL_DIR}") endmacro(ADD_PKGCONFIG_THRIFT) macro(ADD_LIBRARY_THRIFT name) add_library(${name} ${ARGN}) target_include_directories(${name} INTERFACE $) set_target_properties(${name} PROPERTIES OUTPUT_NAME ${name}${THRIFT_RUNTIME_POSTFIX} # windows link variants (/MT, /MD, /MTd, /MDd) get different names VERSION ${thrift_VERSION}) # set_target_properties(${name} PROPERTIES PUBLIC_HEADER "${thriftcpp_HEADERS}") install(TARGETS ${name} EXPORT "${name}Targets" RUNTIME DESTINATION "${BIN_INSTALL_DIR}" LIBRARY DESTINATION "${LIB_INSTALL_DIR}" ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" PUBLIC_HEADER DESTINATION "${INCLUDE_INSTALL_DIR}") export(EXPORT "${name}Targets" FILE "${CMAKE_CURRENT_BINARY_DIR}/${name}/${name}Targets.cmake" NAMESPACE "${name}::") install(EXPORT "${name}Targets" FILE "${name}Targets.cmake" NAMESPACE "${name}::" DESTINATION "${CMAKE_INSTALL_DIR}/thrift") endmacro()thrift-0.16.0/build/cmake/android-toolchain.cmake000066400000000000000000000020131420101504100216350ustar00rootroot00000000000000set(ANDROID_NDK "/opt/android-ndk" CACHE) set(ANDROID_PLATFORM "android-15" CACHE) set(ANDROID_ARCH "arch-arm" CACHE) set(ANDROID_TOOL_ARCH "android-arm" CACHE) set(ANDROID_CPU "armeabi-v7a" CACHE) set(ANDROID_GCC_VERSION 4.9 CACHE) set(HOST_ARCH linux-x86_64 CACHE) set(CMAKE_SYSTEM_NAME Android) set(ANDROID_SYSROOT "${ANDROID_NDK}/platforms/${ANDROID_PLATFORM}/${ANDROID_ARCH}") set(ANDROID_TRIPLET arm-linux-androideabi) set(ANDROID_STL "${ANDROID_NDK}/sources/cxx-stl/gnu-libstd++/${ANDROID_GCC_VERSION}") set(_COMPILER_ROOT ${ANDROID_NDK}/prebuilt/${ANDROID_TRIPLET}-${ANDROID_GCC_VERSION}/prebuilt/${HOST_ARCH}) set(CMAKE_C_COMPILER ${_COMPILER_ROOT}/bin/${ANDROID_TRIPLET}-gcc) set(CMAKE_CXCX_COMPILER ${_COMPILER_ROOT}/bin/${ANDROID_TRIPLET}-g++) include_directories( ${ANDROID_STL}/include ${ANDROID_STL}/libs/${ANDROID_CPU}/include) set(CMAKE_FIND_ROOT_PATH ${ANDROID_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) thrift-0.16.0/build/cmake/config.h.in000066400000000000000000000120111420101504100172570ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* config.h generated by CMake from config.h.in */ #ifndef CONFIG_H #define CONFIG_H /* Name of package */ #cmakedefine PACKAGE "${PACKAGE}" /* Define to the address where bug reports for this package should be sent. */ #cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}" /* Define to the full name of this package. */ #cmakedefine PACKAGE_NAME "${PACKAGE_NAME}" /* Define to the one symbol short name of this package. */ #cmakedefine PACKAGE_TARNAME "${PACKAGE_TARNAME}" /* Define to the home page for this package. */ #cmakedefine PACKAGE_URL "${PACKAGE_URL}" /* Define to the version of this package. */ #define PACKAGE_VERSION "${PACKAGE_VERSION}" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "${PACKAGE_STRING}" /************************** DEFINES *************************/ /* Define if the AI_ADDRCONFIG symbol is unavailable */ #cmakedefine AI_ADDRCONFIG 0 /* Possible value for SIGNED_RIGHT_SHIFT_IS */ /* TODO: This is just set to 1 for the moment port the macro aclocal/ax_signed_right_shift.m4 to CMake to make this work */ #define ARITHMETIC_RIGHT_SHIFT 1 /* Indicates the effect of the right shift operator on negative signed integers */ /* TODO: This is just set to 1 for the moment */ #define SIGNED_RIGHT_SHIFT_IS 1 /* Use *.h extension for parser header file */ /* TODO: This might now be necessary anymore as it is set only for automake < 1.11 see: aclocal/ac_prog_bison.m4 */ #cmakedefine BISON_USE_PARSER_H_EXTENSION 1 /* Define to 1 if strerror_r returns char *. */ #cmakedefine STRERROR_R_CHAR_P 1 /************************** HEADER FILES *************************/ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SIGNAL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PTHREAD_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_UN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_POLL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SCHED_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_AF_UNIX_H 1 /*************************** FUNCTIONS ***************************/ /* Define to 1 if you have the `gethostbyname' function. */ #cmakedefine HAVE_GETHOSTBYNAME 1 /* Define to 1 if you have the `gethostbyname_r' function. */ #cmakedefine HAVE_GETHOSTBYNAME_R 1 /* Define to 1 if you have the `strerror_r' function. */ #cmakedefine HAVE_STRERROR_R 1 /* Define to 1 if you have the `sched_get_priority_max' function. */ #cmakedefine HAVE_SCHED_GET_PRIORITY_MAX 1 /* Define to 1 if you have the `sched_get_priority_min' function. */ #cmakedefine HAVE_SCHED_GET_PRIORITY_MIN 1 /* Define to 1 if strerror_r returns char *. */ #cmakedefine STRERROR_R_CHAR_P 1 #endif thrift-0.16.0/build/cmake/mingw32-toolchain.cmake000066400000000000000000000015311420101504100215070ustar00rootroot00000000000000# CMake mingw32 cross compile toolchain file # the name of the target operating system SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER i586-mingw32msvc-gcc) SET(CMAKE_CXX_COMPILER i586-mingw32msvc-g++) SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres) # here is the target environment located SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(BUILD_SHARED_LIBS OFF) SET(CMAKE_EXE_LINKER_FLAGS "-static") set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-static-libgcc") set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-static-libstdc++") thrift-0.16.0/build/cmake/uninstall.cmake000066400000000000000000000027501420101504100202600ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # cmake_minimum_required(VERSION 3.4) set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") if(NOT EXISTS ${MANIFEST}) message(FATAL_ERROR "Cannot find install mainfest: ${MANIFEST}") endif() file(STRINGS ${MANIFEST} files) foreach(file ${files}) if(EXISTS ${file} OR IS_SYMLINK ${file}) message(STATUS "Removing: ${file}") execute_process( COMMAND ${CMAKE_COMMAND} -E remove ${file} RESULT_VARIABLE result OUTPUT_QUIET ERROR_VARIABLE stderr ERROR_STRIP_TRAILING_WHITESPACE ) if(NOT ${result} EQUAL 0) message(FATAL_ERROR "${stderr}") endif() else() message(STATUS "Does-not-exist: ${file}") endif() endforeach(file) thrift-0.16.0/build/docker/000077500000000000000000000000001420101504100154305ustar00rootroot00000000000000thrift-0.16.0/build/docker/README.md000066400000000000000000000175201420101504100167140ustar00rootroot00000000000000# Docker Integration # Due to the large number of languages supported by Apache Thrift, docker containers are used to build and test the project on a variety of platforms to provide maximum test coverage. ## Appveyor Integration ## At this time the Appveyor scripts do not use docker containers. Once Microsoft supports Visual Studio Build Tools running inside nano containers (instead of Core, which is huge) then we will consider using containers for the Windows builds as well. ## Travis CI Integration ## The Travis CI scripts use the following environment variables and logic to determine their behavior: ### Environment Variables ### | Variable | Default | Usage | | -------- | ----- | ------- | | `DISTRO` | `ubuntu-bionic` | Set by various build jobs in `.travis.yml` to run builds in different containers. Not intended to be set externally.| | `DOCKER_REPO` | `thrift/thrift-build` | The name of the Docker Hub repository to obtain and store docker images. | | `DOCKER_USER` | `` | The Docker Hub account name containing the repository. | | `DOCKER_PASS` | `` | The Docker Hub account password to use when pushing new tags. | For example, the default docker image that is used in builds if no overrides are specified would be: `thrift/thrift-build:ubuntu-bionic` ### Forks ### If you have forked the Apache Thrift repository and you would like to use your own Docker Hub account to store thrift build images, you can use the Travis CI web interface to set the `DOCKER_USER`, `DOCKER_PASS`, and `DOCKER_REPO` variables in a secure manner. Your fork builds will then pull, push, and tag the docker images in your account. ### Logic ### The Travis CI build runs in two phases - first the docker images are rebuilt for each of the supported containers if they do not match the Dockerfile that was used to build the most recent tag. If a `DOCKER_PASS` environment variable is specified, the docker stage builds will attempt to log into Docker Hub and push the resulting tags. ## Supported Containers ## The Travis CI (continuous integration) builds use the Ubuntu Bionic (18.04 LTS) and Xenial (16.04 LTS) images to maximize language level coverage. ### Ubuntu ### * bionic (stable, current) * artful (previous stable) * xenial (legacy) ## Unsupported Containers ## These containers may be in various states, and may not build everything. They can be found in the `old/` subdirectory. ### CentOS ### * 7.3 * make check in lib/py may hang in test_sslsocket - root cause unknown ### Debian ### * jessie * stretch * make check in lib/cpp fails due to https://svn.boost.org/trac10/ticket/12507 ## Building like Travis CI does, locally ## We recommend you build locally the same way Travis CI does, so that when you submit your pull request you will run into fewer surprises. To make it a little easier, put the following into your `~/.bash_aliases` file: # Kill all running containers. alias dockerkillall='docker kill $(docker ps -q)' # Delete all stopped containers. alias dockercleanc='printf "\n>>> Deleting stopped containers\n\n" && docker rm $(docker ps -a -q)' # Delete all untagged images. alias dockercleani='printf "\n>>> Deleting untagged images\n\n" && docker rmi $(docker images -q -f dangling=true)' # Delete all stopped containers and untagged images. alias dockerclean='dockercleanc || true && dockercleani' # Build a thrift docker image (run from top level of git repo): argument #1 is image type (ubuntu, centos, etc). function dockerbuild { docker build -t $1 build/docker/$1 } # Run a thrift docker image: argument #1 is image type (ubuntu, centos, etc). function dockerrun { docker run -v $(pwd):/thrift/src -it $1 /bin/bash } Then, to pull down the current image being used to build (the same way Travis CI does it) - if it is out of date in any way it will build a new one for you: thrift$ DOCKER_REPO=thrift/thrift-build DISTRO=ubuntu-bionic build/docker/refresh.sh To run all unit tests (just like Travis CI does): thrift$ dockerrun thrift/thrift-build:ubuntu-bionic root@8caf56b0ce7b:/thrift/src# build/docker/scripts/autotools.sh To run the cross tests (just like Travis CI does): thrift$ dockerrun thrift/thrift-build:ubuntu-bionic root@8caf56b0ce7b:/thrift/src# build/docker/scripts/cross-test.sh When you are done, you want to clean up occasionally so that docker isn't using lots of extra disk space: thrift$ dockerclean You need to run the docker commands from the root of the local clone of the thrift git repository for them to work. When you are done in the root docker shell you can `exit` to go back to your user host shell. Once the unit tests and cross test passes locally, submit the changes, and if desired squash the pull request to one commit to make it easier to merge (the committers can squash at commit time now that GitHub is the master repository). Now you are building like Travis CI does! ## Raw Commands for Building with Docker ## If you do not want to use the same scripts Travis CI does, you can do it manually: Build the image: thrift$ docker build -t thrift build/docker/ubuntu-bionic Open a command prompt in the image: thrift$ docker run -v $(pwd):/thrift/src -it thrift /bin/bash ## Core Tool Versions per Dockerfile ## Last updated: October 1, 2017 | Tool | ubuntu-xenial | ubuntu-bionic | Notes | | :-------- | :------------ | :------------ | :---- | | ant | 1.9.6 | 1.10.3 | | | autoconf | 2.69 | 2.69 | | | automake | 1.15 | 1.15.1 | | | bison | 3.0.4 | 3.0.4 | | | boost | 1.58.0 | 1.65.1 | | | cmake | 3.5.1 | 3.10.2 | | | cppcheck | 1.72 | 1.82 | | | flex | 2.6.0 | 2.6.4 | | | libc6 | 2.23 | 2.27 | glibc | | libevent | 2.0.21 | 2.1.8 | | | libstdc++ | 5.4.0 | 7.3.0 | | | make | 4.1 | 4.1 | | | openssl | 1.0.2g | 1.1.0g | | | qt5 | 5.5.1 | 5.9.5 | | ## Compiler/Language Versions per Dockerfile ## | Language | ubuntu-xenial | ubuntu-bionic | Notes | | :-------- | :------------ | :------------ | :---- | | as of | Mar 06, 2018 | Jul 1, 2019 | | | as3 | | 4.6.0 | | | C++ gcc | 5.4.0 | 7.4.0 | | | C++ clang | 3.8 | 6.0 | | | C# (mono) | 4.2.1.0 | 4.6.2.7 | | | c_glib | 2.48.2 | 2.56.4 | | | cl (sbcl) | | 1.5.3 | | | d | 2.087.0 | 2.087.0 | | | dart | 2.0.0 | 2.4.0 | | | delphi | | | Not in CI | | erlang | 18.3 | 22.0 | | | go | 1.15.10 | 1.16.2 | | | haxe | 3.2.1 | 3.4.4 | THRIFT-4352: avoid 3.4.2 | | java | 1.8.0_191 | 11.0.3 | | | js | Node.js 6.17.1, V8 5.1.281.111, npm 3.10.10 | Node.js 10.18.0, V8 6.8.275.32, npm 6.13.4 | | | lua | | 5.2.4 | Lua 5.3: see THRIFT-4386 | | netstd | 6.0 | 6.0 | | | nodejs | 6.16.0 | 10.16.0 | | | ocaml | | 4.05.0 | THRIFT-4517: ocaml 4.02.3 on xenial appears broken | | perl | 5.22.1 | 5.26.1 | | | php | 7.0.32 | 7.2.19 | | | python | 2.7.12 | 2.7.15 | | | python3 | 3.5.2 | 3.6.8 | | | ruby | 2.3.1p112 | 2.5.1p57 | | | rust | 1.40.0 | 1.40.0 | | | smalltalk | | | Not in CI | | swift | | 5.1.4 | | thrift-0.16.0/build/docker/msvc2017/000077500000000000000000000000001420101504100167125ustar00rootroot00000000000000thrift-0.16.0/build/docker/msvc2017/Dockerfile000066400000000000000000000076411420101504100207140ustar00rootroot00000000000000# escape=` # # 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. # FROM microsoft/dotnet-framework:4.7.1 # Restore the default Windows shell for correct batch processing below. SHELL ["cmd", "/S", "/C"] # Install Build Tools excluding workloads and components with known issues. ADD https://aka.ms/vs/15/release/vs_buildtools.exe C:\TEMP\vs_buildtools.exe RUN C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache ` --installPath C:\BuildTools ` --all ` --remove Microsoft.VisualStudio.Component.Windows10SDK.10240 ` --remove Microsoft.VisualStudio.Component.Windows10SDK.10586 ` --remove Microsoft.VisualStudio.Component.Windows10SDK.14393 ` --remove Microsoft.VisualStudio.Component.Windows81SDK ` || IF "%ERRORLEVEL%"=="3010" EXIT 0 RUN DEL C:\TEMP\vs_buildtools.exe # Install CMake ADD https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-win64-x64.msi C:\TEMP\cmake.msi RUN msiexec.exe /i C:\TEMP\cmake.msi /qn && ` SETX PATH "%PATH%;C:\Program Files\CMake\bin" && ` DEL C:\TEMP\cmake.msi # Install boost (for the thrift runtime library build) ADD https://boost.teeks99.com/bin/1.69.0/boost_1_69_0-msvc-14.1-64.exe C:\TEMP\boost.exe RUN C:\TEMP\boost.exe /DIR="C:\Libraries\boost_1_69_0" /SILENT && ` DEL C:\TEMP\boost.exe # Install chocolatey RUN @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" ` -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command ` "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" ` && SETX PATH "%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" # Install winflexbison (for the thrift compiler build) RUN choco install winflexbison3 -y # Install 7zip and curl (used by the libevent and zlib build scripts) RUN choco install 7zip curl -y # Install libevent COPY appveyor\build-libevent.bat C:\TEMP\build-libevent.bat ENV LIBEVENT_VERSION=2.1.8 ENV WIN3P=C:\TEMP\WIN3P RUN C:\BuildTools\Common7\Tools\VsDevCmd.bat -arch=amd64 && ` MKDIR C:\TEMP\WIN3P && ` C:\TEMP\build-libevent.bat && ` MKDIR C:\Libraries\libevent-%LIBEVENT_VERSION% && ` MOVE C:\TEMP\WIN3P\libevent-%LIBEVENT_VERSION%-stable\include C:\Libraries\libevent-%LIBEVENT_VERSION% && ` MOVE C:\TEMP\WIN3P\libevent-%LIBEVENT_VERSION%-stable\lib C:\Libraries\libevent-%LIBEVENT_VERSION% && ` RMDIR /S /Q C:\TEMP\WIN3P # Install zlib COPY appveyor\build-zlib.bat C:\TEMP\build-zlib.bat ENV ZLIB_VERSION=1.2.11 ENV WIN3P=C:\TEMP\WIN3P RUN C:\BuildTools\Common7\Tools\VsDevCmd.bat -arch=amd64 && ` MKDIR C:\TEMP\WIN3P && ` C:\TEMP\build-zlib.bat && ` MOVE C:\TEMP\WIN3P\zlib-inst C:\Libraries\zlib-%ZLIB_VERSION% && ` RMDIR /S /Q C:\TEMP\WIN3P # Install OpenSSL 1.1.0 ADD http://slproweb.com/download/Win64OpenSSL-1_1_0j.exe C:\TEMP\openssl.exe RUN C:\TEMP\openssl.exe /silent && ` DEL C:\TEMP\openssl.exe # Install java RUN choco install jdk8 -y # Install python3 RUN choco install python3 -y # Install Adobe Flex 4.6 SDK and set FLEX_HOME so it can be found ADD http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip C:\Adobe\Flex\SDK\4.6\SDK.zip RUN CD C:\Adobe\Flex\SDK\4.6 && ` 7z x SDK.zip && ` DEL SDK.zip && ` SETX FLEX_HOME "C:\Adobe\Flex\SDK\4.6" # Start developer command prompt with any other commands specified. ENTRYPOINT C:\BuildTools\Common7\Tools\VsDevCmd.bat -arch=amd64 && # Default to PowerShell if no other command specified. CMD ["powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"] thrift-0.16.0/build/docker/msvc2017/README.md000066400000000000000000000032531420101504100201740ustar00rootroot00000000000000# Building Thrift using Docker for Windows The build image is very large (just under 30GB) so plan accordingly. Once Microsoft supports build tools in nano, it should get better. Install Docker for Windows and switch to Windows container mode. Pull from docker hub: PS C:\> docker pull thrift/thrift-build:msvc2017 or build in a docker for windows environment: PS C:\Thrift> docker build -t thrift/thrift-build:msvc2017 -f build\docker\msvc2017\Dockerfile build\ The following directories are used inside the container: C:\Build the out-of-tree build directory C:\Install the install target directory C:\Thrift the source tree You can override these as docker volumes if desired. ### Compiler To build a portable windows thrift compiler (with a statically linked runtime) and get it placed into C:\install: docker run -v C:\thrift:C:\thrift^ -v C:\install:C:\install^ --rm -t thrift/thrift-build:msvc2017^ C:\thrift\build\docker\msvc2017\build-compiler.bat The end result is a portable windows thrift compiler located at C:\Install\bin\thrift.exe If you run it through the [Dependency Walker](http://www.dependencywalker.com/) you will see it only depends on KERNEL32.DLL which means the runtime is statically linked, so the executable is portable and self-contained. This is how the windows thrift compiler is built for each Apache Thrift release. ### Libraries To build, test everything and get the C++ SDK placed into C:\install: docker run -v C:\thrift:C:\thrift^ -v C:\install:C:\install^ -m 4096 --rm -t thrift/thrift-build:msvc2017^ C:\thrift\build\docker\msvc2017\build.batthrift-0.16.0/build/docker/msvc2017/build-compiler.bat000066400000000000000000000024471420101504100223200ustar00rootroot00000000000000:: :: 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. :: :: :: Build script example for inside the windows docker container :: :: C:\build is the out-of-tree build directory :: C:\install is the location where artifacts are placed :: C:\thrift is where the sources are :: :: Make and go into the out-of-tree directory IF NOT EXIST C:\build (MKDIR C:\build) cd c:\build :: Generate the out-of-tree build files cmake^ -DBOOST_ROOT=C:\Libraries\boost_1_69_0^ -DBOOST_LIBRARYDIR=C:\Libraries\boost_1_69_0\lib64-msvc-14.1^ -DBUILD_LIBRARIES=OFF^ -DCMAKE_BUILD_TYPE=Release^ -DCMAKE_INSTALL_PREFIX=C:\install^ -DWITH_MT=ON^ c:\thrift || EXIT /B :: Build cmake --build . --target thrift-compiler --config Release || EXIT /B :: Test cmake --build . --target check || EXIT /B :: Install cmake --install .thrift-0.16.0/build/docker/msvc2017/build.bat000066400000000000000000000025421420101504100205040ustar00rootroot00000000000000:: :: 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. :: :: :: Build script example for inside the windows docker container :: :: C:\build is the out-of-tree build directory :: C:\install is the location where artifacts are placed :: C:\thrift is where the sources are :: :: Make and go into the out-of-tree directory IF NOT EXIST C:\build (MKDIR C:\build) cd c:\build :: Generate the out-of-tree build files cmake^ -DBOOST_ROOT=C:\Libraries\boost_1_69_0^ -DBOOST_LIBRARYDIR=C:\Libraries\boost_1_69_0\lib64-msvc-14.1^ -DFLEX_HOME=C:\Adobe\Flex\SDK\4.6^ -DLIBEVENT_ROOT=C:\Libraries\libevent-2.1.8^ -DZLIB_ROOT=C:\Libraries\zlib-1.2.11^ -DCMAKE_BUILD_TYPE=Release^ -DCMAKE_INSTALL_PREFIX=C:\install^ c:\thrift || EXIT /B :: Build cmake --build . --config Release || EXIT /B :: Test cmake --build . --target check || EXIT /B :: Install cmake --install . thrift-0.16.0/build/docker/old/000077500000000000000000000000001420101504100162065ustar00rootroot00000000000000thrift-0.16.0/build/docker/old/Vagrantfile000066400000000000000000000037451420101504100204040ustar00rootroot00000000000000# -*- mode: ruby -*- # vi: set ft=ruby : # # 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. # Base system bootstrap script $bootstrap_script = <<__BOOTSTRAP__ echo "Provisioning defaults" sudo apt-get update -y sudo apt-get upgrade -y # Install default packages sudo apt-get install -y build-essential curl git # Install latest Docker version sudo curl -sSL https://get.docker.io/gpg | sudo apt-key add - sudo echo "deb http://get.docker.io/ubuntu docker main" > /etc/apt/sources.list.d/docker.list sudo apt-get update -y sudo apt-get install -y linux-image-extra-`uname -r` aufs-tools sudo apt-get install -y lxc-docker echo "Finished provisioning defaults" __BOOTSTRAP__ Vagrant.configure("2") do |config| config.vm.box = "trusty64" config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box" config.ssh.forward_agent = true config.vm.provider :virtualbox do |vbox| vbox.customize ["modifyvm", :id, "--memory", "1024"] vbox.customize ["modifyvm", :id, "--cpus", "2"] end # Setup the default bootstrap script for our ubuntu base box image config.vm.provision "shell", inline: $bootstrap_script # Setup the custom docker image from our Ubuntu Dockerfile config.vm.provision "docker" do |d| d.build_image "/vagrant/ubuntu", args: "-t thrift" end # Setup the custom docker image from our Centos Dockerfile #config.vm.provision "docker" do |d| # d.build_image "/vagrant/centos", args: "-t thrift-centos" #end end thrift-0.16.0/build/docker/old/centos-7.3/000077500000000000000000000000001420101504100200065ustar00rootroot00000000000000thrift-0.16.0/build/docker/old/centos-7.3/Dockerfile000066400000000000000000000127471420101504100220130ustar00rootroot00000000000000# 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. # Apache Thrift Docker build environment for CentOS # # Known missing client libraries: # - dotnet (will update to 2.0.0 separately) # - haxe (not in centos) FROM centos:7.3.1611 MAINTAINER Apache Thrift RUN yum install -y epel-release # General dependencies RUN yum install -y \ autoconf \ bison \ bison-devel \ clang \ clang-analyzer \ cmake3 \ curl \ flex \ gcc \ gcc-c++ \ gdb \ git \ libtool \ m4 \ make \ tar \ unzip \ valgrind \ wget && \ ln -s /usr/bin/cmake3 /usr/bin/cmake && \ ln -s /usr/bin/cpack3 /usr/bin/cpack && \ ln -s /usr/bin/ctest3 /usr/bin/ctest # C++ dependencies RUN yum install -y \ boost-devel-static \ zlib-devel \ openssl-devel \ libevent-devel && \ cd /usr/lib64 && \ ln -s libboost_thread-mt.a libboost_thread.a # C# Dependencies RUN yum install -y \ mono-core \ mono-devel \ mono-web-devel \ mono-extras # D Dependencies RUN yum install -y http://downloads.dlang.org/releases/2.x/2.076.0/dmd-2.076.0-0.fedora.x86_64.rpm xdg-utils RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ mv libevent-master/deimos/* openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv libevent-master/C/* openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf libevent-master openssl-master # Dart RUN cd /usr/local && \ wget -q https://storage.googleapis.com/dart-archive/channels/stable/release/1.24.2/sdk/dartsdk-linux-x64-release.zip && \ unzip -q dartsdk-linux-x64-release.zip && \ rm dartsdk-linux-x64-release.zip ENV PATH /usr/local/dart-sdk/bin:$PATH # Erlang Dependencies RUN curl -sSL http://packages.erlang-solutions.com/rpm/centos/erlang_solutions.repo -o /etc/yum.repos.d/erlang_solutions.repo && \ yum install -y \ erlang-kernel \ erlang-erts \ erlang-stdlib \ erlang-eunit \ erlang-rebar \ erlang-tools # GLibC Dependencies RUN yum install -y glib2-devel # Go Dependencies RUN curl -sSL https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz | tar -C /usr/local/ -xz ENV PATH /usr/local/go/bin:$PATH # Haxe Dependencies # Not in debian/stretch # Java Dependencies RUN yum install -y \ ant \ junit \ ant-junit \ java-1.8.0-openjdk-devel # Lua Dependencies # Lua in epel is too old (5.1.4, need 5.2) so we get the latest RUN yum install -y readline-devel && \ wget -q http://www.lua.org/ftp/lua-5.3.4.tar.gz && \ tar xzf lua-5.3.4.tar.gz && \ cd lua-5.3.4 && \ sed -i 's/CFLAGS= /CFLAGS= -fPIC /g' src/Makefile && \ make linux && \ make install && \ cd .. && \ rm -rf lua-5* # MinGW Dependencies RUN yum install -y \ mingw32-binutils \ mingw32-crt \ mingw32-nsis # Node.js Dependencies # Work around epel issue where they removed http-parser that nodejs depends on! RUN yum -y install https://opensource.enda.eu/packages/http-parser-2.7.1-3.el7.x86_64.rpm RUN yum install -y \ nodejs \ npm # Ocaml Dependencies RUN yum install -y \ ocaml \ ocaml-ocamldoc && \ wget -q https://raw.github.com/ocaml/opam/master/shell/opam_installer.sh -O - | sh -s /usr/local/bin && \ opam init --yes && \ opam install --yes oasis && \ echo '. /root/.opam/opam-init/init.sh > /dev/null 2> /dev/null || true' >> ~/.bashrc # Perl Dependencies RUN yum install -y \ perl \ perl-version \ perl-Bit-Vector \ perl-Class-Accessor \ perl-ExtUtils-MakeMaker \ perl-Test-Simple \ perl-IO-Socket-SSL \ perl-Net-SSLeay \ perl-Crypt-SSLeay # PHP Dependencies RUN yum install -y \ php \ php-devel \ php-pear \ re2c \ php-phpunit-PHPUnit \ bzip2 # Python Dependencies RUN yum install -y \ python \ python-devel \ python-pip \ python-setuptools \ python34 \ python34-devel \ python34-pip \ python34-setuptools RUN pip2 install --upgrade pip RUN pip2 install --upgrade backports.ssl_match_hostname ipaddress setuptools six tornado tornado-testing twisted virtualenv zope-interface RUN pip3 install --upgrade pip RUN pip3 install --upgrade backports.ssl_match_hostname ipaddress setuptools six tornado tornado-testing twisted virtualenv zope-interface # Ruby Dependencies RUN yum install -y \ ruby \ ruby-devel \ rubygems && \ gem install bundler rake # Rust RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.17.0 ENV PATH /root/.cargo/bin:$PATH # Clean up RUN rm -rf /tmp/* && \ yum clean all ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/docker/old/debian-jessie/000077500000000000000000000000001420101504100207105ustar00rootroot00000000000000thrift-0.16.0/build/docker/old/debian-jessie/Dockerfile000066400000000000000000000140111420101504100226770ustar00rootroot00000000000000# 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. # Apache Thrift Docker build environment for Debian # # Known missing client libraries: # - dotnetcore # - rust FROM buildpack-deps:jessie-scm MAINTAINER Apache Thrift ENV DEBIAN_FRONTEND noninteractive # Add apt sources # jessie-backports for cmake and some ruby bits RUN echo "deb http://ftp.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/jessie-backports.list # Dart RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g' RUN apt-get update && apt-get install -y --no-install-recommends \ `# General dependencies` \ bison \ build-essential \ clang \ debhelper \ flex \ pkg-config && \ apt-get -t jessie-backports install -y --no-install-recommends cmake RUN apt-get install -y --no-install-recommends \ `# C++ dependencies` \ libboost-dev \ libboost-filesystem-dev \ libboost-program-options-dev \ libboost-system-dev \ libboost-test-dev \ libboost-thread-dev \ libevent-dev \ libssl-dev \ qt5-default \ qtbase5-dev \ qtbase5-dev-tools RUN apt-get install -y --no-install-recommends \ `# Java dependencies` \ ant \ ant-optional \ openjdk-7-jdk \ maven RUN apt-get install -y --no-install-recommends \ `# Python dependencies` \ python-all \ python-all-dbg \ python-all-dev \ python-pip \ python-setuptools \ python-twisted \ python-zope.interface \ python3-all \ python3-all-dbg \ python3-all-dev \ python3-setuptools \ python3-pip RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ ruby \ ruby-bundler \ ruby-dev \ `# Perl dependencies` \ libbit-vector-perl \ libclass-accessor-class-perl \ libcrypt-ssleay-perl \ libio-socket-ssl-perl \ libnet-ssleay-perl RUN apt-get -t jessie-backports install -y ruby-bundler RUN apt-get install -y --no-install-recommends \ `# Php dependencies` \ php5 \ php5-dev \ php5-cli \ php-pear \ re2c \ phpunit \ `# GlibC dependencies` \ libglib2.0-dev RUN apt-get update && apt-get install -y --no-install-recommends \ `# Erlang dependencies` \ erlang-base \ erlang-eunit \ erlang-dev \ erlang-tools \ rebar RUN apt-get update && apt-get install -y --no-install-recommends \ `# Haxe dependencies` \ neko \ neko-dev \ libneko0 RUN apt-get update && apt-get install -y --no-install-recommends \ `# Node.js dependencies` \ nodejs \ nodejs-dev \ nodejs-legacy \ npm RUN apt-get update && apt-get install -y --no-install-recommends \ `# D dependencies` \ xdg-utils \ `# Dart dependencies` \ dart \ `# Lua dependencies` \ lua5.2 \ lua5.2-dev \ `# MinGW dependencies` \ mingw32 \ mingw32-binutils \ `# mingw32-runtime` \ nsis \ `# Clean up` \ && rm -rf /var/cache/apt/* && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /var/tmp/* # Ruby RUN gem install bundler --no-ri --no-rdoc # Python optional dependencies RUN pip2 install -U ipaddress backports.ssl_match_hostname tornado RUN pip3 install -U backports.ssl_match_hostname tornado # Go RUN curl -sSL https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz ENV PATH /usr/local/go/bin:$PATH # Haxe RUN mkdir -p /usr/lib/haxe && \ wget -O - https://github.com/HaxeFoundation/haxe/releases/download/3.2.1/haxe-3.2.1-linux64.tar.gz | \ tar -C /usr/lib/haxe --strip-components=1 -xz && \ ln -s /usr/lib/haxe/haxe /usr/bin/haxe && \ ln -s /usr/lib/haxe/haxelib /usr/bin/haxelib && \ mkdir -p /usr/lib/haxe/lib && \ chmod -R 777 /usr/lib/haxe/lib && \ haxelib setup /usr/lib/haxe/lib && \ haxelib install hxcpp # D RUN curl -sSL http://downloads.dlang.org/releases/2.x/2.070.0/dmd_2.070.0-0_amd64.deb -o /tmp/dmd_2.070.0-0_amd64.deb && \ dpkg -i /tmp/dmd_2.070.0-0_amd64.deb && \ rm /tmp/dmd_2.070.0-0_amd64.deb && \ curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ mv libevent-master/deimos/* openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv libevent-master/C/* openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf libevent-master openssl-master && \ echo 'gcc -Wl,--no-as-needed $*' > /usr/local/bin/gcc-dmd && \ chmod 755 /usr/local/bin/gcc-dmd && \ echo 'CC=/usr/local/bin/gcc-dmd' >> /etc/dmd.conf # Dart ENV PATH /usr/lib/dart/bin:$PATH # OCaml RUN echo 'deb http://ppa.launchpad.net/avsm/ppa/ubuntu trusty main' > /etc/apt/sources.list.d/avsm-official-ocaml.list && \ gpg --keyserver keyserver.ubuntu.com --recv 61707B09 && \ gpg --export --armor 61707B09 | apt-key add - && \ apt-get update && \ apt-get install -y ocaml opam && \ opam init && \ opam install oasis # Force utf8 locale to successfully build Haskell tf-random ENV LC_ALL C.UTF-8 ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/docker/old/debian-stretch/000077500000000000000000000000001420101504100211025ustar00rootroot00000000000000thrift-0.16.0/build/docker/old/debian-stretch/Dockerfile000066400000000000000000000151551420101504100231030ustar00rootroot00000000000000# 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. # Apache Thrift Docker build environment for Debian Stretch # # Known issues: # - d: deimos for libevent and openssl disabled - build errors # - dotnetcore, because netcore is for 1.0.0-preview and 2.0.0 is out # - rust: cargo not in debian repo - perhaps not needed? FROM buildpack-deps:stretch-scm MAINTAINER Apache Thrift ENV DEBIAN_FRONTEND noninteractive ### Add apt repos RUN apt-get update && apt-get install -y --no-install-recommends apt apt-transport-https curl wget apt-utils # D RUN wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \ apt-get update && apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring # Dart RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \ sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g' # dotnet (core) 2.0.0 - project isn't ready for this yet: # RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ # echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list # node.js (this step runs apt-get update internally) RUN curl -sL https://deb.nodesource.com/setup_8.x | bash ### install general dependencies RUN apt-get install -y --no-install-recommends \ `# General dependencies` \ bash-completion \ bison \ build-essential \ clang \ cmake \ debhelper \ flex \ gdb \ ninja-build \ pkg-config \ valgrind \ vim ### languages RUN apt-get install -y --no-install-recommends \ `# C++ dependencies` \ libboost-dev \ libboost-filesystem-dev \ libboost-program-options-dev \ libboost-system-dev \ libboost-test-dev \ libboost-thread-dev \ libevent-dev \ libssl-dev \ qt5-default \ qtbase5-dev \ qtbase5-dev-tools RUN apt-get install -y --no-install-recommends \ `# D dependencies` \ dmd-bin \ libevent-dev \ libssl-dev \ xdg-utils # libevent deimos disabled - build errors # RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ # curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ # mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ # mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \ # rm -rf libevent-master # openssl deimos doesn't work with openssl-1.1.0 - disabling it for now: # RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ # mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ # mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ # rm -rf openssl-master RUN apt-get install -y --no-install-recommends \ `# Dart dependencies` \ dart ENV PATH /usr/lib/dart/bin:$PATH # project isn't ready for this quite yet: # RUN apt-get install -y --no-install-recommends \ # `# dotnet core dependencies` \ # dotnet-sdk-6.0 \ # dotnet-runtime-6.0 \ # aspnetcore-runtime-6.0 \ # dotnet-apphost-pack-6.0 RUN apt-get install -y --no-install-recommends \ `# Erlang dependencies` \ erlang-base \ erlang-eunit \ erlang-dev \ erlang-tools \ rebar RUN apt-get install -y --no-install-recommends \ `# GlibC dependencies` \ libglib2.0-dev RUN apt-get install -y --no-install-recommends \ `# golang (go) dependencies` \ golang-go RUN apt-get install -y --no-install-recommends \ `# Haxe dependencies` \ haxe \ neko \ neko-dev RUN haxelib setup --always /usr/share/haxe/lib && \ haxelib install --always hxcpp RUN apt-get install -y --no-install-recommends \ `# Java dependencies` \ ant \ ant-optional \ openjdk-8-jdk \ maven RUN apt-get install -y --no-install-recommends \ `# Lua dependencies` \ lua5.2 \ lua5.2-dev # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 # same for debian stretch # lua5.3 does not install alternatives so stick with 5.2 here RUN apt-get install -y --no-install-recommends \ `# Node.js dependencies` \ nodejs RUN apt-get install -y --no-install-recommends \ `# OCaml dependencies` \ ocaml \ opam && \ opam init --yes && \ opam install --yes oasis RUN apt-get install -y --no-install-recommends \ `# Perl dependencies` \ libbit-vector-perl \ libclass-accessor-class-perl \ libcrypt-ssleay-perl \ libio-socket-ssl-perl \ libnet-ssleay-perl RUN apt-get install -y --no-install-recommends \ `# Php dependencies` \ php7.0 \ php7.0-cli \ php7.0-dev \ php-pear \ re2c \ phpunit RUN apt-get install -y --no-install-recommends \ `# Python dependencies` \ python-all \ python-all-dbg \ python-all-dev \ python-backports.ssl-match-hostname \ python-ipaddress \ python-pip \ python-setuptools \ python-six \ python-tornado \ python-twisted \ python-wheel \ python-zope.interface \ python3-all \ python3-all-dbg \ python3-all-dev \ python3-setuptools \ python3-six \ python3-tornado \ python3-twisted \ python3-wheel \ python3-zope.interface && \ pip install --upgrade backports.ssl_match_hostname RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ ruby \ ruby-dev \ ruby-bundler RUN gem install bundler --no-ri --no-rdoc RUN apt-get install -y --no-install-recommends \ `# Rust dependencies` \ rustc # Update anything else left hanging RUN apt-get dist-upgrade -y # Clean up RUN rm -rf /var/cache/apt/* && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /var/tmp/* ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/docker/old/ubuntu-artful/000077500000000000000000000000001420101504100210235ustar00rootroot00000000000000thrift-0.16.0/build/docker/old/ubuntu-artful/Dockerfile000066400000000000000000000175521420101504100230270ustar00rootroot00000000000000# 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. # # Apache Thrift Docker build environment for Ubuntu Artful # Using all stock Ubuntu Artful packaging except for: # - cpp: stock boost 1.62 in artful has a nasty bug so we use stock boost 1.63 # - d: dmd does not come with Ubuntu # - dart: does not come with Ubuntu. Pinned to last 1.x release # - dotnet: does not come with Ubuntu # - haxe: version 3.4.2 that comes with Ubuntu cores in our CI build # - go: artful comes with 1.9, we want the latest (supported) # - nodejs: want v8, artful comes with v6 # FROM buildpack-deps:artful-scm MAINTAINER Apache Thrift ENV DEBIAN_FRONTEND noninteractive ### Add apt repos RUN apt-get update && \ apt-get dist-upgrade -y && \ apt-get install -y --no-install-recommends \ apt \ apt-transport-https \ apt-utils \ curl \ dirmngr \ software-properties-common \ wget # Dart RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \ /etc/apt/sources.list.d/dart_stable.list ENV DART_VERSION 1.24.3-1 # dotnet (netcore) RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-artful-prod artful main" > \ /etc/apt/sources.list.d/dotnetdev.list # haxe (https://haxe.org/download/linux/) RUN add-apt-repository ppa:haxe/releases -y # node.js RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ echo "deb https://deb.nodesource.com/node_8.x artful main" | tee /etc/apt/sources.list.d/nodesource.list ### install general dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ `# General dependencies` \ bash-completion \ bison \ build-essential \ clang \ cmake \ debhelper \ flex \ gdb \ llvm \ ninja-build \ pkg-config \ valgrind \ vim ENV PATH /usr/lib/llvm-3.8/bin:$PATH # boost-1.62 has a terrible bug in boost::test, see https://svn.boost.org/trac10/ticket/12507 RUN apt-get install -y --no-install-recommends \ `# C++ dependencies` \ libboost1.63-all-dev \ libevent-dev \ libssl-dev \ qt5-default \ qtbase5-dev \ qtbase5-dev-tools ENV SBCL_VERSION 1.4.5 RUN \ `# Common Lisp (sbcl) dependencies` \ curl --version && \ curl -O -J -L https://kent.dl.sourceforge.net/project/sbcl/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \ tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \ cd sbcl-${SBCL_VERSION}-x86-64-linux && \ ./install.sh && \ sbcl --version && \ rm -rf sbcl* ENV D_VERSION 2.080.0 ENV DMD_DEB dmd_2.080.0-0_amd64.deb RUN \ `# D dependencies` \ wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \ dpkg --install ${DMD_DEB} && \ rm -f ${DMD_DEB} && \ mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf libevent-master && \ curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf openssl-master RUN apt-get install -y --no-install-recommends \ `# Dart dependencies` \ dart=$DART_VERSION ENV PATH /usr/lib/dart/bin:$PATH RUN apt-get install -y --no-install-recommends \ `# dotnet core dependencies` \ dotnet-sdk-6.0 \ dotnet-runtime-6.0 \ aspnetcore-runtime-6.0 \ dotnet-apphost-pack-6.0 RUN apt-get install -y --no-install-recommends \ `# Erlang dependencies` \ erlang-base \ erlang-eunit \ erlang-dev \ erlang-tools \ rebar RUN apt-get install -y --no-install-recommends \ `# GlibC dependencies` \ libglib2.0-dev # golang ENV GOLANG_VERSION 1.10 ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 b5a64335f1490277b585832d1f6c7f8c6c11206cba5cd3f771dcb87b98ad1a33 RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \ echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \ tar -C /usr/local -xzf golang.tar.gz && \ ln -s /usr/local/go/bin/go /usr/local/bin && \ rm golang.tar.gz RUN apt-get install -y --no-install-recommends \ `# Haxe dependencies` \ haxe \ neko \ neko-dev && \ haxelib setup --always /usr/share/haxe/lib && \ haxelib install --always hxcpp 2>&1 > /dev/null RUN apt-get install -y --no-install-recommends \ `# Java dependencies` \ ant \ ant-optional \ openjdk-8-jdk \ maven RUN apt-get install -y --no-install-recommends \ `# Lua dependencies` \ lua5.2 \ lua5.2-dev # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 # lua5.3 does not install alternatives! # need to update our luasocket code, lua doesn't have luaL_openlib any more RUN apt-get install -y --no-install-recommends \ `# Node.js dependencies` \ nodejs # Test dependencies for running puppeteer RUN apt-get install -y --no-install-recommends \ `# JS dependencies` \ libxss1 RUN apt-get install -y --no-install-recommends \ `# OCaml dependencies` \ ocaml \ opam && \ opam init --yes && \ opam install --yes oasis RUN apt-get install -y --no-install-recommends \ `# Perl dependencies` \ libbit-vector-perl \ libclass-accessor-class-perl \ libcrypt-ssleay-perl \ libio-socket-ssl-perl \ libnet-ssleay-perl RUN apt-get install -y --no-install-recommends \ `# Php dependencies` \ php \ php-cli \ php-dev \ php-pear \ re2c \ composer RUN apt-get install -y --no-install-recommends \ `# Python dependencies` \ python-all \ python-all-dbg \ python-all-dev \ python-ipaddress \ python-pip \ python-setuptools \ python-six \ python-tornado \ python-twisted \ python-wheel \ python-zope.interface && \ pip install --upgrade backports.ssl_match_hostname RUN apt-get install -y --no-install-recommends \ `# Python3 dependencies` \ python3-all \ python3-all-dbg \ python3-all-dev \ python3-pip \ python3-setuptools \ python3-six \ python3-tornado \ python3-twisted \ python3-wheel \ python3-zope.interface RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ ruby \ ruby-dev \ ruby-bundler RUN apt-get install -y --no-install-recommends \ `# Rust dependencies` \ cargo \ rustc RUN apt-get install -y --no-install-recommends \ `# Static Code Analysis dependencies` \ cppcheck \ sloccount && \ pip install flake8 # Clean up RUN rm -rf /var/cache/apt/* && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /var/tmp/* ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/docker/old/ubuntu-trusty/000077500000000000000000000000001420101504100211005ustar00rootroot00000000000000thrift-0.16.0/build/docker/old/ubuntu-trusty/Dockerfile000066400000000000000000000170321420101504100230750ustar00rootroot00000000000000# 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. # # Apache Thrift Docker build environment for Ubuntu Trusty # Using all stock Ubuntu Trusty packaging except for: # - d: does not come with Ubuntu so we're installing 2.070.0 # - dart: does not come with Ubuntu so we're installing 1.20.1 # - dotnetcore, disabled because netcore is for 1.0.0-preview and 2.0.0 is out # - haxe, disabled because the distro comes with 3.0.0 and it cores while installing # - node.js, disabled because it is at 0.10.0 in the distro which is too old (need 4+) # - ocaml, disabled because it fails to install properly # FROM buildpack-deps:trusty-scm MAINTAINER Apache Thrift ENV DEBIAN_FRONTEND noninteractive ### Add apt repos RUN apt-get update && \ apt-get dist-upgrade -y && \ apt-get install -y --no-install-recommends \ apt \ apt-transport-https \ apt-utils \ curl \ dirmngr \ software-properties-common \ wget # D RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EBCF975E5BA24D5E && \ wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \ wget -qO - https://dlang.org/d-keyring.gpg | apt-key add - # Dart RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \ /etc/apt/sources.list.d/dart_stable.list RUN apt-get update && apt-get install -y --no-install-recommends \ `# General dependencies` \ bash-completion \ bison \ build-essential \ clang \ cmake \ debhelper \ flex \ gdb \ llvm \ ninja-build \ pkg-config \ valgrind \ vim ENV PATH /usr/lib/llvm-3.8/bin:$PATH RUN apt-get install -y --no-install-recommends \ `# C++ dependencies` \ libboost-all-dev \ libevent-dev \ libssl-dev \ qt5-default \ qtbase5-dev \ qtbase5-dev-tools RUN apt-get install -y --no-install-recommends \ `# D dependencies` \ dmd-bin=2.070.2-0 \ libphobos2-dev=2.070.2-0 \ dub \ dfmt \ dscanner \ xdg-utils RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \ mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf libevent-master RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \ mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf openssl-master RUN apt-get install -y --no-install-recommends \ `# Dart dependencies` \ dart=1.20.1-1 ENV PATH /usr/lib/dart/bin:$PATH RUN apt-get install -y --no-install-recommends \ `# Erlang dependencies` \ erlang-base \ erlang-eunit \ erlang-dev \ erlang-tools \ rebar RUN apt-get install -y --no-install-recommends \ `# GlibC dependencies` \ libglib2.0-dev # golang ENV GOLANG_VERSION 1.7.6 ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 ad5808bf42b014c22dd7646458f631385003049ded0bb6af2efc7f1f79fa29ea RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \ echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \ tar -C /usr/local -xzf golang.tar.gz && \ ln -s /usr/local/go/bin/go /usr/local/bin && \ rm golang.tar.gz # disabled because it cores while installing # RUN apt-get install -y --no-install-recommends \ # `# Haxe dependencies` \ # haxe \ # neko \ # neko-dev && \ # haxelib setup /usr/share/haxe/lib && \ # haxelib install hxcpp 3.2.102 RUN apt-get install -y --no-install-recommends \ `# Java dependencies` \ ant \ ant-optional \ openjdk-7-jdk \ maven RUN apt-get install -y --no-install-recommends \ `# Lua dependencies` \ lua5.1 \ lua5.1-dev # disabled because it is too old # RUN apt-get install -y --no-install-recommends \ # `# Node.js dependencies` \ # nodejs \ # npm # disabled because it fails to install properly # RUN apt-get install -y --no-install-recommends \ # `# OCaml dependencies` \ # ocaml \ # opam && \ # opam init --yes && \ # opam install --yes oasis RUN apt-get install -y --no-install-recommends \ `# Perl dependencies` \ libbit-vector-perl \ libclass-accessor-class-perl \ libcrypt-ssleay-perl \ libio-socket-ssl-perl \ libnet-ssleay-perl RUN apt-get install -y --no-install-recommends \ `# Php dependencies` \ php5 \ php5-cli \ php5-dev \ php-pear \ re2c && \ wget https://getcomposer.org/installer -O - -q | php -- --quiet --install-dir=/usr/local/bin/ --filename=composer RUN apt-get install -y --no-install-recommends \ `# Python dependencies` \ python-all \ python-all-dbg \ python-all-dev \ python-pip \ python-setuptools \ python-six \ python-twisted \ python-wheel \ python-zope.interface \ python3-all \ python3-all-dbg \ python3-all-dev \ python3-pip \ python3-setuptools \ python3-six \ python3-wheel \ python3-zope.interface && \ pip install -U ipaddress backports.ssl_match_hostname tornado && \ pip3 install -U backports.ssl_match_hostname tornado # installing tornado by pip/pip3 instead of debian package # if we install the debian package, the build fails in py2 RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ ruby \ ruby-dev \ ruby-bundler RUN gem install bundler --no-ri --no-rdoc RUN apt-get install -y --no-install-recommends \ `# Rust dependencies` \ cargo \ rustc RUN apt-get install -y --no-install-recommends \ `# Static Code Analysis dependencies` \ cppcheck \ sloccount && \ pip install flake8 # Install BouncyCastle provider to fix Java builds issues with JDK 7 # Builds accessing repote repositories fail as seen here: https://github.com/travis-ci/travis-ci/issues/8503 RUN apt-get install -y --no-install-recommends \ `# BouncyCastle JCE Provider dependencies` \ libbcprov-java && \ ln -s /usr/share/java/bcprov.jar /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/bcprov.jar && \ awk -F . -v OFS=. 'BEGIN{n=2}/^security\.provider/ {split($3, posAndEquals, "=");$3=n++"="posAndEquals[2];print;next} 1' /etc/java-7-openjdk/security/java.security > /tmp/java.security && \ echo "security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider" >> /tmp/java.security && \ mv /tmp/java.security /etc/java-7-openjdk/security/java.security # Clean up RUN rm -rf /var/cache/apt/* && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /var/tmp/* ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/docker/refresh.sh000077500000000000000000000054301420101504100174270ustar00rootroot00000000000000#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # The build has two stages: "docker" and "test" # The "docker" stage is meant to rebuild the docker images # if needed. If we cannot push that result however then # there is no reason to do anything. # The "test" stage is an actual test job. Even if the docker # image doesn't match what's in the repo, we still build # the image so the build job can run properly. # set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DOCKER_TAG=$DOCKER_REPO:$DISTRO function dockerfile_changed { # image may not exist yet, so we have to let it fail silently: docker pull $DOCKER_TAG || true docker run $DOCKER_TAG bash -c 'cd .. && sha512sum Dockerfile' > .Dockerfile.sha512 sha512sum -c .Dockerfile.sha512 } # # If this build has no DOCKER_PASS and it is in the docker stage # then there's no reason to do any processing because we cannot # push the result if the Dockerfile changed. # if [[ "$TRAVIS_BUILD_STAGE" == "docker" ]] && [[ -z "$DOCKER_PASS" ]]; then echo Detected docker stage build and no defined DOCKER_PASS, this build job will be skipped. echo Subsequent jobs in the test stage may each rebuild the docker image. exit 0 fi pushd ${SCRIPT_DIR}/$DISTRO if dockerfile_changed; then echo Dockerfile has not changed. No need to rebuild. exit 0 else echo Dockerfile has changed. fi popd # # Dockerfile has changed - rebuild it for the current build job. # If it is a "docker" stage build then we want to push it back # to the DOCKER_REPO. If it is a "test" stage build then we do # not. If nobody defined a DOCKER_PASS then it doesn't matter. # echo Rebuilding docker image $DISTRO docker build --tag $DOCKER_TAG build/docker/$DISTRO if [[ "$TRAVIS_BUILD_STAGE" == "docker" ]] && [[ ! -z "$DOCKER_USER" ]] && [[ ! -z "$DOCKER_PASS" ]]; then echo Pushing docker image $DOCKER_TAG docker login -u $DOCKER_USER -p $DOCKER_PASS docker push $DOCKER_TAG else echo Not pushing docker image: either not a docker stage build job, or one of DOCKER_USER or DOCKER_PASS is undefined. fi thrift-0.16.0/build/docker/run.sh000077500000000000000000000020421420101504100165710ustar00rootroot00000000000000#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DOCKER_TAG=$DOCKER_REPO:$DISTRO printenv | sort docker run --net=host -e BUILD_LIBS="$BUILD_LIBS" $BUILD_ENV -v $(pwd):/thrift/src \ -it $DOCKER_TAG build/docker/scripts/$SCRIPT $BUILD_ARG thrift-0.16.0/build/docker/scripts/000077500000000000000000000000001420101504100171175ustar00rootroot00000000000000thrift-0.16.0/build/docker/scripts/autotools.sh000077500000000000000000000005401420101504100215060ustar00rootroot00000000000000#!/bin/sh set -ev mkdir ~/.m2 tee >~/.m2/settings.xml < secure-central https://repo.maven.apache.org/maven2 central EOF ./bootstrap.sh ./configure $* make check -j3 thrift-0.16.0/build/docker/scripts/cmake.sh000077500000000000000000000005771420101504100205470ustar00rootroot00000000000000#!/bin/sh set -ev CMAKE_FLAGS=$* MAKEPROG=make if ninja --version >/dev/null 2>&1; then MAKEPROG=ninja CMAKE_FLAGS="-GNinja $CMAKE_FLAGS" fi mkdir -p cmake_build && cd cmake_build cmake $CMAKE_FLAGS .. for LIB in $BUILD_LIBS; do if ! grep "^BUILD_${LIB}:BOOL=ON$" CMakeCache.txt ; then echo "failed to configure $LIB" exit 1 fi done $MAKEPROG -j3 cpack ctest -VV thrift-0.16.0/build/docker/scripts/coverity.sh000077500000000000000000000025161420101504100213260ustar00rootroot00000000000000#! /bin/bash # # This script allows you to run coverity on the project and submit the # results. Do this inside the docker build container. Only works if # you are a coverity scan thrift project admin with access to the # necessary security token. # # Environment Variables # # COVERITY_SCAN_NOTIFICATION_EMAIL - email address to notify # COVERITY_SCAN_TOKEN - the Coverity Scan token (should be secure) # VERSION - the version to report we scanned set -ex wget -nv https://entrust.com/root-certificates/entrust_l1k.cer -O /tmp/scanca.cer pushd /tmp if [[ "$1" != "--skipdownload" ]]; then rm -rf coverity_tool.tgz cov-analysis* wget -nv -O coverity_tool.tgz https://scan.coverity.com/download/cxx/linux64 --post-data "project=thrift&token=$COVERITY_SCAN_TOKEN" tar xzf coverity_tool.tgz fi COVBIN=$(echo $(pwd)/cov-analysis*/bin) export PATH=$COVBIN:$PATH popd ./bootstrap.sh ./configure $* rm -rf cov-int/ cov-build --dir cov-int make check -j3 tail -50 cov-int/build-log.txt tar cJf cov-int.tar.xz cov-int/ curl --cacert /tmp/scanca.cer \ --form token="$COVERITY_SCAN_TOKEN" \ --form email="$COVERITY_SCAN_NOTIFICATION_EMAIL" \ --form file=@cov-int.tar.xz \ --form version="$VERSION" \ --form description="thrift master" \ https://scan.coverity.com/builds?project=thrift thrift-0.16.0/build/docker/scripts/covscan.sh000077500000000000000000000033621420101504100211160ustar00rootroot00000000000000# # Coverity Scan Travis build script # To run this interactively, set the environment variables yourself, # and run this inside a docker container. # # Command-Line Arguments # # --skipdownload to skip re-downloading the Coverity Scan build package (large) # # Environment Variables (required) # # COVERITY_SCAN_NOTIFICATION_EMAIL - email address to notify # COVERITY_SCAN_TOKEN - the Coverity Scan token (should be secure) # # Environment Variables (defaulted) # # COVERITY_SCAN_BUILD_COMMAND - defaults to "build/docker/scripts/autotools.sh" # COVERITY_SCAN_DESCRIPTION - defaults to TRAVIS_BRANCH or "master" if empty # COVERITY_SCAN_PROJECT - defaults to "thrift" set -ex COVERITY_SCAN_BUILD_COMMAND=${COVERITY_SCAN_BUILD_COMMAND:-build/docker/scripts/autotools.sh} COVERITY_SCAN_DESCRIPTION=${COVERITY_SCAN_DESCRIPTION:-${TRAVIS_BRANCH:-master}} COVERITY_SCAN_PROJECT=${COVERITY_SCAN_PROJECT:-thrift} # download the coverity scan package pushd /tmp if [[ "$1" != "--skipdownload" ]]; then rm -rf coverity_tool.tgz cov-analysis* wget https://scan.coverity.com/download/linux64 --post-data "token=$COVERITY_SCAN_TOKEN&project=$COVERITY_SCAN_PROJECT" -O coverity_tool.tgz tar xzf coverity_tool.tgz fi COVBIN=$(echo $(pwd)/cov-analysis*/bin) export PATH=$COVBIN:$PATH popd # build the project with coverity scan rm -rf cov-int/ cov-build --dir cov-int $COVERITY_SCAN_BUILD_COMMAND tar cJf cov-int.tar.xz cov-int/ curl --form token="$COVERITY_SCAN_TOKEN" \ --form email="$COVERITY_SCAN_NOTIFICATION_EMAIL" \ --form file=@cov-int.tar.xz \ --form version="$(git describe --tags)" \ --form description="$COVERITY_SCAN_DESCRIPTION" \ https://scan.coverity.com/builds?project="$COVERITY_SCAN_PROJECT" thrift-0.16.0/build/docker/scripts/cross-test.sh000077500000000000000000000005651420101504100215720ustar00rootroot00000000000000#!/bin/sh set -ev ./bootstrap.sh ./configure --enable-tutorial=no make -j3 precross set +e make cross$1 RET=$? if [ $RET -ne 0 ]; then if [ -f "test/features/log/unexpected_failures.log" ]; then cat "test/features/log/unexpected_failures.log" fi if [ -f "test/log/unexpected_failures.log" ]; then cat "test/log/unexpected_failures.log" fi fi exit $RET thrift-0.16.0/build/docker/scripts/dpkg.sh000077500000000000000000000000731420101504100204030ustar00rootroot00000000000000#!/bin/sh set -ev dpkg-buildpackage -tc -us -uc ls -al .. thrift-0.16.0/build/docker/scripts/make-dist.sh000077500000000000000000000001771420101504100213410ustar00rootroot00000000000000#!/bin/sh set -ev ./bootstrap.sh ./configure $* make dist tar xvf thrift-*.tar.gz cd thrift-* ./build/docker/scripts/cmake.sh thrift-0.16.0/build/docker/scripts/sca.sh000077500000000000000000000033141420101504100202250ustar00rootroot00000000000000#!/bin/bash set -ev # # Generate thrift files so the static code analysis includes an analysis # of the files the thrift compiler spits out. If running interactively # set the NOBUILD environment variable to skip the boot/config/make phase. # if [[ -z "$NOBUILD" ]]; then ./bootstrap.sh ./configure --enable-tutorial=no make -j3 precross fi # # C/C++ static code analysis with cppcheck # add --error-exitcode=1 to --enable=all as soon as everything is fixed # # Python code style check with flake8 # # search for TODO etc within source tree # some statistics about the code base # some info about the build machine # Compiler cppcheck (All) cppcheck --force --quiet --inline-suppr --enable=all -j2 compiler/cpp/src # C++ cppcheck (All) cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp # C Glib cppcheck (All) cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib # Silent error checks # See THRIFT-4371 : flex generated code triggers "possible null pointer dereference" in yy_init_buffer cppcheck --force --quiet --inline-suppr --suppress="*:thrift/thriftl.cc" --error-exitcode=1 -j2 compiler/cpp/src cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib # Python code style flake8 # PHP code style composer install --quiet ./vendor/bin/phpcs # TODO etc echo FIXMEs: `grep -r FIXME * | wc -l` echo HACKs: `grep -r HACK * | wc -l` echo TODOs: `grep -r TODO * | wc -l` # LoC sloccount . # System Info dpkg -l uname -a thrift-0.16.0/build/docker/scripts/ubsan.sh000077500000000000000000000017501420101504100205710ustar00rootroot00000000000000#!/bin/sh set -e # Wraps autotools.sh, but each binary crashes if it exhibits undefined behavior. # Set the undefined behavior flags. This crashes on all undefined behavior except for # undefined casting, aka "vptr". # TODO: fix undefined vptr behavior and turn this option back on. export CFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -O0 -ggdb3 -fno-omit-frame-pointer" export CXXFLAGS="${CFLAGS}" export LDFLAGS="-lubsan" export UBSAN_OPTIONS=print_stacktrace=1 # # work around https://svn.boost.org/trac10/ticket/11632 if present # sed -i 's/, stream_t(rdbuf()) /, stream_t(pbase_type::member.get())/g' /usr/include/boost/format/alt_sstream.hpp # llvm-symbolizer must be on PATH to get a stack trace on error CLANG_PATH="$(mktemp -d)" trap "rm -rf ${CLANG_PATH}" EXIT ln -s "$(whereis llvm-symbolizer-4.0 | rev | cut -d ' ' -f 1 | rev)" \ "${CLANG_PATH}/llvm-symbolizer" export PATH="${CLANG_PATH}:${PATH}" llvm-symbolizer -version build/docker/scripts/autotools.sh $* thrift-0.16.0/build/docker/ubuntu-bionic/000077500000000000000000000000001420101504100202135ustar00rootroot00000000000000thrift-0.16.0/build/docker/ubuntu-bionic/Dockerfile000066400000000000000000000220311420101504100222030ustar00rootroot00000000000000# 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. # # Apache Thrift Docker build environment for Ubuntu Bionic # with some updated packages. # FROM buildpack-deps:bionic-scm MAINTAINER Apache Thrift ENV DEBIAN_FRONTEND noninteractive ### Add apt repos RUN apt-get update && \ apt-get dist-upgrade -y && \ apt-get install -y --no-install-recommends --fix-missing \ apt \ apt-transport-https \ apt-utils \ curl \ dirmngr \ software-properties-common \ wget # Dart RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \ /etc/apt/sources.list.d/dart_stable.list # dotnet (netcore) RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \ chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \ chown root:root /etc/apt/sources.list.d/microsoft-prod.list # erlang RUN wget -O- https://packages.erlang-solutions.com/ubuntu/erlang_solutions.asc | apt-key add - && \ echo "deb https://packages.erlang-solutions.com/ubuntu bionic contrib" | tee /etc/apt/sources.list.d/erlang.list # node.js RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ echo "deb https://deb.nodesource.com/node_10.x bionic main" | tee /etc/apt/sources.list.d/nodesource.list ### install general dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ `# General dependencies` \ bash-completion \ bison \ build-essential \ clang \ cmake \ debhelper \ flex \ gdb \ libasound2 \ libatk-bridge2.0-0 \ libgtk-3-0 \ llvm \ ninja-build \ pkg-config \ unzip \ valgrind \ vim ENV PATH /usr/lib/llvm-6.0/bin:$PATH # lib/as3 (ActionScript) RUN mkdir -p /usr/local/adobe/flex/4.6 && \ cd /usr/local/adobe/flex/4.6 && \ wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \ unzip flex_sdk_4.6.zip ENV FLEX_HOME /usr/local/adobe/flex/4.6 RUN apt-get install -y --no-install-recommends \ `# C++ dependencies` \ libboost-all-dev \ libevent-dev \ libssl-dev \ qt5-default \ qtbase5-dev \ qtbase5-dev-tools ENV SBCL_VERSION 1.5.3 RUN \ `# Common Lisp (sbcl) dependencies` \ curl --version && \ curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \ tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \ cd sbcl-${SBCL_VERSION}-x86-64-linux && \ ./install.sh && \ sbcl --version && \ cd .. && \ rm -rf sbcl* ENV D_VERSION 2.087.0 ENV DMD_DEB dmd_2.087.0-0_amd64.deb RUN \ `# D dependencies` \ wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \ dpkg --install ${DMD_DEB} && \ rm -f ${DMD_DEB} && \ mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \ mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf deimos-libevent-2.0 && \ git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \ mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf deimos-openssl-1.1.0h ENV DART_VERSION 2.7.2-1 RUN apt-get install -y --no-install-recommends \ `# Dart dependencies` \ dart=$DART_VERSION ENV PATH /usr/lib/dart/bin:$PATH RUN apt-get install -y --no-install-recommends \ `# dotnet core dependencies` \ dotnet-sdk-6.0 \ dotnet-runtime-6.0 \ aspnetcore-runtime-6.0 \ dotnet-apphost-pack-6.0 RUN apt-get install -y --no-install-recommends \ `# Erlang dependencies` \ erlang && \ wget https://s3.amazonaws.com/rebar3/rebar3 -O /usr/bin/rebar3 && \ chmod 755 /usr/bin/rebar3 && \ rebar3 --version RUN apt-get install -y --no-install-recommends \ `# GlibC dependencies` \ libglib2.0-dev # golang ENV GOLANG_VERSION 1.17.6 ENV GOLANG_DOWNLOAD_URL https://go.dev/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 231654bbf2dab3d86c1619ce799e77b03d96f9b50770297c8f4dff8836fc8ca2 RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \ echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \ tar -C /usr/local -xzf golang.tar.gz && \ ln -s /usr/local/go/bin/go /usr/local/bin && \ rm golang.tar.gz RUN apt-get install -y --no-install-recommends \ `# Haxe dependencies` \ haxe \ neko \ neko-dev && \ haxelib setup --always /usr/share/haxe/lib && \ haxelib install --always hxcpp 2>&1 > /dev/null RUN apt-get install -y --no-install-recommends \ `# Java dependencies` \ ant \ ant-optional \ maven \ openjdk-11-jdk-headless RUN apt-get install -y --no-install-recommends \ `# Lua dependencies` \ lua5.2 \ lua5.2-dev # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 # lua5.3 does not install alternatives! # need to update our luasocket code, lua doesn't have luaL_openlib any more RUN apt-get install -y --no-install-recommends \ `# Node.js dependencies` \ nodejs # Test dependencies for running puppeteer RUN apt-get install -y --no-install-recommends \ `# JS dependencies` \ libxss1 \ libxtst6 RUN apt-get install -y --no-install-recommends \ `# OCaml dependencies` \ ocaml \ opam && \ opam init --yes && \ opam install --yes oasis RUN apt-get install -y --no-install-recommends \ `# Perl dependencies` \ libbit-vector-perl \ libclass-accessor-class-perl \ libcrypt-ssleay-perl \ libio-socket-ssl-perl \ libnet-ssleay-perl \ libtest-exception-perl RUN apt-get install -y --no-install-recommends \ `# Php dependencies` \ php \ php-cli \ php-dev \ php-json \ php-pear \ re2c \ composer RUN apt-get install -y --no-install-recommends \ `# Python dependencies` \ python-all \ python-all-dbg \ python-all-dev \ python-ipaddress \ python-pip \ python-setuptools \ python-six \ python-tornado \ python-twisted \ python-wheel \ python-zope.interface && \ pip install --upgrade backports.ssl_match_hostname RUN apt-get install -y --no-install-recommends \ `# Python3 dependencies` \ python3-all \ python3-all-dbg \ python3-all-dev \ python3-pip \ python3-setuptools \ python3-six \ python3-tornado \ python3-twisted \ python3-wheel \ python3-zope.interface RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ ruby \ ruby-dev \ ruby-bundler # Rust dependencies RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y ENV PATH /root/.cargo/bin:$PATH # Swift on Linux for cross tests RUN cd / && \ wget --quiet https://swift.org/builds/swift-5.1.4-release/ubuntu1804/swift-5.1.4-RELEASE/swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \ tar xf swift-5.1.4-RELEASE-ubuntu18.04.tar.gz --strip-components=1 && \ rm swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \ swift --version # Locale(s) for cpp unit tests RUN apt-get install -y --no-install-recommends \ `# Locale dependencies` \ locales && \ locale-gen en_US.UTF-8 && \ locale-gen de_DE.UTF-8 && \ update-locale # cppcheck-1.82 has a nasty cpp parser bug, so we're using something newer RUN apt-get install -y --no-install-recommends \ `# Static Code Analysis dependencies` \ cppcheck \ sloccount && \ pip install flake8 && \ wget -q "https://launchpad.net/ubuntu/+source/cppcheck/1.83-2/+build/14874703/+files/cppcheck_1.83-2_amd64.deb" && \ dpkg -i cppcheck_1.83-2_amd64.deb && \ rm cppcheck_1.83-2_amd64.deb # Clean up RUN rm -rf /var/cache/apt/* && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /var/tmp/* ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/docker/ubuntu-disco/000077500000000000000000000000001420101504100200515ustar00rootroot00000000000000thrift-0.16.0/build/docker/ubuntu-disco/Dockerfile000066400000000000000000000222131420101504100220430ustar00rootroot00000000000000# 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. # # Apache Thrift Docker build environment for Ubuntu Disco # with some updated packages. # FROM buildpack-deps:disco-scm MAINTAINER Apache Thrift ENV DEBIAN_FRONTEND noninteractive ### Add apt repos RUN apt-get update && \ apt-get dist-upgrade -y && \ apt-get install -y --no-install-recommends \ apt \ apt-transport-https \ apt-utils \ curl \ dirmngr \ software-properties-common \ wget # Dart RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \ /etc/apt/sources.list.d/dart_stable.list # dotnet (netcore) RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \ chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \ chown root:root /etc/apt/sources.list.d/microsoft-prod.list # erlang RUN wget -O- https://packages.erlang-solutions.com/ubuntu/erlang_solutions.asc | apt-key add - && \ echo "deb https://packages.erlang-solutions.com/ubuntu disco contrib" | tee /etc/apt/sources.list.d/erlang.list # node.js RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ echo "deb https://deb.nodesource.com/node_10.x disco main" | tee /etc/apt/sources.list.d/nodesource.list ### install general dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ `# General dependencies` \ bash-completion \ bison \ build-essential \ clang \ cmake \ debhelper \ flex \ gdb \ libasound2 \ libatk-bridge2.0-0 \ libgtk-3-0 \ llvm \ ninja-build \ pkg-config \ unzip \ valgrind \ vim ENV PATH /usr/lib/llvm-6.0/bin:$PATH # lib/as3 (ActionScript) RUN mkdir -p /usr/local/adobe/flex/4.6 && \ cd /usr/local/adobe/flex/4.6 && \ wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \ unzip flex_sdk_4.6.zip ENV FLEX_HOME /usr/local/adobe/flex/4.6 RUN apt-get install -y --no-install-recommends \ `# C++ dependencies` \ libboost-all-dev \ libevent-dev \ libssl-dev \ qt5-default \ qtbase5-dev \ qtbase5-dev-tools ENV SBCL_VERSION 1.5.3 RUN \ `# Common Lisp (sbcl) dependencies` \ curl --version && \ curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \ tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \ cd sbcl-${SBCL_VERSION}-x86-64-linux && \ ./install.sh && \ sbcl --version && \ cd .. && \ rm -rf sbcl* ENV D_VERSION 2.087.0 ENV DMD_DEB dmd_2.087.0-0_amd64.deb RUN \ `# D dependencies` \ wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \ dpkg --install ${DMD_DEB} && \ rm -f ${DMD_DEB} && \ mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \ mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf deimos-libevent-2.0 && \ git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \ mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf deimos-openssl-1.1.0h ENV DART_VERSION 2.7.2-1 RUN apt-get install -y --no-install-recommends \ `# Dart dependencies` \ dart=$DART_VERSION ENV PATH /usr/lib/dart/bin:$PATH RUN apt-get install -y --no-install-recommends \ `# dotnet core dependencies` \ dotnet-sdk-6.0 \ dotnet-runtime-6.0 \ aspnetcore-runtime-6.0 \ dotnet-apphost-pack-6.0 RUN apt-get install -y --no-install-recommends \ `# Erlang dependencies` \ erlang && \ wget https://s3.amazonaws.com/rebar3/rebar3 -O /usr/bin/rebar3 && \ chmod 755 /usr/bin/rebar3 && \ rebar3 --version RUN apt-get install -y --no-install-recommends \ `# GlibC dependencies` \ libglib2.0-dev # golang ENV GOLANG_VERSION 1.17.6 ENV GOLANG_DOWNLOAD_URL https://go.dev/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 231654bbf2dab3d86c1619ce799e77b03d96f9b50770297c8f4dff8836fc8ca2 RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \ echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \ tar -C /usr/local -xzf golang.tar.gz && \ ln -s /usr/local/go/bin/go /usr/local/bin && \ rm golang.tar.gz RUN apt-get install -y --no-install-recommends \ `# Haxe dependencies` \ haxe \ neko \ neko-dev && \ haxelib setup --always /usr/share/haxe/lib && \ haxelib install --always hxcpp 2>&1 > /dev/null RUN apt-get install -y --no-install-recommends \ `# Java dependencies` \ ant \ ant-optional \ maven \ openjdk-11-jdk-headless RUN apt-get install -y --no-install-recommends \ `# Lua dependencies` \ lua5.2 \ lua5.2-dev # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 # lua5.3 does not install alternatives! # need to update our luasocket code, lua doesn't have luaL_openlib any more RUN apt-get install -y --no-install-recommends \ `# Node.js dependencies` \ nodejs # Test dependencies for running puppeteer RUN apt-get install -y --no-install-recommends \ `# JS dependencies` \ libxss1 \ libxtst6 # does not work on disco? # RUN apt-get install -y --no-install-recommends \ # `# OCaml dependencies` \ # ocaml \ # opam && \ # opam init --yes && \ # opam install --yes oasis RUN apt-get install -y --no-install-recommends \ `# Perl dependencies` \ libbit-vector-perl \ libclass-accessor-class-perl \ libcrypt-ssleay-perl \ libio-socket-ssl-perl \ libnet-ssleay-perl \ libtest-exception-perl RUN apt-get install -y --no-install-recommends \ `# Php dependencies` \ php \ php-cli \ php-dev \ php-json \ php-pear \ re2c \ composer RUN apt-get install -y --no-install-recommends \ `# Python dependencies` \ python-all \ python-all-dbg \ python-all-dev \ python-ipaddress \ python-pip \ python-setuptools \ python-six \ python-tornado \ python-twisted \ python-wheel \ python-zope.interface && \ pip install --upgrade backports.ssl_match_hostname RUN apt-get install -y --no-install-recommends \ `# Python3 dependencies` \ python3-all \ python3-all-dbg \ python3-all-dev \ python3-pip \ python3-setuptools \ python3-six \ python3-tornado \ python3-twisted \ python3-wheel \ python3-zope.interface RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ ruby \ ruby-dev \ ruby-bundler # Rust dependencies RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y ENV PATH /root/.cargo/bin:$PATH # Swift on Linux for cross tests # does not work on disco # RUN cd / && \ # wget --quiet https://swift.org/builds/swift-4.2.1-release/ubuntu1804/swift-4.2.1-RELEASE/swift-4.2.1-RELEASE-ubuntu18.04.tar.gz && \ # tar xf swift-4.2.1-RELEASE-ubuntu18.04.tar.gz --strip-components=1 && \ # rm swift-4.2.1-RELEASE-ubuntu18.04.tar.gz && \ # swift --version # Locale(s) for cpp unit tests RUN apt-get install -y --no-install-recommends \ `# Locale dependencies` \ locales && \ locale-gen en_US.UTF-8 && \ locale-gen de_DE.UTF-8 && \ update-locale # cppcheck-1.82 has a nasty cpp parser bug, so we're using something newer # don't need this on disco, nobody uses it # RUN apt-get install -y --no-install-recommends \ # `# Static Code Analysis dependencies` \ # cppcheck \ # sloccount && \ # pip install flake8 && \ # wget -q "https://launchpad.net/ubuntu/+source/cppcheck/1.83-2/+build/14874703/+files/cppcheck_1.83-2_amd64.deb" && \ # dpkg -i cppcheck_1.83-2_amd64.deb && \ # rm cppcheck_1.83-2_amd64.deb # Clean up RUN rm -rf /var/cache/apt/* && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /var/tmp/* ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/docker/ubuntu-xenial/000077500000000000000000000000001420101504100202305ustar00rootroot00000000000000thrift-0.16.0/build/docker/ubuntu-xenial/Dockerfile000066400000000000000000000176171420101504100222360ustar00rootroot00000000000000# 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. # # Apache Thrift Docker build environment for Ubuntu Xenial # Using all stock Ubuntu Xenial packaging except for: # - d: does not come with Ubuntu so we're installing 2.087.0 for coverage # - dart: does not come with Ubuntu so we're installing 2.0.0-1 for coverage # - dotnet: does not come with Ubuntu # - go: Xenial comes with 1.6, but we need 1.10 or later # - nodejs: Xenial comes with 4.2.6 which exits LTS April 2018, so we're installing 10.x # - ocaml: causes stack overflow error, just started March 2018 not sure why # FROM buildpack-deps:xenial-scm MAINTAINER Apache Thrift ENV DEBIAN_FRONTEND noninteractive ### Add apt repos RUN apt-get update && \ apt-get dist-upgrade -y && \ apt-get install -y --no-install-recommends \ apt \ apt-transport-https \ apt-utils \ curl \ software-properties-common \ wget && \ # Dart curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \ /etc/apt/sources.list.d/dart_stable.list && \ # dotnet (core) curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > \ /etc/apt/sources.list.d/dotnetdev.list && \ # node.js curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ echo "deb https://deb.nodesource.com/node_10.x xenial main" | tee /etc/apt/sources.list.d/nodesource.list && \ # ruby 2.4 apt-add-repository ppa:brightbox/ruby-ng ### install general dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ `# General dependencies` \ bash-completion \ bison \ build-essential \ clang \ cmake \ debhelper \ flex \ gdb \ llvm \ ninja-build \ pkg-config \ valgrind \ vim ENV PATH /usr/lib/llvm-3.8/bin:$PATH ### languages RUN apt-get install -y --no-install-recommends \ `# C++ dependencies` \ libboost-dev \ libboost-filesystem-dev \ libboost-program-options-dev \ libboost-system-dev \ libboost-test-dev \ libboost-thread-dev \ libevent-dev \ libssl-dev \ qt5-default \ qtbase5-dev \ qtbase5-dev-tools ENV D_VERSION 2.087.0 ENV DMD_DEB dmd_2.087.0-0_amd64.deb RUN \ `# D dependencies` \ wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \ dpkg --install ${DMD_DEB} && \ rm -f ${DMD_DEB} && \ mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \ git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \ mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf deimos-libevent-2.0 && \ git clone -b 'v1.1.6+1.0.1g' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.0.1g && \ mv deimos-openssl-1.0.1g/deimos/* /usr/include/dmd/druntime/import/deimos/ && \ mv deimos-openssl-1.0.1g/C/* /usr/include/dmd/druntime/import/C/ && \ rm -rf deimos-openssl-1.0.1g ENV DART_VERSION 2.7.2-1 RUN apt-get install -y --no-install-recommends \ `# Dart dependencies` \ dart=$DART_VERSION ENV PATH /usr/lib/dart/bin:$PATH RUN apt-get install -y --no-install-recommends \ `# dotnet core dependencies` \ dotnet-sdk-6.0 \ dotnet-runtime-6.0 \ aspnetcore-runtime-6.0 \ dotnet-apphost-pack-6.0 RUN apt-get install -y --no-install-recommends \ `# Erlang dependencies` \ erlang-base \ erlang-eunit \ erlang-dev \ erlang-tools \ rebar RUN apt-get install -y --no-install-recommends \ `# GlibC dependencies` \ libglib2.0-dev # golang ENV GOLANG_VERSION 1.16.13 ENV GOLANG_DOWNLOAD_URL https://go.dev/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 275fc03c90c13b0bbff13125a43f1f7a9f9c00a0d5a9f2d5b16dbc2fa2c6e12a RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \ echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \ tar -C /usr/local -xzf golang.tar.gz && \ ln -s /usr/local/go/bin/go /usr/local/bin && \ rm golang.tar.gz RUN apt-get install -y --no-install-recommends \ `# Haxe dependencies` \ haxe \ neko \ neko-dev \ libneko0 && \ haxelib setup --always /usr/share/haxe/lib && \ haxelib install --always hxcpp 3.4.64 2>&1 > /dev/null # note: hxcpp 3.4.185 (latest) no longer ships static libraries, and caused a build failure RUN apt-get install -y --no-install-recommends \ `# Java dependencies` \ ant \ ant-optional \ openjdk-8-jdk \ maven # disabled: same as ubuntu-bionic jobs # RUN apt-get install -y --no-install-recommends \ # `# Lua dependencies` \ # lua5.2 \ # lua5.2-dev # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 # lua5.3 does not install alternatives so stick with 5.2 here RUN apt-get install -y --no-install-recommends \ `# Node.js dependencies` \ nodejs # Test dependencies for running puppeteer RUN apt-get install -y --no-install-recommends \ `# JS dependencies` \ libxss1 \ libxtst6 \ libatk-bridge2.0-0 \ libgtk-3-0 # THRIFT-4517: causes stack overflows; version too old; skip ocaml in xenial # RUN apt-get install -y --no-install-recommends \ # `# OCaml dependencies` \ # ocaml \ # opam && \ # opam init --yes && \ # opam install --yes oasis RUN apt-get install -y --no-install-recommends \ `# Perl dependencies` \ libbit-vector-perl \ libclass-accessor-class-perl \ libcrypt-ssleay-perl \ libio-socket-ssl-perl \ libnet-ssleay-perl \ libtest-exception-perl RUN apt-get install -y --no-install-recommends \ `# Php dependencies` \ php7.0 \ php7.0-cli \ php7.0-dev \ php-json \ php-pear \ re2c \ composer RUN apt-get install -y --no-install-recommends \ `# Python dependencies` \ python-all \ python-all-dbg \ python-all-dev \ python-backports.ssl-match-hostname \ python-ipaddress \ python-pip \ python-setuptools \ python-six \ python-tornado \ python-twisted \ python-wheel \ python-zope.interface \ python3-all \ python3-all-dbg \ python3-all-dev \ python3-setuptools \ python3-six \ python3-tornado \ python3-twisted \ python3-wheel \ python3-zope.interface && \ pip install --upgrade backports.ssl_match_hostname RUN apt-get install -y --no-install-recommends \ `# Ruby dependencies` \ ruby2.4 \ ruby2.4-dev \ ruby-bundler # Rust dependencies RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y # Locale(s) for cpp unit tests RUN apt-get install -y --no-install-recommends \ `# Locale dependencies` \ locales && \ locale-gen en_US.UTF-8 && \ locale-gen de_DE.UTF-8 && \ update-locale # Clean up RUN rm -rf /var/cache/apt/* && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /var/tmp/* ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 ENV THRIFT_ROOT /thrift RUN mkdir -p $THRIFT_ROOT/src COPY Dockerfile $THRIFT_ROOT/ WORKDIR $THRIFT_ROOT/src thrift-0.16.0/build/fixchanges.sh000077500000000000000000000030321420101504100166350ustar00rootroot00000000000000#!/usr/bin/env bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # fixchanges will take a file as input and look for text matching # the pattern [THRIFT-nnnn] (the number of digits is not important) # which is not a markdown link, and change it to be a markdown link. # The tool writes to stdout so you can redirect it to a temporary # file and then compare against the original file before replacing # it. # # This tool was developed after the 0.12.0 release to assist with # generation of CHANGES.md content. # while IFS='' read -r line || [[ -n "$line" ]]; do if [[ "$line" =~ ^(.*)\[(THRIFT-[[:digit:]]+)\][^\(](.*)$ ]]; then echo "${BASH_REMATCH[1]}[${BASH_REMATCH[2]}](https://issues.apache.org/jira/browse/${BASH_REMATCH[2]}) ${BASH_REMATCH[3]}" else echo "$line" fi done < "$1" thrift-0.16.0/build/veralign.sh000077500000000000000000000243371420101504100163400ustar00rootroot00000000000000x#!/usr/bin/env bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # The veralign script sets the appropriate versions in all of # the package configuration files for all of the supported # languages. It is used to prepare a release or move master # forward to the next anticipated version. # # USAGE # ----------------------------------------------------------- # usage: veralign.sh # # EXAMPLE # ----------------------------------------------------------- # $ ./veralign.sh 0.12.0 1.0.0 # $ ./veralign.sh 1.0.0 1.1.0 # # IMPORTANT USAGE NOTE # ----------------------------------------------------------- # Define the environment variable DRYRUN to have the script # print out all matches to the oldVersion hilighted so that # you can verify it will change the right things. # declare -A FILES # These files require a manual touch: FILES[CHANGES.md]=manual FILES[debian/changelog]=manual FILES[doap.rdf]=manual # These files can be updated automatically: FILES[ApacheThrift.nuspec]=simpleReplace FILES[appveyor.yml]=simpleReplace FILES[bower.json]=jsonReplace FILES[CMakeLists.txt]=simpleReplace FILES[compiler/cpp/src/thrift/version.h]=simpleReplace FILES[configure.ac]=configureReplace FILES[contrib/Rebus/Properties/AssemblyInfo.cs]=simpleReplace FILES[contrib/thrift.spec]=simpleReplace FILES[contrib/zeromq/csharp/AssemblyInfo.cs]=simpleReplace FILES[contrib/thrift-maven-plugin/pom.xml]=pomReplace FILES[doc/specs/idl.md]=simpleReplace FILES[lib/d/src/thrift/base.d]=simpleReplace FILES[lib/dart/pubspec.yaml]=pubspecReplace FILES[lib/delphi/src/Thrift.pas]=simpleReplace FILES[lib/erl/src/thrift.app.src]=simpleReplace FILES[lib/haxe/haxelib.json]=simpleReplace FILES[lib/java/gradle.properties]=simpleReplace FILES[lib/js/package-lock.json]=jsonReplace FILES[lib/js/package.json]=jsonReplace FILES[lib/js/src/thrift.js]=simpleReplace FILES[lib/lua/Thrift.lua]=simpleReplace FILES[lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj]=simpleReplace FILES[lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj]=simpleReplace FILES[lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj]=simpleReplace FILES[lib/netstd/Thrift/Properties/AssemblyInfo.cs]=simpleReplace FILES[lib/netstd/Thrift/Thrift.csproj]=simpleReplace FILES[lib/ocaml/_oasis]=simpleReplace FILES[lib/perl/lib/Thrift.pm]=simpleReplace FILES[lib/py/setup.py]=simpleReplace FILES[lib/rb/thrift.gemspec]=simpleReplace FILES[lib/rs/Cargo.toml]=simpleReplace FILES[lib/st/package.xml]=simpleReplace FILES[lib/swift/Sources/Thrift.swift]=simpleReplace FILES[lib/swift/Tests/ThriftTests/ThriftTests.swift]=simpleReplace FILES[lib/ts/package-lock.json]=jsonReplace FILES[lib/ts/package.json]=jsonReplace FILES[package-lock.json]=jsonReplace FILES[package.json]=jsonReplace FILES[sonar-project.properties]=simpleReplace FILES[test/dart/test_client/pubspec.yaml]=pubspecReplace FILES[test/erl/src/thrift_test.app.src]=simpleReplace FILES[test/netstd/Client/Client.csproj]=simpleReplace FILES[test/netstd/Server/Server.csproj]=simpleReplace FILES[Thrift.podspec]=simpleReplace FILES[tutorial/dart/client/pubspec.yaml]=pubspecReplace FILES[tutorial/dart/console_client/pubspec.yaml]=pubspecReplace FILES[tutorial/dart/server/pubspec.yaml]=pubspecReplace FILES[tutorial/delphi/DelphiClient/DelphiClient.dproj]=simpleReplace FILES[tutorial/delphi/DelphiServer/DelphiServer.dproj]=simpleReplace FILES[tutorial/netstd/Client/Client.csproj]=simpleReplace FILES[tutorial/netstd/Interfaces/Interfaces.csproj]=simpleReplace FILES[tutorial/netstd/Server/Server.csproj]=simpleReplace FILES[tutorial/ocaml/_oasis]=simpleReplace if [ ! -f "CHANGES.md" ]; then >&2 echo "error: run veralign.sh while in the thrift root directory" exit 1 fi if [ $# -ne 2 ]; then >&2 echo "usage: veralign.sh " exit 1 fi jq --version 1>/dev/null 2>/dev/null if [ $? -ne 0 ]; then >&2 echo "error: the 'jq' package is not installed" exit 1 fi # # validateVersion: check that a version matches the major.minor.patch # format which is the lowest common denominator supported by all # project systems. # \param $1 the version # \returns 0 if the version is compliant # function validateVersion { local result local valid valid=$(echo "$1" | sed '/^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+$/!{q22}') result=$? if [ $result -eq 22 ]; then >&2 echo "error: version '$1' does not conform to the required major.minor.patch format" return ${result} fi } OLDVERSION=$1 NEWVERSION=$2 validateVersion "${OLDVERSION}" || exit $? validateVersion "${NEWVERSION}" || exit $? # # escapeVersion: escape the version for use as a sed search # \param $1 the version to escape # \output the escaped string # \returns 0 # \example VERSEARCH=$(escapeVersion "[1.0.0]"); echo $VERSEARCH; => "\[1\.0\.0\]" # function escapeVersion { echo "$(echo "$1" | sed 's/\./\\./g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g')" } # Set up verbose hilighting if running interactive if [ "$(tput colors)" -ne 0 ]; then reverse=$(tput rev) red=$(tput setaf 1) green=$(tput setaf 2) yellow=$(tput setaf 3) normal=$(tput sgr0) fi declare -A MANUAL # # manual: note that update of said file is manual # \param $1 filename to do replacements on # \returns 0 # function manual { MANUAL["$1"]="" return 0 } # # configureReplace: replace the AC_INIT field in configure.ac # \param $1 filename to do replacements on # \returns 0 on success # function configureReplace { replace "$1" "[thrift], [${OLDVERSION}]" "[thrift], [${NEWVERSION}]" } # # jsonReplace: replace a specific version field in a JSON file # must be a top level "version" field in the json structure # \param $1 filename to do replacements on # \returns 0 on success # function jsonReplace { local result local output if [ ! -z "$DRYRUN" ]; then output=$(jq -e ".version" "$1") else output=$(jq -e ".version = \"${NEWVERSION}\"" "$1" > tmp.$$.json && mv tmp.$$.json "$1") fi result=$? if [ $? -ne 0 ]; then printf "%-60s | %5d | ${red}ERROR${normal}: version tag not found" "$1" "$count" echo return 1 elif [ ! -z "$DRYRUN" ]; then output=${output%\"} output=${output#\"} printf "%-60s | %5d | MATCHES: version: \"${reverse}${green}${output}${normal}\"" "$1" 1 echo return 0 fi printf "%-60s | %5d | ${green}OK${normal}" "$1" 1 echo return 0 } # # pubspecReplace: replace a specific version field in a YAML file # must be a top level "version" field in the yaml structure # did not find a package that preserves comments so this is # somewhat brain-dead, but it gets the job done # \param $1 filename to do replacements on # \returns 0 on success # function pubspecReplace { replace "$1" "version: ${OLDVERSION}" "version: ${NEWVERSION}" } # # pomReplace: replace a specific version field in a maven pom file # must be a top level "version" field in the xml structure # \param $1 filename to do replacements on # \returns 0 on success # function pomReplace { replace "$1" "^ ${OLDVERSION}<\/version>" " ${NEWVERSION}<\/version>" } # # replace: replace occurrences of one string with another # the file specified must contain the old string at least once # in order to be successful. # \param $1 filename to do replacements on # \param $2 the "old" string to be replaced # \param $3 the "new" striing to replace it with # \returns 0 on success # function replace { local result local output local oldString="$2" local newString="$3" local oldRegex=$(escapeVersion "${oldString}") local count=$(grep -Ec "${oldRegex}" "$1") local verbose if [ $count -eq 0 ]; then printf "%-60s | %5d | ${red}NOT FOUND${normal}: ${oldString}" "$1" 0 echo return 1 elif [ ! -z "$DRYRUN" ]; then printf "%-60s | %5d | MATCHES:" "$1" "$count" echo while read -r line; do echo " > $(echo "$line" | sed "s/${oldRegex}/${reverse}${green}${oldString}${normal}/g")" done < <(grep -E "${oldRegex}" "$1") return 0 fi output=$(sed -i "s/${oldRegex}/${newString}/g" "$1") result=$? if [ $result -ne 0 ]; then printf "%-60s | %5d | ${red}ERROR${normal}: %s" "$1" "$count" "$output" echo return 1 fi printf "%-60s | %5d | ${green}OK${normal}" "$1" "$count" echo return 0 } # # simpleReplace: replace occurrences of ${OLDVERSION} with ${NEWVERSION} # the file specified must contain OLDVERSION at least once # in order to be successful. # \param $1 filename to do replacements on # \param $2 the "old" string to be replaced # \param $3 the "new" striing to replace it with # \returns 0 on success # function simpleReplace { replace "$1" "${OLDVERSION}" "${NEWVERSION}" } echo "" echo "Apache Thrift Version Alignment Tool" echo "------------------------------------" echo "" echo "Previous Version: ${OLDVERSION}" echo " New Version: ${NEWVERSION}" echo "" echo "-------------------------------------------------------------+-------+----------------------" echo "Filename | Count | Status " echo "-------------------------------------------------------------+-------+----------------------" for file in $(echo "${!FILES[@]}" | sort); do ${FILES[$file]} $file || exit $? done echo echo "Files that must be modified manually:" echo for manu in $(echo "${!MANUAL[@]}" | sort); do echo " > ${yellow}${manu}${normal}" done exit 0 thrift-0.16.0/compiler/000077500000000000000000000000001420101504100146745ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/000077500000000000000000000000001420101504100154565ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/CMakeLists.txt000066400000000000000000000123371420101504100202240ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # cmake_minimum_required(VERSION 3.3) project("thrift-compiler" VERSION ${PACKAGE_VERSION}) # version.h now handled via veralign.sh #configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h) find_package(FLEX REQUIRED) find_package(BISON REQUIRED) # create directory for thrifty and thriftl file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/) # Create flex and bison files and build the lib parse static library BISON_TARGET(thrifty ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/thrifty.yy ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc) FLEX_TARGET(thriftl ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/thriftl.ll ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc) ADD_FLEX_BISON_DEPENDENCY(thriftl thrifty) set(parse_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.hh ) add_library(parse STATIC ${parse_SOURCES}) # Create the thrift compiler set(compiler_core src/thrift/common.cc src/thrift/generate/t_generator.cc src/thrift/parse/t_typedef.cc src/thrift/parse/parse.cc src/thrift/version.h ) set(thrift-compiler_SOURCES src/thrift/main.cc src/thrift/audit/t_audit.cpp ) set(thrift_compiler_LANGS ) # This macro adds an option THRIFT_COMPILER_${NAME} # that allows enabling or disabling certain languages macro(THRIFT_ADD_COMPILER name description initial) string(TOUPPER "THRIFT_COMPILER_${name}" enabler) set(src "src/thrift/generate/t_${name}_generator.cc") option(${enabler} ${description} ${initial}) if(${enabler}) list(APPEND thrift-compiler_SOURCES ${src}) list(APPEND thrift_compiler_LANGS ${name}) endif() endmacro() # The following compiler can be enabled or disabled THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" ON) THRIFT_ADD_COMPILER(cl "Enable compiler for Common LISP" ON) THRIFT_ADD_COMPILER(cpp "Enable compiler for C++" ON) THRIFT_ADD_COMPILER(d "Enable compiler for D" ON) THRIFT_ADD_COMPILER(dart "Enable compiler for Dart" ON) THRIFT_ADD_COMPILER(delphi "Enable compiler for Delphi" ON) THRIFT_ADD_COMPILER(erl "Enable compiler for Erlang" ON) THRIFT_ADD_COMPILER(go "Enable compiler for Go" ON) THRIFT_ADD_COMPILER(gv "Enable compiler for GraphViz" ON) THRIFT_ADD_COMPILER(haxe "Enable compiler for Haxe" ON) THRIFT_ADD_COMPILER(html "Enable compiler for HTML Documentation" ON) THRIFT_ADD_COMPILER(markdown "Enable compiler for Markdown Documentation" ON) THRIFT_ADD_COMPILER(java "Enable compiler for Java" ON) THRIFT_ADD_COMPILER(javame "Enable compiler for Java ME" ON) THRIFT_ADD_COMPILER(js "Enable compiler for JavaScript" ON) THRIFT_ADD_COMPILER(json "Enable compiler for JSON" ON) THRIFT_ADD_COMPILER(lua "Enable compiler for Lua" ON) THRIFT_ADD_COMPILER(netstd "Enable compiler for .NET Standard" ON) THRIFT_ADD_COMPILER(ocaml "Enable compiler for OCaml" ON) THRIFT_ADD_COMPILER(perl "Enable compiler for Perl" ON) THRIFT_ADD_COMPILER(php "Enable compiler for PHP" ON) THRIFT_ADD_COMPILER(py "Enable compiler for Python 2.0" ON) THRIFT_ADD_COMPILER(rb "Enable compiler for Ruby" ON) THRIFT_ADD_COMPILER(rs "Enable compiler for Rust" ON) THRIFT_ADD_COMPILER(st "Enable compiler for Smalltalk" ON) THRIFT_ADD_COMPILER(swift "Enable compiler for Cocoa Swift" ON) THRIFT_ADD_COMPILER(xml "Enable compiler for XML" ON) THRIFT_ADD_COMPILER(xsd "Enable compiler for XSD" ON) # Thrift is looking for include files in the src directory # we also add the current binary directory for generated files include_directories(${CMAKE_CURRENT_BINARY_DIR} src) list(APPEND thrift-compiler_SOURCES ${compiler_core}) add_executable(thrift-compiler ${thrift-compiler_SOURCES}) set_target_properties(thrift-compiler PROPERTIES RUNTIME_OUTPUT_DIRECTORY bin/) set_target_properties(thrift-compiler PROPERTIES OUTPUT_NAME thrift) target_link_libraries(thrift-compiler parse) add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/thrift${CMAKE_EXECUTABLE_SUFFIX}" DEPENDS thrift-compiler COMMAND ${CMAKE_COMMAND} -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/" COMMENT "Copying the thrift compiler to the source tree for use by downstream targets") add_custom_target(copy-thrift-compiler DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/thrift${CMAKE_EXECUTABLE_SUFFIX}") install(TARGETS thrift-compiler DESTINATION bin) if(BUILD_TESTING) add_subdirectory(test) endif() thrift-0.16.0/compiler/cpp/Makefile.am000066400000000000000000000116511420101504100175160ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # Contains some contributions under the Thrift Software License. # Please see doc/old-thrift-license.txt in the Thrift distribution for # details. AUTOMAKE_OPTIONS = subdir-objects nostdinc SUBDIRS = src . if WITH_TESTS SUBDIRS += test endif bin_PROGRAMS = thrift thrift_OBJDIR = obj thrift_SOURCES = src/thrift/audit/t_audit.cpp \ src/thrift/audit/t_audit.h \ src/thrift/common.cc \ src/thrift/common.h \ src/thrift/generate/t_generator.cc \ src/thrift/generate/t_generator.h \ src/thrift/generate/t_generator_registry.h \ src/thrift/generate/t_html_generator.h \ src/thrift/generate/t_oop_generator.h \ src/thrift/globals.h \ src/thrift/logging.h \ src/thrift/main.cc \ src/thrift/main.h \ src/thrift/version.h \ src/thrift/parse/parse.cc \ src/thrift/parse/t_base_type.h \ src/thrift/parse/t_const.h \ src/thrift/parse/t_const_value.h \ src/thrift/parse/t_container.h \ src/thrift/parse/t_doc.h \ src/thrift/parse/t_enum.h \ src/thrift/parse/t_enum_value.h \ src/thrift/parse/t_field.h \ src/thrift/parse/t_function.h \ src/thrift/parse/t_list.h \ src/thrift/parse/t_map.h \ src/thrift/parse/t_program.h \ src/thrift/parse/t_scope.h \ src/thrift/parse/t_service.h \ src/thrift/parse/t_set.h \ src/thrift/parse/t_struct.h \ src/thrift/parse/t_type.h \ src/thrift/parse/t_typedef.cc \ src/thrift/parse/t_typedef.h \ src/thrift/platform.h # Specific client generator source thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \ src/thrift/generate/t_cl_generator.cc \ src/thrift/generate/t_cpp_generator.cc \ src/thrift/generate/t_d_generator.cc \ src/thrift/generate/t_dart_generator.cc \ src/thrift/generate/t_delphi_generator.cc \ src/thrift/generate/t_erl_generator.cc \ src/thrift/generate/t_go_generator.cc \ src/thrift/generate/t_gv_generator.cc \ src/thrift/generate/t_haxe_generator.cc \ src/thrift/generate/t_html_generator.cc \ src/thrift/generate/t_markdown_generator.cc \ src/thrift/generate/t_java_generator.cc \ src/thrift/generate/t_javame_generator.cc \ src/thrift/generate/t_js_generator.cc \ src/thrift/generate/t_json_generator.cc \ src/thrift/generate/t_lua_generator.cc \ src/thrift/generate/t_netstd_generator.cc \ src/thrift/generate/t_netstd_generator.h \ src/thrift/generate/t_ocaml_generator.cc \ src/thrift/generate/t_perl_generator.cc \ src/thrift/generate/t_php_generator.cc \ src/thrift/generate/t_py_generator.cc \ src/thrift/generate/t_rb_generator.cc \ src/thrift/generate/t_rs_generator.cc \ src/thrift/generate/t_st_generator.cc \ src/thrift/generate/t_swift_generator.cc \ src/thrift/generate/t_xml_generator.cc \ src/thrift/generate/t_xsd_generator.cc thrift_CPPFLAGS = -I$(srcdir)/src thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror thrift_LDADD = @LEXLIB@ src/thrift/libparse.a WINDOWS_DIST = \ compiler.sln \ compiler.vcxproj \ compiler.vcxproj.filters EXTRA_DIST = \ coding_standards.md \ README.md \ CMakeLists.txt \ test \ tests \ $(WINDOWS_DIST) #clean-local: # $(RM) version.h -- do not delete, we need it src/thrift/main.cc: src/thrift/version.h style-local: $(CPPSTYLE_CMD) thrift-0.16.0/compiler/cpp/README.md000066400000000000000000000123721420101504100167420ustar00rootroot00000000000000# Build Thrift IDL compiler using CMake - [Build Thrift IDL compiler using CMake](#build-thrift-idl-compiler-using-cmake) - [Build on Unix-like System](#build-on-unix-like-system) - [Prerequisites](#prerequisites) - [Build using CMake](#build-using-cmake) - [Build with Eclipse IDE](#build-with-eclipse-ide) - [Build with XCode IDE in MacOS](#build-with-xcode-ide-in-macos) - [Usage of other IDEs](#usage-of-other-ides) - [Build on Windows](#build-on-windows) - [Prerequisites](#prerequisites-1) - [Build using Git Bash](#build-using-git-bash) - [Using Visual Studio and Win flex-bison](#using-visual-studio-and-win-flex-bison) - [Cross compile using mingw32 and generate a Windows Installer with CPack](#cross-compile-using-mingw32-and-generate-a-windows-installer-with-cpack) - [Other cases](#other-cases) - [Building the Thrift IDL compiler in Windows without CMake](#building-the-thrift-idl-compiler-in-windows-without-cmake) - [Unit tests for compiler](#unit-tests-for-compiler) - [Using boost test](#using-boost-test) - [Using Catch C++ test library](#using-catch-c-test-library) - [Have a Happy free time and holidays](#have-a-happy-free-time-and-holidays) ## Build on Unix-like System ### Prerequisites - Install CMake - Install flex and bison ### Build using CMake - Go to **thrift\compiler\cpp** - Use the following steps to build using cmake: ``` mkdir cmake-build && cd cmake-build cmake .. make ``` #### Build with Eclipse IDE - Go to **thrift\compiler\cpp** - Use the following steps to build using cmake: ``` mkdir cmake-ec && cd cmake-ec cmake -G "Eclipse CDT4 - Unix Makefiles" .. make ``` Now open the folder cmake-ec using eclipse. #### Build with XCode IDE in MacOS - Install/update flex, bison and cmake with brew ``` brew install flex brew install bison brew install cmake ``` - Go to **thrift\compiler\cpp** - Run commands in command line: ``` mkdir cmake-build && cd cmake-build cmake -G "Xcode" .. cmake --build . ``` #### Usage of other IDEs Please check list of supported IDE ``` cmake --help ``` ## Build on Windows ### Prerequisites - Install CMake - https://cmake.org/download/ - In case if you want to build without Git Bash - install winflexbison - https://sourceforge.net/projects/winflexbison/ - In case if you want to build with Visual Studio - install Visual Studio - Better to use the latest stable Visual Studio Community Edition - https://www.visualstudio.com/vs/whatsnew/ (ensure that you installed workload "Desktop Development with C++" for VS2017) - Microsoft added some support for CMake and improving it in Visual Studio ### Build using Git Bash Git Bash provides flex and bison - Go to **thrift\compiler\cpp** - Use the following steps to build using cmake: ``` mkdir cmake-vs && cd cmake-vs cmake -DWITH_SHARED_LIB=off .. cmake --build . ``` ### Using Visual Studio and Win flex-bison - Generate a Visual Studio project for version of Visual Studio which you have (**cmake --help** can show list of supportable VS versions): - Run commands in command line: ``` mkdir cmake-vs cd cmake-vs cmake -G "Visual Studio 15 2017" .. ``` - Now open the folder cmake-vs using Visual Studio. ### Cross compile using mingw32 and generate a Windows Installer with CPack ``` mkdir cmake-mingw32 && cd cmake-mingw32 cmake -DCMAKE_TOOLCHAIN_FILE=../build/cmake/mingw32-toolchain.cmake -DBUILD_COMPILER=ON -DBUILD_LIBRARIES=OFF -DBUILD_TESTING=OFF .. cpack ``` # Other cases ## Building the Thrift IDL compiler in Windows without CMake If you don't want to use CMake you can use the already available Visual Studio 2010 solution. The Visual Studio project contains pre-build commands to generate the thriftl.cc, thrifty.cc and thrifty.hh files which are necessary to build the compiler. These depend on bison, flex and their dependencies to work properly. Download flex & bison as described above. Place these binaries somewhere in the path and rename win_flex.exe and win_bison.exe to flex.exe and bison.exe respectively. If this doesn't work on a system, try these manual pre-build steps. Open compiler.sln and remove the Pre-build commands under the project's: Properties -> Build Events -> Pre-Build Events. From a command prompt: ``` cd thrift/compiler/cpp flex -o src\thrift\thriftl.cc src\thrift\thriftl.ll ``` In the generated thriftl.cc, comment out #include Place a copy of bison.simple in thrift/compiler/cpp ``` bison -y -o "src/thrift/thrifty.cc" --defines src/thrift/thrifty.yy move src\thrift\thrifty.cc.hh src\thrift\thrifty.hh ``` Bison might generate the yacc header file "thrifty.cc.h" with just one h ".h" extension; in this case you'll have to rename to "thrifty.h". ``` move src\thrift\version.h.in src\thrift\version.h ``` Download inttypes.h from the interwebs and place it in an include path location (e.g. thrift/compiler/cpp/src). Build the compiler in Visual Studio. # Unit tests for compiler ## Using boost test - pls check **test** folder ## Using Catch C++ test library Added generic way to cover code by tests for many languages (you just need to make a correct header file for generator for your language - example in **netstd** implementation) - pls check **tests** folder # Have a Happy free time and holidays thrift-0.16.0/compiler/cpp/coding_standards.md000066400000000000000000000003021420101504100213010ustar00rootroot00000000000000## Compiler Coding Standards * When making small change / bugfix - follow style as seen in nearby code. * When making major refactor and / or adding new feature - follow style for C++ librarythrift-0.16.0/compiler/cpp/compiler.sln000066400000000000000000000015361420101504100200130ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compiler", "compiler.vcxproj", "{89975A1A-F799-4556-98B8-64E30AB39A90}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {89975A1A-F799-4556-98B8-64E30AB39A90}.Debug|Win32.ActiveCfg = Debug|Win32 {89975A1A-F799-4556-98B8-64E30AB39A90}.Debug|Win32.Build.0 = Debug|Win32 {89975A1A-F799-4556-98B8-64E30AB39A90}.Release|Win32.ActiveCfg = Release|Win32 {89975A1A-F799-4556-98B8-64E30AB39A90}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal thrift-0.16.0/compiler/cpp/compiler.vcxproj000066400000000000000000000322371420101504100207140ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 {89975A1A-F799-4556-98B8-64E30AB39A90} Win32Proj compiler Application true MultiByte Application true MultiByte Application false true MultiByte Application false true MultiByte true $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) thrift $(ExecutablePath);C:\Program Files (x86)\Git\bin true $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) thrift $(ExecutablePath);C:\Program Files (x86)\Git\bin false $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) thrift $(ExecutablePath);C:\Program Files (x86)\Git\bin false $(ProjectDir)\src\;$(ProjectDir)\src\windows\;$(IncludePath) thrift $(ExecutablePath);C:\Program Files (x86)\Git\bin Level3 Disabled WIN32;MINGW;YY_NO_UNISTD_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) thrift\windows\config.h CompileAsCpp MultiThreadedDebugDLL Console true flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy Level3 Disabled WIN32;MINGW;YY_NO_UNISTD_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) thrift\windows\config.h CompileAsCpp MultiThreadedDLL Console true flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy Level3 MaxSpeed true true WIN32;MINGW;YY_NO_UNISTD_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) thrift\windows\config.h CompileAsCpp MultiThreadedDLL Console true true true flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy Level3 MaxSpeed true true WIN32;MINGW;YY_NO_UNISTD_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) thrift\windows\config.h CompileAsCpp MultiThreadedDLL Console true true true flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll && bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy thrift-0.16.0/compiler/cpp/compiler.vcxproj.filters000066400000000000000000000152331420101504100223600ustar00rootroot00000000000000 generate generate generate generate parse parse parse parse parse parse parse parse parse parse parse parse parse parse parse parse parse parse windows windows {ae9d0a15-57ae-4f01-87a4-81f790249b83} {5df016bb-591b-420a-a535-4330d9187fbf} {b5c626af-afa5-433c-8e10-ee734533cb68} generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate generate parse parse generate generate thrift-0.16.0/compiler/cpp/src/000077500000000000000000000000001420101504100162455ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/src/Makefile.am000066400000000000000000000026111420101504100203010ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # Contains some contributions under the Thrift Software License. # Please see doc/old-thrift-license.txt in the Thrift distribution for # details. AUTOMAKE_OPTIONS = subdir-objects nostdinc AM_YFLAGS = -d BUILT_SOURCES = thrift/thrifty.cc noinst_LIBRARIES = thrift/libparse.a thrift_libparse_a_CPPFLAGS = -I$(srcdir) thrift_libparse_a_CXXFLAGS = -Wall -Wno-sign-compare -Wno-unused thrift_libparse_a_SOURCES = thrift/thrifty.yy \ thrift/thriftl.ll clean-local: $(RM) thrift/thriftl.cc thrift/thrifty.cc thrift/thrifty.h thrift/thrifty.hh EXTRA_DIST = \ thrift/logging.cc \ thrift/windows/config.h thrift-0.16.0/compiler/cpp/src/thrift/000077500000000000000000000000001420101504100175455ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/src/thrift/audit/000077500000000000000000000000001420101504100206535ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/src/thrift/audit/t_audit.cpp000066400000000000000000000416171420101504100230210ustar00rootroot00000000000000 #include #include #include #include #include #include #include #include #include #include #include // Careful: must include globals first for extern definitions #include "thrift/globals.h" #include "thrift/parse/t_program.h" #include "thrift/parse/t_scope.h" #include "thrift/parse/t_const.h" #include "thrift/parse/t_field.h" #include "thrift/version.h" #include "thrift/audit/t_audit.h" extern int g_warn; extern std::string g_curpath; extern bool g_return_failure; void thrift_audit_warning(int level, const char* fmt, ...) { if (g_warn < level) { return; } va_list args; printf("[Thrift Audit Warning:%s] ", g_curpath.c_str()); va_start(args, fmt); vprintf(fmt, args); va_end(args); printf("\n"); } void thrift_audit_failure(const char* fmt, ...) { va_list args; fprintf(stderr, "[Thrift Audit Failure:%s] ", g_curpath.c_str()); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); g_return_failure = true; } void compare_namespace(t_program* newProgram, t_program* oldProgram) { const std::map& newNamespaceMap = newProgram->get_all_namespaces(); const std::map& oldNamespaceMap = oldProgram->get_all_namespaces(); for(const auto & oldNamespaceMapIt : oldNamespaceMap) { auto newNamespaceMapIt = newNamespaceMap.find(oldNamespaceMapIt.first); if(newNamespaceMapIt == newNamespaceMap.end()) { thrift_audit_warning(1, "Language %s not found in new thrift file\n", (oldNamespaceMapIt.first).c_str()); } else if((newNamespaceMapIt->second) != oldNamespaceMapIt.second) { thrift_audit_warning(1, "Namespace %s changed in new thrift file\n", (oldNamespaceMapIt.second).c_str()); } } } void compare_enum_values(t_enum* newEnum,t_enum* oldEnum) { const std::vector& oldEnumValues = oldEnum->get_constants(); for(auto oldEnumValue : oldEnumValues) { int enumValue = oldEnumValue->get_value(); t_enum_value* newEnumValue = newEnum->get_constant_by_value(enumValue); if(newEnumValue != nullptr) { std::string enumName = oldEnumValue->get_name(); if(enumName != newEnumValue->get_name()) { thrift_audit_warning(1, "Name of the value %d changed in enum %s\n", enumValue, oldEnum->get_name().c_str()); } } else { thrift_audit_failure("Enum value %d missing in %s\n", enumValue, oldEnum->get_name().c_str()); } } } void compare_enums(const std::vector& newEnumList, const std::vector& oldEnumList) { std::map newEnumMap; std::vector::const_iterator newEnumIt; for(newEnumIt = newEnumList.begin(); newEnumIt != newEnumList.end(); newEnumIt++) { newEnumMap[(*newEnumIt)->get_name()] = *newEnumIt; } std::vector::const_iterator oldEnumIt; for(oldEnumIt = oldEnumList.begin(); oldEnumIt != oldEnumList.end(); oldEnumIt++) { std::map::iterator newEnumMapIt; newEnumMapIt = newEnumMap.find((*oldEnumIt)->get_name()); if(newEnumMapIt == newEnumMap.end()) { thrift_audit_warning(1, "Enum %s not found in new thrift file\n",(*oldEnumIt)->get_name().c_str()); } else { compare_enum_values(newEnumMapIt->second, *oldEnumIt); } } } //This function returns 'true' if the two arguements are of same types. //Returns false if they are of different type bool compare_type(t_type* newType, t_type* oldType) { //Comparing names of two types will work when the newType and oldType are basic types or structs or enums. //However, when they are containers, get_name() returns empty for which we have to compare the type of //their elements as well. if((newType->get_name()).empty() && (oldType->get_name()).empty()) { if(newType->is_list() && oldType->is_list()) { t_type* newElementType = ((t_list*)newType)->get_elem_type(); t_type* oldElementType = ((t_list*)oldType)->get_elem_type(); return compare_type(newElementType, oldElementType); } else if(newType->is_map() && oldType->is_map()) { t_type* newKeyType = ((t_map*)newType)->get_key_type(); t_type* oldKeyType = ((t_map*)oldType)->get_key_type(); t_type* newValType = ((t_map*)newType)->get_val_type(); t_type* oldValType = ((t_map*)oldType)->get_val_type(); return (compare_type(newKeyType, oldKeyType) && compare_type(newValType, oldValType)); } else if(newType->is_set() && oldType->is_set()) { t_type* newElementType = ((t_set*)newType)->get_elem_type(); t_type* oldElementType = ((t_set*)oldType)->get_elem_type(); return compare_type(newElementType, oldElementType); } else { return false; } } else if(newType->get_name() == oldType->get_name()) { return true; } else { return false; } } bool compare_pair(std::pair newMapPair, std::pair oldMapPair) { return compare_defaults(newMapPair.first, oldMapPair.first) && compare_defaults(newMapPair.second, oldMapPair.second); } // This function returns 'true' if the default values are same. Returns false if they are different. bool compare_defaults(t_const_value* newStructDefault, t_const_value* oldStructDefault) { if(newStructDefault == nullptr && oldStructDefault == nullptr) return true; else if(newStructDefault == nullptr && oldStructDefault != nullptr) return false; else if (newStructDefault != nullptr && oldStructDefault == nullptr) return false; if(newStructDefault->get_type() != oldStructDefault->get_type()) { return false; } switch(newStructDefault->get_type()) { case t_const_value::CV_INTEGER: return (newStructDefault->get_integer() == oldStructDefault->get_integer()); case t_const_value::CV_DOUBLE: return (newStructDefault->get_double() == oldStructDefault->get_double()); case t_const_value::CV_STRING: return (newStructDefault->get_string() == oldStructDefault->get_string()); case t_const_value::CV_LIST: { const std::vector& oldDefaultList = oldStructDefault->get_list(); const std::vector& newDefaultList = newStructDefault->get_list(); bool defaultValuesCompare = (oldDefaultList.size() == newDefaultList.size()); return defaultValuesCompare && std::equal(newDefaultList.begin(), newDefaultList.end(), oldDefaultList.begin(), compare_defaults); } case t_const_value::CV_MAP: { const std::map newMap = newStructDefault->get_map(); const std::map oldMap = oldStructDefault->get_map(); bool defaultValuesCompare = (oldMap.size() == newMap.size()); return defaultValuesCompare && std::equal(newMap.begin(), newMap.end(), oldMap.begin(), compare_pair); } case t_const_value::CV_IDENTIFIER: return (newStructDefault->get_identifier() == oldStructDefault->get_identifier()); default: return false; } } void compare_struct_field(t_field* newField, t_field* oldField, std::string oldStructName) { t_type* newFieldType = newField->get_type(); t_type* oldFieldType = oldField->get_type(); if(!compare_type(newFieldType, oldFieldType)) { thrift_audit_failure("Struct Field Type Changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str()); } // A Struct member can be optional if it is mentioned explicitly, or if it is assigned with default values. bool newStructFieldOptional = (newField->get_req() != t_field::T_REQUIRED); bool oldStructFieldOptional = (oldField->get_req() != t_field::T_REQUIRED); if(newStructFieldOptional != oldStructFieldOptional) { thrift_audit_failure("Struct Field Requiredness Changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str()); } if(newStructFieldOptional || oldStructFieldOptional) { if(!compare_defaults(newField->get_value(), oldField->get_value())) { thrift_audit_warning(1, "Default value changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str()); } } std::string fieldName = newField->get_name(); if(fieldName != oldField->get_name()) { thrift_audit_warning(1, "Struct field name changed for Id = %d in %s\n", newField->get_key(), oldStructName.c_str()); } } void compare_single_struct(t_struct* newStruct, t_struct* oldStruct, const std::string& oldStructName = std::string()) { std::string structName = oldStructName.empty() ? oldStruct->get_name() : oldStructName; const std::vector& oldStructMembersInIdOrder = oldStruct->get_sorted_members(); const std::vector& newStructMembersInIdOrder = newStruct->get_sorted_members(); auto oldStructMemberIt = oldStructMembersInIdOrder.begin(); auto newStructMemberIt = newStructMembersInIdOrder.begin(); // Since we have the struct members in their ID order, comparing their IDs can be done by traversing the two member // lists together. while(!(oldStructMemberIt == oldStructMembersInIdOrder.end() && newStructMemberIt == newStructMembersInIdOrder.end())) { if(newStructMemberIt == newStructMembersInIdOrder.end() && oldStructMemberIt != oldStructMembersInIdOrder.end()) { // A field ID has been removed from the end. thrift_audit_failure("Struct Field removed for Id = %d in %s \n", (*oldStructMemberIt)->get_key(), structName.c_str()); oldStructMemberIt++; } else if(newStructMemberIt != newStructMembersInIdOrder.end() && oldStructMemberIt == oldStructMembersInIdOrder.end()) { //New field ID has been added to the end. if((*newStructMemberIt)->get_req() == t_field::T_REQUIRED) { thrift_audit_failure("Required Struct Field Added for Id = %d in %s \n", (*newStructMemberIt)->get_key(), structName.c_str()); } newStructMemberIt++; } else if((*newStructMemberIt)->get_key() == (*oldStructMemberIt)->get_key()) { //Field ID found in both structs. Compare field types, default values. compare_struct_field(*newStructMemberIt, *oldStructMemberIt, structName); newStructMemberIt++; oldStructMemberIt++; } else if((*newStructMemberIt)->get_key() < (*oldStructMemberIt)->get_key()) { //New Field Id is inserted in between //Adding fields to struct is fine, but adding them in the middle is suspicious. Error!! thrift_audit_failure("Struct field is added in the middle with Id = %d in %s\n", (*newStructMemberIt)->get_key(), structName.c_str()); newStructMemberIt++; } else if((*newStructMemberIt)->get_key() > (*oldStructMemberIt)->get_key()) { //A field is deleted in newStruct. thrift_audit_failure("Struct Field removed for Id = %d in %s \n", (*oldStructMemberIt)->get_key(), structName.c_str()); oldStructMemberIt++; } } } void compare_structs(const std::vector& newStructList, const std::vector& oldStructList) { std::map newStructMap; std::vector::const_iterator newStructListIt; for(newStructListIt = newStructList.begin(); newStructListIt != newStructList.end(); newStructListIt++) { newStructMap[(*newStructListIt)->get_name()] = *newStructListIt; } std::vector::const_iterator oldStructListIt; for(oldStructListIt = oldStructList.begin(); oldStructListIt != oldStructList.end(); oldStructListIt++) { std::map::iterator newStructMapIt; newStructMapIt = newStructMap.find((*oldStructListIt)->get_name()); if(newStructMapIt == newStructMap.end()) { thrift_audit_failure("Struct %s not found in new thrift file\n", (*oldStructListIt)->get_name().c_str()); } else { compare_single_struct(newStructMapIt->second, *oldStructListIt); } } } void compare_single_function(t_function* newFunction, t_function* oldFunction) { t_type* newFunctionReturnType = newFunction->get_returntype(); if(newFunction->is_oneway() != oldFunction->is_oneway()) { thrift_audit_failure("Oneway attribute changed for function %s\n",oldFunction->get_name().c_str()); } if(!compare_type(newFunctionReturnType, oldFunction->get_returntype())) { thrift_audit_failure("Return type changed for function %s\n",oldFunction->get_name().c_str()); } //Compare function arguments. compare_single_struct(newFunction->get_arglist(), oldFunction->get_arglist()); std::string exceptionName = oldFunction->get_name(); exceptionName += "_exception"; compare_single_struct(newFunction->get_xceptions(), oldFunction->get_xceptions(), exceptionName); } void compare_functions(const std::vector& newFunctionList, const std::vector& oldFunctionList) { std::map newFunctionMap; std::map::iterator newFunctionMapIt; for(auto newFunctionIt : newFunctionList) { newFunctionMap[newFunctionIt->get_name()] = newFunctionIt; } for(auto oldFunctionIt : oldFunctionList) { newFunctionMapIt = newFunctionMap.find(oldFunctionIt->get_name()); if(newFunctionMapIt == newFunctionMap.end()) { thrift_audit_failure("New Thrift File has missing function %s\n",oldFunctionIt->get_name().c_str()); continue; } else { //Function is found in both thrift files. Compare return type and argument list compare_single_function(newFunctionMapIt->second, oldFunctionIt); } } } void compare_services(const std::vector& newServices, const std::vector& oldServices) { std::vector::const_iterator oldServiceIt; std::map newServiceMap; for(auto newService : newServices) { newServiceMap[newService->get_name()] = newService; } for(oldServiceIt = oldServices.begin(); oldServiceIt != oldServices.end(); oldServiceIt++) { const std::string oldServiceName = (*oldServiceIt)->get_name(); auto newServiceMapIt = newServiceMap.find(oldServiceName); if(newServiceMapIt == newServiceMap.end()) { thrift_audit_failure("New Thrift file is missing a service %s\n", oldServiceName.c_str()); } else { t_service* oldServiceExtends = (*oldServiceIt)->get_extends(); t_service* newServiceExtends = (newServiceMapIt->second)->get_extends(); if(oldServiceExtends == nullptr) { // It is fine to add extends. So if service in older thrift did not have any extends, we are fine. // DO Nothing } else if(oldServiceExtends != nullptr && newServiceExtends == nullptr) { thrift_audit_failure("Change in Service inheritance for %s\n", oldServiceName.c_str()); } else { std::string oldExtendsName = oldServiceExtends->get_name(); std::string newExtendsName = newServiceExtends->get_name(); if( newExtendsName != oldExtendsName) { thrift_audit_failure("Change in Service inheritance for %s\n", oldServiceName.c_str()); } } compare_functions((newServiceMapIt->second)->get_functions(), (*oldServiceIt)->get_functions()); } } } void compare_consts(const std::vector& newConst, const std::vector& oldConst) { std::vector::const_iterator newConstIt; std::vector::const_iterator oldConstIt; std::map newConstMap; for(newConstIt = newConst.begin(); newConstIt != newConst.end(); newConstIt++) { newConstMap[(*newConstIt)->get_name()] = *newConstIt; } std::map::const_iterator newConstMapIt; for(oldConstIt = oldConst.begin(); oldConstIt != oldConst.end(); oldConstIt++) { newConstMapIt = newConstMap.find((*oldConstIt)->get_name()); if(newConstMapIt == newConstMap.end()) { thrift_audit_warning(1, "Constants Missing %s \n", ((*oldConstIt)->get_name()).c_str()); } else if(!compare_type((newConstMapIt->second)->get_type(), (*oldConstIt)->get_type())) { thrift_audit_warning(1, "Constant %s is of different type \n", ((*oldConstIt)->get_name()).c_str()); } else if(!compare_defaults((newConstMapIt->second)->get_value(), (*oldConstIt)->get_value())) { thrift_audit_warning(1, "Constant %s has different value\n", ((*oldConstIt)->get_name()).c_str()); } } } thrift-0.16.0/compiler/cpp/src/thrift/audit/t_audit.h000066400000000000000000000012621420101504100224560ustar00rootroot00000000000000#ifndef T_AUDIT_H #define T_AUDIT_H void compare_namespace(t_program* newProgram, t_program* oldProgram); void compare_enums(const std::vector& newEnumList, const std::vector& oldEnumList); bool compare_defaults(t_const_value* newStructDefault, t_const_value* oldStructDefault); void compare_structs(const std::vector& newStructList, const std::vector& oldStructList); void compare_services(const std::vector& newServices, const std::vector& oldServices); void compare_consts(const std::vector& newConst, const std::vector& oldConst); #endif thrift-0.16.0/compiler/cpp/src/thrift/common.cc000066400000000000000000000043031420101504100213440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "thrift/common.h" #include "thrift/parse/t_base_type.h" t_type* g_type_void; t_type* g_type_string; t_type* g_type_binary; t_type* g_type_slist; t_type* g_type_bool; t_type* g_type_i8; t_type* g_type_i16; t_type* g_type_i32; t_type* g_type_i64; t_type* g_type_double; void initGlobals() { g_type_void = new t_base_type("void", t_base_type::TYPE_VOID); g_type_string = new t_base_type("string", t_base_type::TYPE_STRING); g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING); ((t_base_type*)g_type_binary)->set_binary(true); g_type_slist = new t_base_type("string", t_base_type::TYPE_STRING); ((t_base_type*)g_type_slist)->set_string_list(true); g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL); g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8); g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16); g_type_i32 = new t_base_type("i32", t_base_type::TYPE_I32); g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64); g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE); } void clearGlobals() { delete g_type_void; delete g_type_string; delete g_type_bool; delete g_type_i8; delete g_type_i16; delete g_type_i32; delete g_type_i64; delete g_type_double; } /** * The location of the last parsed doctext comment. */ int g_doctext_lineno; int g_program_doctext_lineno = 0; PROGDOCTEXT_STATUS g_program_doctext_status = INVALID; thrift-0.16.0/compiler/cpp/src/thrift/common.h000066400000000000000000000023721420101504100212120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_COMMON_H #define T_COMMON_H #include "thrift/parse/t_type.h" /** * Global types for the parser to be able to reference */ extern t_type* g_type_void; extern t_type* g_type_string; extern t_type* g_type_binary; extern t_type* g_type_slist; extern t_type* g_type_bool; extern t_type* g_type_i8; extern t_type* g_type_i16; extern t_type* g_type_i32; extern t_type* g_type_i64; extern t_type* g_type_double; void initGlobals(); void clearGlobals(); #endif thrift-0.16.0/compiler/cpp/src/thrift/generate/000077500000000000000000000000001420101504100213375ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc000066400000000000000000005764241420101504100255000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /* forward declarations */ string initial_caps_to_underscores(string name); string underscores_to_initial_caps(string name); string to_upper_case(string name); string to_lower_case(string name); /** * C code generator, using glib for C typing. */ class t_c_glib_generator : public t_oop_generator { public: /* constructor */ t_c_glib_generator(t_program* program, const map& parsed_options, const string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; /* set the output directory */ this->out_dir_base_ = "gen-c_glib"; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option c_glib:" + iter->first; } /* set the namespace */ this->nspace = program_->get_namespace("c_glib"); if (this->nspace.empty()) { this->nspace = ""; this->nspace_u = ""; this->nspace_uc = ""; this->nspace_lc = ""; } else { /* replace dots with underscores */ char* tmp = strdup(this->nspace.c_str()); for (unsigned int i = 0; i < strlen(tmp); i++) { if (tmp[i] == '.') { tmp[i] = '_'; } } this->nspace = string(tmp, strlen(tmp)); free(tmp); /* clean up the namespace for C. * An input of 'namespace foo' should result in: * - nspace = foo - for thrift objects and typedefs * - nspace_u = Foo - for internal GObject prefixes * - nspace_uc = FOO_ - for macro prefixes * - nspace_lc = foo_ - for filename and method prefixes * The underscores are there since uc and lc strings are used as file and * variable prefixes. */ this->nspace_u = initial_caps_to_underscores(this->nspace); this->nspace_uc = to_upper_case(this->nspace_u) + "_"; this->nspace_lc = to_lower_case(this->nspace_u) + "_"; } } /* initialization and destruction */ void init_generator() override; void close_generator() override; /* generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_consts(vector consts) override; void generate_struct(t_struct* tstruct) override; void generate_service(t_service* tservice) override; void generate_xception(t_struct* tstruct) override; private: /* file streams */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_types_impl_; ofstream_with_content_based_conditional_update f_header_; ofstream_with_content_based_conditional_update f_service_; /* namespace variables */ string nspace; string nspace_u; string nspace_uc; string nspace_lc; /* helper functions */ bool is_complex_type(t_type* ttype); bool is_numeric(t_type* ttype); string type_name(t_type* ttype, bool in_typedef = false, bool is_const = false); string property_type_name(t_type* ttype, bool in_typedef = false, bool is_const = false); string base_type_name(t_type* type); string type_to_enum(t_type* type); string constant_literal(t_type* type, t_const_value* value); string constant_value(string name, t_type* type, t_const_value* value); string constant_value_with_storage(string name, t_type* type, t_const_value* value); string function_signature(t_function* tfunction); string argument_list(t_struct* tstruct); string xception_list(t_struct* tstruct); string declare_field(t_field* tfield, bool init = false, bool pointer = false, bool constant = false, bool reference = false); void declare_local_variable(ostream& out, t_type* ttype, string& base_name, bool for_hash_table); void declore_local_variable_for_write(ostream& out, t_type* ttype, string& base_name); /* generation functions */ void generate_const_initializer(string name, t_type* type, t_const_value* value, bool top_level = false); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_handler(t_service* tservice); void generate_service_processor(t_service* tservice); void generate_service_server(t_service* tservice); void generate_object(t_struct* tstruct); void generate_struct_writer(ostream& out, t_struct* tstruct, string this_name, string this_get = "", bool is_function = true); void generate_struct_reader(ostream& out, t_struct* tstruct, string this_name, string this_get = "", bool is_function = true); void generate_serialize_field(ostream& out, t_field* tfield, string prefix, string suffix, int error_ret); void generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix, int error_ret); void generate_serialize_container(ostream& out, t_type* ttype, string prefix, int error_ret); void generate_serialize_map_element(ostream& out, t_map* tmap, string key, string value, int error_ret); void generate_serialize_set_element(ostream& out, t_set* tset, string element, int error_ret); void generate_serialize_list_element(ostream& out, t_list* tlist, string list, string index, int error_ret); void generate_deserialize_field(ostream& out, t_field* tfield, string prefix, string suffix, int error_ret, bool allocate = true); void generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix, int error_ret, bool allocate = true); void generate_deserialize_container(ostream& out, t_type* ttype, string prefix, int error_ret); void generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix, int error_ret); void generate_deserialize_set_element(ostream& out, t_set* tset, string prefix, int error_ret); void generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix, string index, int error_ret); string generate_new_hash_from_type(t_type* key, t_type* value); string generate_new_array_from_type(t_type* ttype); string generate_free_func_from_type(t_type* ttype); string generate_hash_func_from_type(t_type* ttype); string generate_cmp_func_from_type(t_type* ttype); }; /** * Prepare for file generation by opening up the necessary file * output streams. */ void t_c_glib_generator::init_generator() { /* create output directory */ MKDIR(get_out_dir().c_str()); string program_name_u = initial_caps_to_underscores(program_name_); string program_name_uc = to_upper_case(program_name_u); string program_name_lc = to_lower_case(program_name_u); /* create output files */ string f_types_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.h"; f_types_.open(f_types_name.c_str()); string f_types_impl_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.c"; f_types_impl_.open(f_types_impl_name.c_str()); /* add thrift boilerplate headers */ f_types_ << autogen_comment(); f_types_impl_ << autogen_comment(); /* include inclusion guard */ f_types_ << "#ifndef " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << "#define " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << endl; /* include base types */ f_types_ << "/* base includes */" << endl << "#include " << endl << "#include " << endl << "#include " << endl; /* include other thrift includes */ const vector& includes = program_->get_includes(); if (!includes.empty()) { f_types_ << "/* other thrift includes */" << endl; for (auto include : includes) { const std::string& include_nspace = include->get_namespace("c_glib"); std::string include_nspace_prefix = include_nspace.empty() ? "" : initial_caps_to_underscores(include_nspace) + "_"; f_types_ << "#include \"" << include_nspace_prefix << initial_caps_to_underscores(include->get_name()) << "_types.h\"" << endl; } f_types_ << endl; } /* include custom headers */ const vector& c_includes = program_->get_c_includes(); f_types_ << "/* custom thrift includes */" << endl; for (const auto & c_include : c_includes) { if (c_include[0] == '<') { f_types_ << "#include " << c_include << endl; } else { f_types_ << "#include \"" << c_include << "\"" << endl; } } f_types_ << endl; /* include math.h (for "INFINITY") in the implementation file, in case we encounter a struct with a member of type double */ f_types_impl_ << endl << "#include " << endl; // include the types file f_types_impl_ << endl << "#include \"" << this->nspace_lc << program_name_u << "_types.h\"" << endl << "#include " << endl << endl; f_types_ << "/* begin types */" << endl << endl; } /** * Finish up generation and close all file streams. */ void t_c_glib_generator::close_generator() { string program_name_uc = to_upper_case(initial_caps_to_underscores(program_name_)); /* end the header inclusion guard */ f_types_ << "#endif /* " << this->nspace_uc << program_name_uc << "_TYPES_H */" << endl; /* close output file */ f_types_.close(); f_types_impl_.close(); } /** * Generates a Thrift typedef in C code. For example: * * Thrift: * typedef map SomeMap * * C: * typedef GHashTable * ThriftSomeMap; */ void t_c_glib_generator::generate_typedef(t_typedef* ttypedef) { f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << this->nspace << ttypedef->get_symbolic() << ";" << endl << endl; } /** * Generates a C enumeration. For example: * * Thrift: * enum MyEnum { * ONE = 1, * TWO * } * * C: * enum _ThriftMyEnum { * THRIFT_MY_ENUM_ONE = 1, * THRIFT_MY_ENUM_TWO * }; * typedef enum _ThriftMyEnum ThriftMyEnum; */ void t_c_glib_generator::generate_enum(t_enum* tenum) { string name = tenum->get_name(); string name_uc = to_upper_case(initial_caps_to_underscores(name)); f_types_ << indent() << "enum _" << this->nspace << name << " {" << endl; indent_up(); vector constants = tenum->get_constants(); vector::iterator c_iter; bool first = true; /* output each of the enumeration elements */ for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { if (first) { first = false; } else { f_types_ << "," << endl; } f_types_ << indent() << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name(); f_types_ << " = " << (*c_iter)->get_value(); } indent_down(); f_types_ << endl << "};" << endl << "typedef enum _" << this->nspace << name << " " << this->nspace << name << ";" << endl << endl; f_types_ << "/* return the name of the constant */" << endl; f_types_ << "const char *" << endl; f_types_ << "toString_" << name << "(int value); " << endl << endl; ; f_types_impl_ << "/* return the name of the constant */" << endl; f_types_impl_ << "const char *" << endl; f_types_impl_ << "toString_" << name << "(int value) " << endl; f_types_impl_ << "{" << endl; f_types_impl_ << " static __thread char buf[16] = {0};" << endl; f_types_impl_ << " switch(value) {" << endl; std::set done; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); // Skipping duplicate value if (done.find(value) == done.end()) { done.insert(value); f_types_impl_ << " case " << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() << ":" << "return \"" << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name() << "\";" << endl; } } f_types_impl_ << " default: g_snprintf(buf, 16, \"%d\", value); return buf;" << endl; f_types_impl_ << " }" << endl; f_types_impl_ << "}" << endl << endl; } /** * Generates Thrift constants in C code. */ void t_c_glib_generator::generate_consts(vector consts) { f_types_ << "/* constants */" << endl; f_types_impl_ << "/* constants */" << endl; vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { string name = (*c_iter)->get_name(); string name_uc = to_upper_case(name); string name_lc = to_lower_case(name); t_type* type = (*c_iter)->get_type(); t_const_value* value = (*c_iter)->get_value(); if (is_complex_type(type)) { f_types_ << type_name(type) << indent() << this->nspace_lc << name_lc << "_constant();" << endl; } f_types_ << indent() << "#define " << this->nspace_uc << name_uc << " " << constant_value(name_lc, type, value) << endl; generate_const_initializer(name_lc, type, value, true); } f_types_ << endl; f_types_impl_ << endl; } /** * Generate Thrift structs in C code, as GObjects. Example: * * Thrift: * struct Bonk * { * 1: string message, * 2: i32 type * } * * C GObject instance header: * struct _ThriftBonk * { * GObject parent; * * gchar * message; * gint32 type; * }; * typedef struct _ThriftBonk ThriftBonk * // ... additional GObject boilerplate ... */ void t_c_glib_generator::generate_struct(t_struct* tstruct) { f_types_ << "/* struct " << tstruct->get_name() << " */" << endl; generate_object(tstruct); } /** * Generate C code to represent Thrift services. Creates a new GObject * which can be used to access the service. */ void t_c_glib_generator::generate_service(t_service* tservice) { string svcname_u = initial_caps_to_underscores(tservice->get_name()); string svcname_uc = this->nspace_uc + to_upper_case(svcname_u); string filename = this->nspace_lc + to_lower_case(svcname_u); // make output files string f_header_name = get_out_dir() + filename + ".h"; f_header_.open(f_header_name.c_str()); string program_name_u = initial_caps_to_underscores(program_name_); string program_name_lc = to_lower_case(program_name_u); // add header file boilerplate f_header_ << autogen_comment(); // add an inclusion guard f_header_ << "#ifndef " << svcname_uc << "_H" << endl << "#define " << svcname_uc << "_H" << endl << endl; // add standard includes f_header_ << "#include " << endl << endl; f_header_ << "#include \"" << this->nspace_lc << program_name_lc << "_types.h\"" << endl; // if we are inheriting from another service, include its header t_service* extends_service = tservice->get_extends(); if (extends_service != nullptr) { f_header_ << "#include \"" << this->nspace_lc << to_lower_case(initial_caps_to_underscores(extends_service->get_name())) << ".h\"" << endl; } f_header_ << endl; // create the service implementation string f_service_name = get_out_dir() + filename + ".c"; f_service_.open(f_service_name.c_str()); // add the boilerplace header f_service_ << autogen_comment(); // include the headers f_service_ << "#include " << endl << "#include " << endl << "#include " << endl << "#include \"" << filename << ".h\"" << endl << endl; // generate the service-helper classes generate_service_helpers(tservice); // generate the client objects generate_service_client(tservice); // generate the server objects generate_service_server(tservice); // end the header inclusion guard f_header_ << "#endif /* " << svcname_uc << "_H */" << endl; // close the files f_service_.close(); f_header_.close(); } /** * */ void t_c_glib_generator::generate_xception(t_struct* tstruct) { string name = tstruct->get_name(); string name_u = initial_caps_to_underscores(name); string name_lc = to_lower_case(name_u); string name_uc = to_upper_case(name_u); generate_object(tstruct); f_types_ << "/* exception */" << endl << "typedef enum" << endl << "{" << endl; indent_up(); f_types_ << indent() << this->nspace_uc << name_uc << "_ERROR_CODE" << endl; indent_down(); f_types_ << "} " << this->nspace << name << "Error;" << endl << endl << "GQuark " << this->nspace_lc << name_lc << "_error_quark (void);" << endl << "#define " << this->nspace_uc << name_uc << "_ERROR (" << this->nspace_lc << name_lc << "_error_quark())" << endl << endl << endl; f_types_impl_ << "/* define the GError domain for exceptions */" << endl << "#define " << this->nspace_uc << name_uc << "_ERROR_DOMAIN \"" << this->nspace_lc << name_lc << "_error_quark\"" << endl << "GQuark" << endl << this->nspace_lc << name_lc << "_error_quark (void)" << endl << "{" << endl << " return g_quark_from_static_string (" << this->nspace_uc << name_uc << "_ERROR_DOMAIN);" << endl << "}" << endl << endl; } /******************** * HELPER FUNCTIONS * ********************/ /** * Returns true if ttype is not a primitive. */ bool t_c_glib_generator::is_complex_type(t_type* ttype) { ttype = get_true_type(ttype); return ttype->is_container() || ttype->is_struct() || ttype->is_xception(); } bool t_c_glib_generator::is_numeric(t_type* ttype) { return ttype->is_enum() || (ttype->is_base_type() && !ttype->is_string()); } /** * Maps a Thrift t_type to a C type. */ string t_c_glib_generator::type_name(t_type* ttype, bool in_typedef, bool is_const) { if (ttype->is_base_type()) { string bname = base_type_name(ttype); if (is_const) { return "const " + bname; } else { return bname; } } if (ttype->is_container()) { string cname; t_container* tcontainer = (t_container*)ttype; if (tcontainer->has_cpp_name()) { cname = tcontainer->get_cpp_name(); } else if (ttype->is_map()) { cname = "GHashTable"; } else if (ttype->is_set()) { // since a set requires unique elements, use a GHashTable, and // populate the keys and values with the same data, using keys for // the actual writes and reads. // TODO: discuss whether or not to implement TSet, THashSet or GHashSet cname = "GHashTable"; } else if (ttype->is_list()) { t_type* etype = get_true_type(((t_list*)ttype)->get_elem_type()); if (etype->is_void()) { throw std::runtime_error("compiler error: list element type cannot be void"); } // TODO: investigate other implementations besides GPtrArray cname = is_numeric(etype) ? "GArray" : "GPtrArray"; } /* Omit the dereference operator if we are aliasing this type within a typedef, to allow the type to be used more naturally in client code; otherwise, include it */ if (!in_typedef) { cname += " *"; } if (is_const) { return "const " + cname; } else { return cname; } } // check for a namespace t_program* tprogram = ttype->get_program(); string pname = (tprogram ? tprogram->get_namespace("c_glib") : "") + ttype->get_name(); if (is_complex_type(ttype)) { pname += " *"; } if (is_const) { return "const " + pname; } else { return pname; } } /** * Maps a Thrift primitive to the type needed to hold its value when used as an * object property. * * This method is needed because all integer properties of width less than 64 * bits map to the same type, gint, as opposed to their width-specific type * (gint8, gint16 or gint32). */ string t_c_glib_generator::property_type_name(t_type* ttype, bool in_typedef, bool is_const) { string result; if (ttype->is_base_type()) { switch (((t_base_type*)ttype)->get_base()) { case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: if (is_const) { result = "const gint"; } else { result = "gint"; } break; default: result = type_name(ttype, in_typedef, is_const); } } else { result = type_name(ttype, in_typedef, is_const); } return result; } /** * Maps a Thrift primitive to a C primitive. */ string t_c_glib_generator::base_type_name(t_type* type) { if (type->is_enum()) { return type_name(type); } if (!type->is_base_type()) { throw std::invalid_argument("Only base types are suppported."); } t_base_type* base_type = reinterpret_cast(type); t_base_type::t_base tbase = base_type->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: if (base_type->is_binary()) { return "GByteArray *"; } else { return "gchar *"; } case t_base_type::TYPE_BOOL: return "gboolean"; case t_base_type::TYPE_I8: return "gint8"; case t_base_type::TYPE_I16: return "gint16"; case t_base_type::TYPE_I32: return "gint32"; case t_base_type::TYPE_I64: return "gint64"; case t_base_type::TYPE_DOUBLE: return "gdouble"; default: throw std::logic_error("compiler error: no C base type name for base type " + t_base_type::t_base_name(tbase)); } } /** * Returns a member of the ThriftType C enumeration in thrift_protocol.h * for a Thrift type. */ string t_c_glib_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "T_STRING"; case t_base_type::TYPE_BOOL: return "T_BOOL"; case t_base_type::TYPE_I8: return "T_BYTE"; case t_base_type::TYPE_I16: return "T_I16"; case t_base_type::TYPE_I32: return "T_I32"; case t_base_type::TYPE_I64: return "T_I64"; case t_base_type::TYPE_DOUBLE: return "T_DOUBLE"; } } else if (type->is_enum()) { return "T_I32"; } else if (type->is_struct()) { return "T_STRUCT"; } else if (type->is_xception()) { return "T_STRUCT"; } else if (type->is_map()) { return "T_MAP"; } else if (type->is_set()) { return "T_SET"; } else if (type->is_list()) { return "T_LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Returns a Thrift constant formatted as a literal for inclusion in C code. */ string t_c_glib_generator::constant_literal(t_type* type, t_const_value* value) { ostringstream render; if (type->is_base_type()) { /* primitives */ t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: render << "\"" + value->get_string() + "\""; break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() != 0) ? "TRUE" : "FALSE"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: render << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: render << value->get_double(); break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else { t_const_value::t_const_value_type value_type = value->get_type(); switch (value_type) { case t_const_value::CV_IDENTIFIER: render << value->get_integer(); break; case t_const_value::CV_LIST: render << "{ "; { t_type* elem_type = ((t_list*)type)->get_elem_type(); const vector& list = value->get_list(); vector::const_iterator list_iter; if (list.size() > 0) { list_iter = list.begin(); render << constant_literal(elem_type, *list_iter); while (++list_iter != list.end()) { render << ", " << constant_literal(elem_type, *list_iter); } } } render << " }"; break; case t_const_value::CV_MAP: default: render << "NULL /* not supported */"; } } return render.str(); } /** * Returns C code that represents a Thrift constant. */ string t_c_glib_generator::constant_value(string name, t_type* type, t_const_value* value) { ostringstream render; if (type->is_base_type()) { /* primitives */ t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: render << "g_strdup (\"" + value->get_string() + "\")"; break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() != 0) ? 1 : 0); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: render << value->get_integer(); break; case t_base_type::TYPE_I64: render << "G_GINT64_CONSTANT (" << value->get_integer() << ")"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << value->get_integer(); } else { render << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { render << "(" << type_name(type) << ")" << value->get_integer(); } else if (is_complex_type(type)) { render << "(" << this->nspace_lc << to_lower_case(name) << "_constant())"; } else { render << "NULL /* not supported */"; } return render.str(); } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_c_glib_generator::function_signature(t_function* tfunction) { t_type* ttype = tfunction->get_returntype(); t_struct* arglist = tfunction->get_arglist(); t_struct* xlist = tfunction->get_xceptions(); string fname = initial_caps_to_underscores(tfunction->get_name()); bool has_return = !ttype->is_void(); bool has_args = arglist->get_members().size() == 0; bool has_xceptions = xlist->get_members().size() == 0; return "gboolean " + this->nspace_lc + fname + " (" + this->nspace + service_name_ + "If * iface" + (has_return ? ", " + type_name(ttype) + "* _return" : "") + (has_args ? "" : (", " + argument_list(arglist))) + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError ** error)"; } /** * Renders a field list * * @param tstruct The struct definition * @return Comma sepearated list of all field names in that struct */ string t_c_glib_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name(); } return result; } /** * Renders mutable exception lists * * @param tstruct The struct definition * @return Comma sepearated list of all field names in that struct */ string t_c_glib_generator::xception_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += type_name((*f_iter)->get_type(), false, false) + "* " + (*f_iter)->get_name(); } return result; } /** * Declares a field, including any necessary initialization. */ string t_c_glib_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant, bool reference) { string result = ""; if (constant) { result += "const "; } result += type_name(tfield->get_type()); if (pointer) { result += "*"; } if (reference) { result += "*"; } result += " " + tfield->get_name(); if (init) { t_type* type = get_true_type(tfield->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: break; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = (gdouble) 0"; break; case t_base_type::TYPE_STRING: result += " = NULL"; break; default: throw "compiler error: no C intializer for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { result += " = (" + type_name(type) + ") 0"; } else if (type->is_struct() || type->is_container()) { result += " = NULL"; } } if (!reference) { result += ";"; } return result; } string t_c_glib_generator::constant_value_with_storage(string fname, t_type* etype, t_const_value* value) { ostringstream render; if (is_numeric(etype)) { render << " " << type_name(etype) << " *" << fname << " = " << "g_new (" << base_type_name(etype) << ", 1);" << endl << " *" << fname << " = " << constant_value(fname, (t_type*)etype, value) << ";" << endl; } else { render << " " << type_name(etype) << " " << fname << " = " << constant_value(fname, (t_type*)etype, value) << ";" << endl; } return render.str(); } /** * Generates C code that initializes complex constants. */ void t_c_glib_generator::generate_const_initializer(string name, t_type* type, t_const_value* value, bool top_level) { string name_u = initial_caps_to_underscores(name); string name_lc = to_lower_case(name_u); string type_u = initial_caps_to_underscores(type->get_name()); string type_uc = to_upper_case(type_u); string maybe_static = top_level ? "" : "static "; if (type->is_struct() || type->is_xception()) { const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; ostringstream initializers; // initialize any constants that may be referenced by this initializer for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; string field_name = ""; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); field_name = (*f_iter)->get_name(); break; } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } field_name = tmp(field_name); generate_const_initializer(name + "_constant_" + field_name, field_type, v_iter->second); initializers << " constant->" << v_iter->first->get_string() << " = " << constant_value(name + "_constant_" + field_name, field_type, v_iter->second) << ";" << endl << " constant->__isset_" << v_iter->first->get_string() << " = TRUE;" << endl; } // implement the initializer f_types_impl_ << maybe_static << this->nspace << type->get_name() << " *" << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "static " << this->nspace << type->get_name() << " *constant = NULL;" << endl << indent() << "if (constant == NULL)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "constant = g_object_new (" << this->nspace_uc << "TYPE_" << type_uc << ", NULL);" << endl << initializers.str(); scope_down(f_types_impl_); for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; string field_name = ""; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); field_name = (*f_iter)->get_name(); break; } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } field_name = tmp(field_name); } f_types_impl_ << indent() << "return constant;" << endl; scope_down(f_types_impl_); f_types_impl_ << endl; } else if (type->is_list()) { string list_type = "GPtrArray *"; string free_func = generate_free_func_from_type(reinterpret_cast(type)->get_elem_type()); string list_initializer = "g_ptr_array_new_with_free_func (" + free_func + ");"; string list_appender = "g_ptr_array_add"; bool list_variable = false; t_type* etype = ((t_list*)type)->get_elem_type(); const vector& val = value->get_list(); vector::const_iterator v_iter; ostringstream initializers; ostringstream appenders; list_initializer = generate_new_array_from_type(etype); if (etype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)etype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot determine array type"; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: list_type = "GArray *"; list_appender = "g_array_append_val"; list_variable = true; break; case t_base_type::TYPE_STRING: break; default: throw "compiler error: no array info for type"; } } else if (etype->is_enum()) { list_type = "GArray *"; list_appender = "g_array_append_val"; list_variable = true; } for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string fname = tmp(name); generate_const_initializer(fname, etype, (*v_iter)); if (list_variable) { initializers << " " << type_name(etype) << " " << fname << " = " << constant_value(fname, (t_type*)etype, (*v_iter)) << ";" << endl; appenders << " " << list_appender << "(constant, " << fname << ");" << endl; } else { appenders << " " << list_appender << "(constant, " << constant_value(fname, (t_type*)etype, (*v_iter)) << ");" << endl; } } f_types_impl_ << maybe_static << list_type << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "static " << list_type << " constant = NULL;" << endl << indent() << "if (constant == NULL)" << endl; scope_up(f_types_impl_); if (!initializers.str().empty()) { f_types_impl_ << initializers.str() << endl; } f_types_impl_ << indent() << "constant = " << list_initializer << endl << appenders.str(); scope_down(f_types_impl_); f_types_impl_ << indent() << "return constant;" << endl; scope_down(f_types_impl_); f_types_impl_ << endl; } else if (type->is_set()) { t_type* etype = ((t_set*)type)->get_elem_type(); const vector& val = value->get_list(); vector::const_iterator v_iter; ostringstream initializers; ostringstream appenders; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string fname = tmp(name); string ptr = is_numeric(etype) ? "*" : ""; generate_const_initializer(fname, etype, (*v_iter)); initializers << constant_value_with_storage(fname, (t_type*)etype, *v_iter); appenders << " g_hash_table_insert (constant, " << fname << ", 0);" << endl; } f_types_impl_ << maybe_static << "GHashTable *" << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl << indent() << "if (constant == NULL)" << endl; scope_up(f_types_impl_); f_types_impl_ << initializers.str() << endl << indent() << "constant = " << generate_new_hash_from_type(etype, nullptr) << endl << appenders.str(); scope_down(f_types_impl_); f_types_impl_ << indent() << "return constant;" << endl; scope_down(f_types_impl_); f_types_impl_ << endl; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; ostringstream initializers; ostringstream appenders; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string fname = tmp(name); string kname = fname + "key"; string vname = fname + "val"; generate_const_initializer(kname, ktype, v_iter->first); generate_const_initializer(vname, vtype, v_iter->second); initializers << constant_value_with_storage(kname, (t_type*)ktype, v_iter->first); initializers << constant_value_with_storage(vname, (t_type*)vtype, v_iter->second); appenders << " g_hash_table_insert (constant, " << kname << ", " << vname << ");" << endl; } f_types_impl_ << maybe_static << "GHashTable *" << endl << this->nspace_lc << name_lc << "_constant (void)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl << indent() << "if (constant == NULL)" << endl; scope_up(f_types_impl_); f_types_impl_ << initializers.str() << endl << indent() << "constant = " << generate_new_hash_from_type(ktype, vtype) << endl << appenders.str(); scope_down(f_types_impl_); f_types_impl_ << indent() << "return constant;" << endl; scope_down(f_types_impl_); f_types_impl_ << endl; } } /** * Generates helper classes for a service, consisting of a ThriftStruct subclass * for the arguments to and the result from each method. * * @param tservice The service for which to generate helper classes */ void t_c_glib_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator function_iter; // Iterate through the service's methods for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string function_name = (*function_iter)->get_name(); t_struct* arg_list = (*function_iter)->get_arglist(); string arg_list_name_orig = arg_list->get_name(); // Generate the arguments class arg_list->set_name(tservice->get_name() + underscores_to_initial_caps(function_name) + "Args"); generate_struct(arg_list); arg_list->set_name(arg_list_name_orig); // Generate the result class if (!(*function_iter)->is_oneway()) { t_struct result(program_, tservice->get_name() + underscores_to_initial_caps(function_name) + "Result"); t_field success((*function_iter)->get_returntype(), "success", 0); success.set_req(t_field::T_OPTIONAL); if (!(*function_iter)->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = (*function_iter)->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator field_iter; for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) { (*field_iter)->set_req(t_field::T_OPTIONAL); result.append(*field_iter); } generate_struct(&result); } } } /** * Generates C code that represents a Thrift service client. */ void t_c_glib_generator::generate_service_client(t_service* tservice) { /* get some C friendly service names */ string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_)); string service_name_uc = to_upper_case(service_name_lc); string parent_service_name; string parent_service_name_lc; string parent_service_name_uc; string parent_class_name = "GObject"; string parent_type_name = "G_TYPE_OBJECT"; // The service this service extends, or nullptr if it extends no // service t_service* extends_service = tservice->get_extends(); if (extends_service) { // The name of the parent service parent_service_name = extends_service->get_name(); parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name)); parent_service_name_uc = to_upper_case(parent_service_name_lc); // The names of the client class' parent class and type parent_class_name = this->nspace + parent_service_name + "Client"; parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_CLIENT"; } // The base service (the topmost in the "extends" hierarchy), on // whose client class the "input_protocol" and "output_protocol" // properties are defined t_service* base_service = tservice; while (base_service->get_extends()) { base_service = base_service->get_extends(); } string base_service_name = base_service->get_name(); string base_service_name_lc = to_lower_case(initial_caps_to_underscores(base_service_name)); string base_service_name_uc = to_upper_case(base_service_name_lc); // Generate the client interface dummy object in the header. f_header_ << "/* " << service_name_ << " service interface */" << endl << "typedef struct _" << this->nspace << service_name_ << "If " << this->nspace << service_name_ << "If; " << " /* dummy object */" << endl << endl; // Generate the client interface object in the header. f_header_ << "struct _" << this->nspace << service_name_ << "IfInterface" << endl << "{" << endl << " GTypeInterface parent;" << endl << endl; /* write out the functions for this interface */ indent_up(); vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { /* make the function name C friendly */ string funname = initial_caps_to_underscores((*f_iter)->get_name()); t_type* ttype = (*f_iter)->get_returntype(); t_struct* arglist = (*f_iter)->get_arglist(); t_struct* xlist = (*f_iter)->get_xceptions(); bool has_return = !ttype->is_void(); bool has_args = arglist->get_members().size() == 0; bool has_xceptions = xlist->get_members().size() == 0; string params = "(" + this->nspace + service_name_ + "If *iface" + (has_return ? ", " + type_name(ttype) + "* _return" : "") + (has_args ? "" : (", " + argument_list(arglist))) + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)"; indent(f_header_) << "gboolean (*" << funname << ") " << params << ";" << endl; } indent_down(); f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "IfInterface " << this->nspace << service_name_ << "IfInterface;" << endl << endl; // generate all the interface boilerplate f_header_ << "GType " << this->nspace_lc << service_name_lc << "_if_get_type (void);" << endl << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF " << "(" << this->nspace_lc << service_name_lc << "_if_get_type())" << endl << "#define " << this->nspace_uc << service_name_uc << "_IF(obj) " << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " << this->nspace << service_name_ << "If))" << endl << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_IF(obj) " << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF))" << endl << "#define " << this->nspace_uc << service_name_uc << "_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " << this->nspace << service_name_ << "IfInterface))" << endl << endl; // write out all the interface function prototypes for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { /* make the function name C friendly */ string funname = initial_caps_to_underscores((*f_iter)->get_name()); t_type* ttype = (*f_iter)->get_returntype(); t_struct* arglist = (*f_iter)->get_arglist(); t_struct* xlist = (*f_iter)->get_xceptions(); bool has_return = !ttype->is_void(); bool has_args = arglist->get_members().size() == 0; bool has_xceptions = xlist->get_members().size() == 0; string params = "(" + this->nspace + service_name_ + "If *iface" + (has_return ? ", " + type_name(ttype) + "* _return" : "") + (has_args ? "" : (", " + argument_list(arglist))) + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)"; f_header_ << "gboolean " << this->nspace_lc << service_name_lc << "_if_" << funname << " " << params << ";" << endl; } f_header_ << endl; // Generate the client object instance definition in the header. f_header_ << "/* " << service_name_ << " service client */" << endl << "struct _" << this->nspace << service_name_ << "Client" << endl << "{" << endl << " " << parent_class_name << " parent;" << endl; if (!extends_service) { // Define "input_protocol" and "output_protocol" properties only // for base services; child service-client classes will inherit // these f_header_ << endl << " ThriftProtocol *input_protocol;" << endl << " ThriftProtocol *output_protocol;" << endl; } f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "Client " << this->nspace << service_name_ << "Client;" << endl << endl; // Generate the class definition in the header. f_header_ << "struct _" << this->nspace << service_name_ << "ClientClass" << endl << "{" << endl << " " << parent_class_name << "Class parent;" << endl << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "ClientClass " << this->nspace << service_name_ << "ClientClass;" << endl << endl; // Create all the GObject boilerplate f_header_ << "GType " << this->nspace_lc << service_name_lc << "_client_get_type (void);" << endl << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT " << "(" << this->nspace_lc << service_name_lc << "_client_get_type())" << endl << "#define " << this->nspace_uc << service_name_uc << "_CLIENT(obj) " << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "Client))" << endl << "#define " << this->nspace_uc << service_name_uc << "_CLIENT_CLASS(c) " << "(G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))" << endl << "#define " << this->nspace_uc << service_name_uc << "_IS_CLIENT(obj) " << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT))" << endl << "#define " << this->nspace_uc << service_name_uc << "_IS_CLIENT_CLASS(c) " << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT))" << endl << "#define " << this->nspace_uc << service_name_uc << "_CLIENT_GET_CLASS(obj) " << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))" << endl << endl; /* write out the function prototypes */ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { /* make the function name C friendly */ string funname = to_lower_case(initial_caps_to_underscores((*f_iter)->get_name())); t_function service_function((*f_iter)->get_returntype(), service_name_lc + string("_client_") + funname, (*f_iter)->get_arglist(), (*f_iter)->get_xceptions()); indent(f_header_) << function_signature(&service_function) << ";" << endl; t_function send_function(g_type_void, service_name_lc + string("_client_send_") + funname, (*f_iter)->get_arglist()); indent(f_header_) << function_signature(&send_function) << ";" << endl; // implement recv if not a oneway service if (!(*f_iter)->is_oneway()) { t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), service_name_lc + string("_client_recv_") + funname, &noargs, (*f_iter)->get_xceptions()); indent(f_header_) << function_signature(&recv_function) << ";" << endl; } } /* write out the get/set function prototypes */ f_header_ << "void " + service_name_lc + "_client_set_property (GObject *object, guint " "property_id, const GValue *value, GParamSpec *pspec);" << endl; f_header_ << "void " + service_name_lc + "_client_get_property (GObject *object, guint " "property_id, GValue *value, GParamSpec *pspec);" << endl; f_header_ << endl; // end of header code // Generate interface method implementations for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { /* make the function name C friendly */ string funname = initial_caps_to_underscores((*f_iter)->get_name()); t_type* ttype = (*f_iter)->get_returntype(); t_struct* arglist = (*f_iter)->get_arglist(); t_struct* xlist = (*f_iter)->get_xceptions(); bool has_return = !ttype->is_void(); bool has_args = arglist->get_members().size() == 0; bool has_xceptions = xlist->get_members().size() == 0; string params = "(" + this->nspace + service_name_ + "If *iface" + (has_return ? ", " + type_name(ttype) + "* _return" : "") + (has_args ? "" : (", " + argument_list(arglist))) + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)"; string params_without_type = string("iface, ") + (has_return ? "_return, " : ""); const vector& fields = arglist->get_members(); vector::const_iterator f_iter_field; for (f_iter_field = fields.begin(); f_iter_field != fields.end(); ++f_iter_field) { params_without_type += (*f_iter_field)->get_name(); params_without_type += ", "; } const vector& xceptions = xlist->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { params_without_type += (*x_iter)->get_name(); params_without_type += ", "; } f_service_ << "gboolean" << endl << this->nspace_lc << service_name_lc << "_if_" << funname << " " << params << endl << "{" << endl << " return " << this->nspace_uc << service_name_uc << "_IF_GET_INTERFACE (iface)->" << funname << " (" << params_without_type << "error);" << endl << "}" << endl << endl; } // Generate interface boilerplate f_service_ << "GType" << endl << this->nspace_lc << service_name_lc << "_if_get_type (void)" << endl << "{" << endl << " static GType type = 0;" << endl << " if (type == 0)" << endl << " {" << endl << " static const GTypeInfo type_info =" << endl << " {" << endl << " sizeof (" << this->nspace << service_name_ << "IfInterface)," << endl << " NULL, /* base_init */" << endl << " NULL, /* base_finalize */" << endl << " NULL, /* class_init */" << endl << " NULL, /* class_finalize */" << endl << " NULL, /* class_data */" << endl << " 0, /* instance_size */" << endl << " 0, /* n_preallocs */" << endl << " NULL, /* instance_init */" << endl << " NULL /* value_table */" << endl << " };" << endl << " type = g_type_register_static (G_TYPE_INTERFACE," << endl << " \"" << this->nspace << service_name_ << "If\"," << endl << " &type_info, 0);" << endl << " }" << endl << " return type;" << endl << "}" << endl << endl; // Generate client boilerplate f_service_ << "static void " << endl << this->nspace_lc << service_name_lc << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);" << endl << endl << "G_DEFINE_TYPE_WITH_CODE (" << this->nspace << service_name_ << "Client, " << this->nspace_lc << service_name_lc << "_client," << endl << " " << parent_type_name << ", " << endl << " G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_" << service_name_uc << "_IF," << endl << " " << this->nspace_lc << service_name_lc << "_if_interface_init))" << endl << endl; // Generate property-related code only for base services---child // service-client classes have only properties inherited from their // parent class if (!extends_service) { // Generate client properties f_service_ << "enum _" << this->nspace << service_name_ << "ClientProperties" << endl << "{" << endl << " PROP_0," << endl << " PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL," << endl << " PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_OUTPUT_PROTOCOL" << endl << "};" << endl << endl; // generate property setter f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_set_property (" << "GObject *object, guint property_id, const GValue *value, " << "GParamSpec *pspec)" << endl << "{" << endl << " " << this->nspace << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc << "_CLIENT (object);" << endl << endl << " THRIFT_UNUSED_VAR (pspec);" << endl << endl << " switch (property_id)" << endl << " {" << endl << " case PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl << " client->input_protocol = g_value_get_object (value);" << endl << " break;" << endl << " case PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_OUTPUT_PROTOCOL:" << endl << " client->output_protocol = g_value_get_object (value);" << endl << " break;" << endl << " }" << endl << "}" << endl << endl; // generate property getter f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_get_property (" << "GObject *object, guint property_id, GValue *value, " << "GParamSpec *pspec)" << endl << "{" << endl << " " << this->nspace << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc << "_CLIENT (object);" << endl << endl << " THRIFT_UNUSED_VAR (pspec);" << endl << endl << " switch (property_id)" << endl << " {" << endl << " case PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl << " g_value_set_object (value, client->input_protocol);" << endl << " break;" << endl << " case PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_OUTPUT_PROTOCOL:" << endl << " g_value_set_object (value, client->output_protocol);" << endl << " break;" << endl << " }" << endl << "}" << endl << endl; } // Generate client method implementations for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string name = (*f_iter)->get_name(); string funname = initial_caps_to_underscores(name); // Get the struct of function call params and exceptions t_struct* arg_struct = (*f_iter)->get_arglist(); // Function for sending t_function send_function(g_type_void, service_name_lc + string("_client_send_") + funname, (*f_iter)->get_arglist()); // Open the send function indent(f_service_) << function_signature(&send_function) << endl; scope_up(f_service_); string reqType = (*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL"; // Serialize the request f_service_ << indent() << "gint32 cseqid = 0;" << endl << indent() << "ThriftProtocol * protocol = " << this->nspace_uc << base_service_name_uc << "_CLIENT (iface)->output_protocol;" << endl << endl << indent() << "if (thrift_protocol_write_message_begin (protocol, \"" << name << "\", " << reqType << ", cseqid, error) < 0)" << endl << indent() << " return FALSE;" << endl << endl; generate_struct_writer(f_service_, arg_struct, "", "", false); f_service_ << indent() << "if (thrift_protocol_write_message_end (protocol, error) < 0)" << endl << indent() << " return FALSE;" << endl << indent() << "if (!thrift_transport_flush (protocol->transport, error))" << endl << indent() << " return FALSE;" << endl << indent() << "if (!thrift_transport_write_end (protocol->transport, error))" << endl << indent() << " return FALSE;" << endl << endl << indent() << "return TRUE;" << endl; scope_down(f_service_); f_service_ << endl; // Generate recv function only if not an async function if (!(*f_iter)->is_oneway()) { t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), service_name_lc + string("_client_recv_") + funname, &noargs, (*f_iter)->get_xceptions()); // Open function indent(f_service_) << function_signature(&recv_function) << endl; scope_up(f_service_); f_service_ << indent() << "gint32 rseqid;" << endl << indent() << "gchar * fname = NULL;" << endl << indent() << "ThriftMessageType mtype;" << endl << indent() << "ThriftProtocol * protocol = " << this->nspace_uc << base_service_name_uc << "_CLIENT (iface)->input_protocol;" << endl << indent() << "ThriftApplicationException *xception;" << endl << endl << indent() << "if (thrift_protocol_read_message_begin " "(protocol, &fname, &mtype, &rseqid, error) < 0) {" << endl; indent_up(); f_service_ << indent() << "if (fname) g_free (fname);" << endl << indent() << "return FALSE;" << endl; indent_down(); f_service_ << indent() << "}" << endl << endl << indent() << "if (mtype == T_EXCEPTION) {" << endl; indent_up(); f_service_ << indent() << "if (fname) g_free (fname);" << endl << indent() << "xception = g_object_new " "(THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);" << endl << indent() << "thrift_struct_read (THRIFT_STRUCT (xception), " "protocol, NULL);" << endl << indent() << "thrift_protocol_read_message_end " "(protocol, NULL);" << endl << indent() << "thrift_transport_read_end " "(protocol->transport, NULL);" << endl << indent() << "g_set_error (error, " "THRIFT_APPLICATION_EXCEPTION_ERROR,xception->type, " "\"application error: %s\", xception->message);" << endl << indent() << "g_object_unref (xception);" << endl << indent() << "return FALSE;" << endl; indent_down(); f_service_ << indent() << "} else if (mtype != T_REPLY) {" << endl; indent_up(); f_service_ << indent() << "if (fname) g_free (fname);" << endl << indent() << "thrift_protocol_skip (protocol, T_STRUCT, " "NULL);" << endl << indent() << "thrift_protocol_read_message_end (protocol, " "NULL);" << endl << indent() << "thrift_transport_read_end (" "protocol->transport, NULL);" << endl << indent() << "g_set_error (error, " "THRIFT_APPLICATION_EXCEPTION_ERROR, " "THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE, " "\"invalid message type %d, expected T_REPLY\", mtype);" << endl << indent() << "return FALSE;" << endl; indent_down(); f_service_ << indent() << "} else if (strncmp (fname, \"" << name << "\", " << name.length() << ") != 0) {" << endl; indent_up(); f_service_ << indent() << "thrift_protocol_skip (protocol, T_STRUCT, " "NULL);" << endl << indent() << "thrift_protocol_read_message_end (protocol," "error);" << endl << indent() << "thrift_transport_read_end (" "protocol->transport, error);" << endl << indent() << "g_set_error (error, " "THRIFT_APPLICATION_EXCEPTION_ERROR, " "THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME, " "\"wrong method name %s, expected " << name << "\", fname);" << endl << indent() << "if (fname) g_free (fname);" << endl << indent() << "return FALSE;" << endl; indent_down(); f_service_ << indent() << "}" << endl << indent() << "if (fname) g_free (fname);" << endl << endl; t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; { t_struct result(program_, tservice->get_name() + "_" + (*f_iter)->get_name() + "_result"); t_field success((*f_iter)->get_returntype(), "*_return", 0); if (!(*f_iter)->get_returntype()->is_void()) { result.append(&success); } // add readers for exceptions, dereferencing the pointer. for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) { t_field* xception = new t_field((*x_iter)->get_type(), "*" + (*x_iter)->get_name(), (*x_iter)->get_key()); result.append(xception); } generate_struct_reader(f_service_, &result, "", "", false); } f_service_ << indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)" << endl << indent() << " return FALSE;" << endl << endl << indent() << "if (!thrift_transport_read_end (protocol->transport, error))" << endl << indent() << " return FALSE;" << endl << endl; // copy over any throw exceptions and return failure for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) { f_service_ << indent() << "if (*" << (*x_iter)->get_name() << " != NULL)" << endl << indent() << "{" << endl << indent() << " g_set_error (error, " << this->nspace_uc << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name())) << "_ERROR, " << this->nspace_uc << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name())) << "_ERROR_CODE, \"" << (*x_iter)->get_type()->get_name() << "\");" << endl << indent() << " return FALSE;" << endl << indent() << "}" << endl; } // Close function indent(f_service_) << "return TRUE;" << endl; scope_down(f_service_); f_service_ << endl; } // Open function t_function service_function((*f_iter)->get_returntype(), service_name_lc + string("_client_") + funname, (*f_iter)->get_arglist(), (*f_iter)->get_xceptions()); indent(f_service_) << function_signature(&service_function) << endl; scope_up(f_service_); // wrap each function f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_send_" << funname << " (iface"; // Declare the function arguments const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << ", " << (*fld_iter)->get_name(); } f_service_ << ", error))" << endl << indent() << " return FALSE;" << endl; // if not oneway, implement recv if (!(*f_iter)->is_oneway()) { string ret = (*f_iter)->get_returntype()->is_void() ? "" : "_return, "; const vector& xceptions = (*f_iter)->get_xceptions()->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { ret += (*x_iter)->get_name(); ret += ", "; } f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_recv_" << funname << " (iface, " << ret << "error))" << endl << indent() << " return FALSE;" << endl; } // return TRUE which means all functions were called OK indent(f_service_) << "return TRUE;" << endl; scope_down(f_service_); f_service_ << endl; } // create the interface initializer f_service_ << "static void" << endl << this->nspace_lc << service_name_lc << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface)" << endl; scope_up(f_service_); if (functions.size() > 0) { for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { /* make the function name C friendly */ string funname = initial_caps_to_underscores((*f_iter)->get_name()); f_service_ << indent() << "iface->" << funname << " = " << this->nspace_lc << service_name_lc << "_client_" << funname << ";" << endl; } } else { f_service_ << indent() << "THRIFT_UNUSED_VAR (iface);" << endl; } scope_down(f_service_); f_service_ << endl; // create the client instance initializer f_service_ << "static void" << endl << this->nspace_lc << service_name_lc << "_client_init (" << this->nspace << service_name_ << "Client *client)" << endl; scope_up(f_service_); if (!extends_service) { f_service_ << indent() << "client->input_protocol = NULL;" << endl << indent() << "client->output_protocol = NULL;" << endl; } else { f_service_ << indent() << "THRIFT_UNUSED_VAR (client);" << endl; } scope_down(f_service_); f_service_ << endl; // create the client class initializer f_service_ << "static void" << endl << this->nspace_lc << service_name_lc << "_client_class_init (" << this->nspace << service_name_ << "ClientClass *cls)" << endl << "{" << endl; if (!extends_service) { f_service_ << " GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl << " GParamSpec *param_spec;" << endl << endl << " gobject_class->set_property = " << this->nspace_lc << service_name_lc << "_client_set_property;" << endl << " gobject_class->get_property = " << this->nspace_lc << service_name_lc << "_client_get_property;" << endl << endl << " param_spec = g_param_spec_object (\"input_protocol\"," << endl << " \"input protocol (construct)\"," << endl << " \"Set the client input protocol\"," << endl << " THRIFT_TYPE_PROTOCOL," << endl << " G_PARAM_READWRITE);" << endl << " g_object_class_install_property (gobject_class," << endl << " PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL, param_spec);" << endl << endl << " param_spec = g_param_spec_object (\"output_protocol\"," << endl << " \"output protocol (construct)\"," << endl << " \"Set the client output protocol\"," << endl << " THRIFT_TYPE_PROTOCOL," << endl << " G_PARAM_READWRITE);" << endl << " g_object_class_install_property (gobject_class," << endl << " PROP_" << this->nspace_uc << service_name_uc << "_CLIENT_OUTPUT_PROTOCOL, param_spec);" << endl; } else { f_service_ << " THRIFT_UNUSED_VAR (cls);" << endl; } f_service_ << "}" << endl << endl; } /** * Generates C code that represents a Thrift service handler. * * @param tservice The service for which to generate a handler. */ void t_c_glib_generator::generate_service_handler(t_service* tservice) { vector functions = tservice->get_functions(); vector::const_iterator function_iter; string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_)); string service_name_uc = to_upper_case(service_name_lc); string service_handler_name = service_name_ + "Handler"; string class_name = this->nspace + service_handler_name; string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_handler_name); string class_name_uc = to_upper_case(class_name_lc); string parent_class_name; string parent_type_name; string args_indent; // The service this service extends, or nullptr if it extends no service t_service* extends_service = tservice->get_extends(); // Determine the name of our parent service (if any) and the handler class' // parent class name and type if (extends_service) { string parent_service_name = extends_service->get_name(); string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name)); string parent_service_name_uc = to_upper_case(parent_service_name_lc); parent_class_name = this->nspace + parent_service_name + "Handler"; parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_HANDLER"; } else { parent_class_name = "GObject"; parent_type_name = "G_TYPE_OBJECT"; } // Generate the handler class' definition in the header file // Generate the handler instance definition f_header_ << "/* " << service_name_ << " handler (abstract base class) */" << endl << "struct _" << class_name << endl << "{" << endl; indent_up(); f_header_ << indent() << parent_class_name << " parent;" << endl; indent_down(); f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl << endl; // Generate the handler class definition, including its class members // (methods) f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl; indent_up(); f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl; for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string method_name = initial_caps_to_underscores((*function_iter)->get_name()); t_type* return_type = (*function_iter)->get_returntype(); t_struct* arg_list = (*function_iter)->get_arglist(); t_struct* x_list = (*function_iter)->get_xceptions(); bool has_return = !return_type->is_void(); bool has_args = arg_list->get_members().size() == 0; bool has_xceptions = x_list->get_members().size() == 0; string params = "(" + this->nspace + service_name_ + "If *iface" + (has_return ? ", " + type_name(return_type) + "* _return" : "") + (has_args ? "" : (", " + argument_list(arg_list))) + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)"; indent(f_header_) << "gboolean (*" << method_name << ") " << params << ";" << endl; } indent_down(); f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name << "Class;" << endl << endl; // Generate the remaining header boilerplate f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER " << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc << "(obj) " << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER, " << class_name << "))" << endl << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER(obj) " << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER))" << endl << "#define " << class_name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER_CLASS(c) " << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER))" << endl << "#define " << this->nspace_uc << service_name_uc << "_HANDLER_GET_CLASS(obj) " << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << endl; // Generate the handler class' method definitions for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string method_name = initial_caps_to_underscores((*function_iter)->get_name()); t_type* return_type = (*function_iter)->get_returntype(); t_struct* arg_list = (*function_iter)->get_arglist(); t_struct* x_list = (*function_iter)->get_xceptions(); bool has_return = !return_type->is_void(); bool has_args = arg_list->get_members().size() == 0; bool has_xceptions = x_list->get_members().size() == 0; string params = "(" + this->nspace + service_name_ + "If *iface" + (has_return ? ", " + type_name(return_type) + "* _return" : "") + (has_args ? "" : (", " + argument_list(arg_list))) + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)"; f_header_ << "gboolean " << class_name_lc << "_" << method_name << " " << params << ";" << endl; } f_header_ << endl; // Generate the handler's implementation in the implementation file // Generate the implementation boilerplate f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);" << endl << endl; args_indent = string(25, ' '); f_service_ << "G_DEFINE_TYPE_WITH_CODE (" << class_name << ", " << endl << args_indent << class_name_lc << "," << endl << args_indent << parent_type_name << "," << endl << args_indent << "G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_" << service_name_uc << "_IF," << endl; args_indent += string(23, ' '); f_service_ << args_indent << class_name_lc << "_" << service_name_lc << "_if_interface_init))" << endl << endl; // Generate the handler method implementations for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string function_name = (*function_iter)->get_name(); string method_name = initial_caps_to_underscores(function_name); t_type* return_type = (*function_iter)->get_returntype(); t_struct* arg_list = (*function_iter)->get_arglist(); t_struct* x_list = (*function_iter)->get_xceptions(); const vector& args = arg_list->get_members(); const vector& xceptions = x_list->get_members(); vector::const_iterator field_iter; t_function implementing_function(return_type, service_name_lc + "_handler_" + method_name, arg_list, x_list, (*function_iter)->is_oneway()); indent(f_service_) << function_signature(&implementing_function) << endl; scope_up(f_service_); f_service_ << indent() << "g_return_val_if_fail (" << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER (iface), FALSE);" << endl << endl << indent() << "return " << class_name_uc << "_GET_CLASS (iface)" << "->" << method_name << " (iface, "; if (!return_type->is_void()) { f_service_ << "_return, "; } for (field_iter = args.begin(); field_iter != args.end(); ++field_iter) { f_service_ << (*field_iter)->get_name() << ", "; } for (field_iter = xceptions.begin(); field_iter != xceptions.end(); ++field_iter) { f_service_ << (*field_iter)->get_name() << ", "; } f_service_ << "error);" << endl; scope_down(f_service_); f_service_ << endl; } // Generate the handler interface initializer f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface)" << endl; scope_up(f_service_); if (functions.size() > 0) { for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string method_name = initial_caps_to_underscores((*function_iter)->get_name()); f_service_ << indent() << "iface->" << method_name << " = " << class_name_lc << "_" << method_name << ";" << endl; } } else { f_service_ << "THRIFT_UNUSED_VAR (iface);" << endl; } scope_down(f_service_); f_service_ << endl; // Generate the handler instance initializer f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)" << endl; scope_up(f_service_); f_service_ << indent() << "THRIFT_UNUSED_VAR (self);" << endl; scope_down(f_service_); f_service_ << endl; // Generate the handler class initializer f_service_ << "static void" << endl << class_name_lc << "_class_init (" << class_name << "Class *cls)" << endl; scope_up(f_service_); if (functions.size() > 0) { for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string function_name = (*function_iter)->get_name(); string method_name = initial_caps_to_underscores(function_name); // All methods are pure virtual and must be implemented by subclasses f_service_ << indent() << "cls->" << method_name << " = NULL;" << endl; } } else { f_service_ << indent() << "THRIFT_UNUSED_VAR (cls);" << endl; } scope_down(f_service_); f_service_ << endl; } /** * Generates C code that represents a Thrift service processor. * * @param tservice The service for which to generate a processor */ void t_c_glib_generator::generate_service_processor(t_service* tservice) { vector functions = tservice->get_functions(); vector::const_iterator function_iter; string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_)); string service_name_uc = to_upper_case(service_name_lc); string service_processor_name = service_name_ + "Processor"; string class_name = this->nspace + service_processor_name; string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_processor_name); string class_name_uc = to_upper_case(class_name_lc); string parent_class_name; string parent_type_name; string handler_class_name = this->nspace + service_name_ + "Handler"; string handler_class_name_lc = initial_caps_to_underscores(handler_class_name); string process_function_type_name = class_name + "ProcessFunction"; string process_function_def_type_name = class_name_lc + "_process_function_def"; string function_name; string args_indent; // The service this service extends, or nullptr if it extends no service t_service* extends_service = tservice->get_extends(); // Determine the name of our parent service (if any) and the // processor class' parent class name and type if (extends_service) { string parent_service_name = extends_service->get_name(); string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name)); string parent_service_name_uc = to_upper_case(parent_service_name_lc); parent_class_name = this->nspace + parent_service_name + "Processor"; parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_PROCESSOR"; } else { parent_class_name = "ThriftDispatchProcessor"; parent_type_name = "THRIFT_TYPE_DISPATCH_PROCESSOR"; } // Generate the processor class' definition in the header file // Generate the processor instance definition f_header_ << "/* " << service_name_ << " processor */" << endl << "struct _" << class_name << endl << "{" << endl; indent_up(); f_header_ << indent() << parent_class_name << " parent;" << endl << endl << indent() << "/* protected */" << endl << indent() << this->nspace + service_name_ + "Handler *handler;" << endl << indent() << "GHashTable *process_map;" << endl; indent_down(); f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl << endl; // Generate the processor class definition f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl; indent_up(); f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl << indent() << "/* protected */" << endl << indent() << "gboolean (*dispatch_call) (ThriftDispatchProcessor *processor," << endl; args_indent = indent() + string(27, ' '); f_header_ << args_indent << "ThriftProtocol *in," << endl << args_indent << "ThriftProtocol *out," << endl << args_indent << "gchar *fname," << endl << args_indent << "gint32 seqid," << endl << args_indent << "GError **error);" << endl; indent_down(); f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name << "Class;" << endl << endl; // Generate the remaining header boilerplate f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR " << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc << "(obj) " << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR, " << class_name << "))" << endl << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR(obj) " << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR))" << endl << "#define " << class_name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR_CLASS(c) " << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR))" << endl << "#define " << this->nspace_uc << service_name_uc << "_PROCESSOR_GET_CLASS(obj) " << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << endl; // Generate the processor's implementation in the implementation file // Generate the processor's properties enum f_service_ << "enum _" << class_name << "Properties" << endl << "{" << endl; indent_up(); f_service_ << indent() << "PROP_" << class_name_uc << "_0," << endl << indent() << "PROP_" << class_name_uc << "_HANDLER" << endl; indent_down(); f_service_ << "};" << endl << endl; // Generate the implementation boilerplate args_indent = string(15, ' '); f_service_ << "G_DEFINE_TYPE (" << class_name << "," << endl << args_indent << class_name_lc << "," << endl << args_indent << parent_type_name << ")" << endl << endl; // Generate the processor's processing-function type args_indent = string(process_function_type_name.length() + 23, ' '); f_service_ << "typedef gboolean (* " << process_function_type_name << ") (" << class_name << " *, " << endl << args_indent << "gint32," << endl << args_indent << "ThriftProtocol *," << endl << args_indent << "ThriftProtocol *," << endl << args_indent << "GError **);" << endl << endl; // Generate the processor's processing-function-definition type f_service_ << "typedef struct" << endl << "{" << endl; indent_up(); f_service_ << indent() << "gchar *name;" << endl << indent() << process_function_type_name << " function;" << endl; indent_down(); f_service_ << "} " << process_function_def_type_name << ";" << endl << endl; // Generate forward declarations of the processor's processing functions so we // can refer to them in the processing-function-definition struct below and // keep all of the processor's declarations in one place for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { function_name = class_name_lc + "_process_" + initial_caps_to_underscores((*function_iter)->get_name()); args_indent = string(function_name.length() + 2, ' '); f_service_ << "static gboolean" << endl << function_name << " (" << class_name << " *," << endl << args_indent << "gint32," << endl << args_indent << "ThriftProtocol *," << endl << args_indent << "ThriftProtocol *," << endl << args_indent << "GError **);" << endl; } f_service_ << endl; // Generate the processor's processing-function definitions, if the service // defines any methods if (functions.size() > 0) { f_service_ << indent() << "static " << process_function_def_type_name << endl << indent() << class_name_lc << "_process_function_defs[" << functions.size() << "] = {" << endl; indent_up(); for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string service_function_name = (*function_iter)->get_name(); string process_function_name = class_name_lc + "_process_" + initial_caps_to_underscores(service_function_name); f_service_ << indent() << "{" << endl; indent_up(); f_service_ << indent() << "\"" << service_function_name << "\"," << endl << indent() << process_function_name << endl; indent_down(); f_service_ << indent() << "}" << (function_iter == --functions.end() ? "" : ",") << endl; } indent_down(); f_service_ << indent() << "};" << endl << endl; } // Generate the processor's processing functions for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) { string service_function_name = (*function_iter)->get_name(); string service_function_name_ic = underscores_to_initial_caps(service_function_name); string service_function_name_lc = initial_caps_to_underscores(service_function_name); string service_function_name_uc = to_upper_case(service_function_name_lc); t_type* return_type = (*function_iter)->get_returntype(); bool has_return_value = !return_type->is_void(); t_struct* arg_list = (*function_iter)->get_arglist(); const vector& args = arg_list->get_members(); vector::const_iterator arg_iter; const vector& xceptions = (*function_iter)->get_xceptions()->get_members(); vector::const_iterator xception_iter; string args_class_name = this->nspace + service_name_ + service_function_name_ic + "Args"; string args_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_" + service_function_name_uc + "_ARGS"; string result_class_name = this->nspace + service_name_ + service_function_name_ic + "Result"; string result_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_" + service_function_name_uc + "_RESULT"; string handler_function_name = handler_class_name_lc + "_" + service_function_name_lc; function_name = class_name_lc + "_process_" + initial_caps_to_underscores(service_function_name); args_indent = string(function_name.length() + 2, ' '); f_service_ << "static gboolean" << endl << function_name << " (" << class_name << " *self," << endl << args_indent << "gint32 sequence_id," << endl << args_indent << "ThriftProtocol *input_protocol," << endl << args_indent << "ThriftProtocol *output_protocol," << endl << args_indent << "GError **error)" << endl; scope_up(f_service_); f_service_ << indent() << "gboolean result = TRUE;" << endl << indent() << "ThriftTransport * transport;" << endl << indent() << "ThriftApplicationException *xception;" << endl << indent() << args_class_name + " * args =" << endl; indent_up(); f_service_ << indent() << "g_object_new (" << args_class_type << ", NULL);" << endl << endl; indent_down(); if ((*function_iter)->is_oneway()) { f_service_ << indent() << "THRIFT_UNUSED_VAR (sequence_id);" << endl << indent() << "THRIFT_UNUSED_VAR (output_protocol);" << endl << endl; } f_service_ << indent() << "g_object_get (input_protocol, \"transport\", " << "&transport, NULL);" << endl << endl; // Read the method's arguments from the caller f_service_ << indent() << "if ((thrift_struct_read (THRIFT_STRUCT (args), " << "input_protocol, error) != -1) &&" << endl << indent() << " (thrift_protocol_read_message_end (input_protocol, " << "error) != -1) &&" << endl << indent() << " (thrift_transport_read_end (transport, error) != FALSE))" << endl; scope_up(f_service_); for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { f_service_ << indent() << property_type_name((*arg_iter)->get_type()) << " " << (*arg_iter)->get_name() << ";" << endl; } for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) { f_service_ << indent() << type_name((*xception_iter)->get_type()) << " " << initial_caps_to_underscores((*xception_iter)->get_name()) << " = NULL;" << endl; } if (has_return_value) { f_service_ << indent() << property_type_name(return_type) << " return_value;" << endl; } if (!(*function_iter)->is_oneway()) { f_service_ << indent() << result_class_name << " * result_struct;" << endl; } f_service_ << endl; if (args.size() > 0) { f_service_ << indent() << "g_object_get (args," << endl; args_indent = indent() + string(14, ' '); for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { string arg_name = (*arg_iter)->get_name(); f_service_ << args_indent << "\"" << arg_name << "\", &" << arg_name << "," << endl; } f_service_ << args_indent << "NULL);" << endl << endl; } if (!(*function_iter)->is_oneway()) { f_service_ << indent() << "g_object_unref (transport);" << endl << indent() << "g_object_get (output_protocol, \"transport\", " << "&transport, NULL);" << endl << endl << indent() << "result_struct = g_object_new (" << result_class_type << ", NULL);" << endl; if (has_return_value) { f_service_ << indent() << "g_object_get (result_struct, " "\"success\", &return_value, NULL);" << endl; } f_service_ << endl; } // Pass the arguments to the corresponding method in the handler f_service_ << indent() << "if (" << handler_function_name << " (" << this->nspace_uc << service_name_uc << "_IF (self->handler)," << endl; args_indent = indent() + string(handler_function_name.length() + 6, ' '); if (has_return_value) { string return_type_name = type_name(return_type); f_service_ << args_indent; // Cast return_value if it was declared as a type other than the return // value's actual type---this is true for integer values 32 bits or fewer // in width, for which GLib requires a plain gint type be used when // storing or retrieving as an object property if (return_type_name != property_type_name(return_type)) { if (return_type_name[return_type_name.length() - 1] != '*') { return_type_name += ' '; } return_type_name += '*'; f_service_ << "(" << return_type_name << ")"; } f_service_ << "&return_value," << endl; } for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { f_service_ << args_indent << (*arg_iter)->get_name() << "," << endl; } for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) { f_service_ << args_indent << "&" << initial_caps_to_underscores((*xception_iter)->get_name()) << "," << endl; } f_service_ << args_indent << "error) == TRUE)" << endl; scope_up(f_service_); // The handler reported success; return the result, if any, to the caller if (!(*function_iter)->is_oneway()) { if (has_return_value) { f_service_ << indent() << "g_object_set (result_struct, \"success\", "; if (type_name(return_type) != property_type_name(return_type)) { // Roundtrip cast to fix the position of sign bit. f_service_ << "(" << property_type_name(return_type) << ")" << "(" << type_name(return_type) << ")"; } f_service_ << "return_value, " << "NULL);" << endl; f_service_ << endl; } f_service_ << indent() << "result =" << endl; indent_up(); f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; args_indent = indent() + string(39, ' '); f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent << "error) != -1) &&" << endl << indent() << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl; args_indent = indent() + string(23, ' '); f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));" << endl; indent_down(); } scope_down(f_service_); f_service_ << indent() << "else" << endl; scope_up(f_service_); // The handler reported failure; check to see if an application-defined // exception was raised and if so, return it to the caller f_service_ << indent(); if (xceptions.size() > 0) { for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) { f_service_ << "if (" << initial_caps_to_underscores((*xception_iter)->get_name()) << " != NULL)" << endl; scope_up(f_service_); f_service_ << indent() << "g_object_set (result_struct," << endl; args_indent = indent() + string(14, ' '); f_service_ << args_indent << "\"" << (*xception_iter)->get_name() << "\", " << (*xception_iter)->get_name() << "," << endl << args_indent << "NULL);" << endl << endl; f_service_ << indent() << "g_object_unref ("<< (*xception_iter)->get_name() <<");"<< endl; f_service_ << indent() << "result =" << endl; indent_up(); f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; args_indent = indent() + string(39, ' '); f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent << "error) != -1) &&" << endl << indent() << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl; args_indent = indent() + string(23, ' '); f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));" << endl; indent_down(); scope_down(f_service_); f_service_ << indent() << "else" << endl; } scope_up(f_service_); f_service_ << indent(); } // If the handler reported failure but raised no application-defined // exception, return a Thrift application exception with the information // returned via GLib's own error-reporting mechanism f_service_ << "if (*error == NULL)" << endl; indent_up(); f_service_ << indent() << "g_warning (\"" << service_name_ << "." << (*function_iter)->get_name() << " implementation returned FALSE \"" << endl << indent() << string(11, ' ') << "\"but did not set an error\");" << endl << endl; indent_down(); f_service_ << indent() << "xception =" << endl; indent_up(); f_service_ << indent() << "g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION," << endl; args_indent = indent() + string(14, ' '); f_service_ << args_indent << "\"type\", *error != NULL ? (*error)->code :" << endl << args_indent << string(11, ' ') << "THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN," << endl << args_indent << "\"message\", *error != NULL ? (*error)->message : NULL," << endl << args_indent << "NULL);" << endl; indent_down(); f_service_ << indent() << "g_clear_error (error);" << endl << endl << indent() << "result =" << endl; indent_up(); f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; args_indent = indent() + string(39, ' '); f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent << "T_EXCEPTION," << endl << args_indent << "sequence_id," << endl << args_indent << "error) != -1) &&" << endl << indent() << " (thrift_struct_write (THRIFT_STRUCT (xception)," << endl; args_indent = indent() + string(23, ' '); f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));" << endl; indent_down(); f_service_ << endl << indent() << "g_object_unref (xception);" << endl; if (xceptions.size() > 0) { scope_down(f_service_); } scope_down(f_service_); f_service_ << endl; // Dellocate or unref retrieved argument values as necessary for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { string arg_name = (*arg_iter)->get_name(); t_type* arg_type = get_true_type((*arg_iter)->get_type()); if (arg_type->is_base_type()) { t_base_type* base_type = ((t_base_type*)arg_type); if (base_type->get_base() == t_base_type::TYPE_STRING) { f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl; indent_up(); if (base_type->is_binary()) { f_service_ << indent() << "g_byte_array_unref (" << arg_name << ");" << endl; } else { f_service_ << indent() << "g_free (" << arg_name << ");" << endl; } indent_down(); } } else if (arg_type->is_container()) { f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl; indent_up(); if (arg_type->is_list()) { t_type* elem_type = ((t_list*)arg_type)->get_elem_type(); f_service_ << indent(); if (is_numeric(elem_type)) { f_service_ << "g_array_unref"; } else { f_service_ << "g_ptr_array_unref"; } f_service_ << " (" << arg_name << ");" << endl; } else if (arg_type->is_map() || arg_type->is_set()) { f_service_ << indent() << "g_hash_table_unref (" << arg_name << ");" << endl; } indent_down(); } else if (arg_type->is_struct()) { f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl; indent_up(); f_service_ << indent() << "g_object_unref (" << arg_name << ");" << endl; indent_down(); } } if (!(*function_iter)->is_oneway()) { if (has_return_value) { // Deallocate (or unref) return_value return_type = get_true_type(return_type); if (return_type->is_base_type()) { t_base_type* base_type = ((t_base_type*)return_type); if (base_type->get_base() == t_base_type::TYPE_STRING) { f_service_ << indent() << "if (return_value != NULL)" << endl; indent_up(); if (base_type->is_binary()) { f_service_ << indent() << "g_byte_array_unref (return_value);" << endl; } else { f_service_ << indent() << "g_free (return_value);" << endl; } indent_down(); } } else if (return_type->is_container()) { f_service_ << indent() << "if (return_value != NULL)" << endl; indent_up(); if (return_type->is_list()) { t_type* elem_type = ((t_list*)return_type)->get_elem_type(); f_service_ << indent(); if (is_numeric(elem_type)) { f_service_ << "g_array_unref"; } else { f_service_ << "g_ptr_array_unref"; } f_service_ << " (return_value);" << endl; } else if (return_type->is_map() || return_type->is_set()) { f_service_ << indent() << "g_hash_table_unref (return_value);" << endl; } indent_down(); } else if (return_type->is_struct()) { f_service_ << indent() << "if (return_value != NULL)" << endl; indent_up(); f_service_ << indent() << "g_object_unref (return_value);" << endl; indent_down(); } } f_service_ << indent() << "g_object_unref (result_struct);" << endl << endl << indent() << "if (result == TRUE)" << endl; indent_up(); f_service_ << indent() << "result =" << endl; indent_up(); f_service_ << indent() << "((thrift_protocol_write_message_end " << "(output_protocol, error) != -1) &&" << endl << indent() << " (thrift_transport_write_end (transport, error) " << "!= FALSE) &&" << endl << indent() << " (thrift_transport_flush (transport, error) " << "!= FALSE));" << endl; indent_down(); indent_down(); } scope_down(f_service_); f_service_ << indent() << "else" << endl; indent_up(); f_service_ << indent() << "result = FALSE;" << endl; indent_down(); f_service_ << endl << indent() << "g_object_unref (transport);" << endl << indent() << "g_object_unref (args);" << endl << endl << indent() << "return result;" << endl; scope_down(f_service_); f_service_ << endl; } // Generate the processor's dispatch_call implementation function_name = class_name_lc + "_dispatch_call"; args_indent = indent() + string(function_name.length() + 2, ' '); f_service_ << "static gboolean" << endl << function_name << " (ThriftDispatchProcessor *dispatch_processor," << endl << args_indent << "ThriftProtocol *input_protocol," << endl << args_indent << "ThriftProtocol *output_protocol," << endl << args_indent << "gchar *method_name," << endl << args_indent << "gint32 sequence_id," << endl << args_indent << "GError **error)" << endl; scope_up(f_service_); f_service_ << indent() << class_name_lc << "_process_function_def *" << "process_function_def;" << endl; f_service_ << indent() << "gboolean dispatch_result = FALSE;" << endl << endl << indent() << class_name << " *self = " << class_name_uc << " (dispatch_processor);" << endl; f_service_ << indent() << parent_class_name << "Class " "*parent_class =" << endl; indent_up(); f_service_ << indent() << "g_type_class_peek_parent (" << class_name_uc << "_GET_CLASS (self));" << endl; indent_down(); f_service_ << endl << indent() << "process_function_def = " << "g_hash_table_lookup (self->process_map, method_name);" << endl << indent() << "if (process_function_def != NULL)" << endl; scope_up(f_service_); args_indent = indent() + string(53, ' '); f_service_ << indent() << "g_free (method_name);" << endl << indent() << "dispatch_result = " << "(*process_function_def->function) (self," << endl << args_indent << "sequence_id," << endl << args_indent << "input_protocol," << endl << args_indent << "output_protocol," << endl << args_indent << "error);" << endl; scope_down(f_service_); f_service_ << indent() << "else" << endl; scope_up(f_service_); // Method name not recognized; chain up to our parent processor---note the // top-most implementation of this method, in ThriftDispatchProcessor itself, // will return an application exception to the caller if no class in the // hierarchy recognizes the method name f_service_ << indent() << "dispatch_result = parent_class->dispatch_call " "(dispatch_processor," << endl; args_indent = indent() + string(47, ' '); f_service_ << args_indent << "input_protocol," << endl << args_indent << "output_protocol," << endl << args_indent << "method_name," << endl << args_indent << "sequence_id," << endl << args_indent << "error);" << endl; scope_down(f_service_); f_service_ << endl << indent() << "return dispatch_result;" << endl; scope_down(f_service_); f_service_ << endl; // Generate the processor's property setter function_name = class_name_lc + "_set_property"; args_indent = string(function_name.length() + 2, ' '); f_service_ << "static void" << endl << function_name << " (GObject *object," << endl << args_indent << "guint property_id," << endl << args_indent << "const GValue *value," << endl << args_indent << "GParamSpec *pspec)" << endl; scope_up(f_service_); f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl << endl << indent() << "switch (property_id)" << endl; scope_up(f_service_); f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl; indent_up(); f_service_ << indent() << "if (self->handler != NULL)" << endl; indent_up(); f_service_ << indent() << "g_object_unref (self->handler);" << endl; indent_down(); f_service_ << indent() << "self->handler = g_value_get_object (value);" << endl << indent() << "g_object_ref (self->handler);" << endl; if (extends_service) { // Chain up to set the handler in every superclass as well f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)->" << endl; indent_up(); f_service_ << indent() << "set_property (object, property_id, value, pspec);" << endl; indent_down(); } f_service_ << indent() << "break;" << endl; indent_down(); f_service_ << indent() << "default:" << endl; indent_up(); f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" << endl << indent() << "break;" << endl; indent_down(); scope_down(f_service_); scope_down(f_service_); f_service_ << endl; // Generate processor's property getter function_name = class_name_lc + "_get_property"; args_indent = string(function_name.length() + 2, ' '); f_service_ << "static void" << endl << function_name << " (GObject *object," << endl << args_indent << "guint property_id," << endl << args_indent << "GValue *value," << endl << args_indent << "GParamSpec *pspec)" << endl; scope_up(f_service_); f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl << endl << indent() << "switch (property_id)" << endl; scope_up(f_service_); f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl; indent_up(); f_service_ << indent() << "g_value_set_object (value, self->handler);" << endl << indent() << "break;" << endl; indent_down(); f_service_ << indent() << "default:" << endl; indent_up(); f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" << endl << indent() << "break;" << endl; indent_down(); scope_down(f_service_); scope_down(f_service_); f_service_ << endl; // Generator the processor's dispose function f_service_ << "static void" << endl << class_name_lc << "_dispose (GObject *gobject)" << endl; scope_up(f_service_); f_service_ << indent() << class_name << " *self = " << class_name_uc << " (gobject);" << endl << endl << indent() << "if (self->handler != NULL)" << endl; scope_up(f_service_); f_service_ << indent() << "g_object_unref (self->handler);" << endl << indent() << "self->handler = NULL;" << endl; scope_down(f_service_); f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)" "->dispose (gobject);" << endl; scope_down(f_service_); f_service_ << endl; // Generate processor finalize function f_service_ << "static void" << endl << class_name_lc << "_finalize (GObject *gobject)" << endl; scope_up(f_service_); f_service_ << indent() << this->nspace << service_name_ << "Processor *self = " << this->nspace_uc << service_name_uc << "_PROCESSOR (gobject);" << endl << endl << indent() << "thrift_safe_hash_table_destroy (self->process_map);" << endl << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)" "->finalize (gobject);" << endl; scope_down(f_service_); f_service_ << endl; // Generate processor instance initializer f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)" << endl; scope_up(f_service_); if (functions.size() > 0) { f_service_ << indent() << "guint index;" << endl << endl; } f_service_ << indent() << "self->handler = NULL;" << endl << indent() << "self->process_map = " "g_hash_table_new (g_str_hash, g_str_equal);" << endl; if (functions.size() > 0) { args_indent = string(21, ' '); f_service_ << endl << indent() << "for (index = 0; index < " << functions.size() << "; index += 1)" << endl; indent_up(); f_service_ << indent() << "g_hash_table_insert (self->process_map," << endl << indent() << args_indent << class_name_lc << "_process_function_defs[index].name," << endl << indent() << args_indent << "&" << class_name_lc << "_process_function_defs[index]" << ");" << endl; indent_down(); } scope_down(f_service_); f_service_ << endl; // Generate processor class initializer f_service_ << "static void" << endl << class_name_lc << "_class_init (" << class_name << "Class *cls)" << endl; scope_up(f_service_); f_service_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl << indent() << "ThriftDispatchProcessorClass *dispatch_processor_class =" << endl; indent_up(); f_service_ << indent() << "THRIFT_DISPATCH_PROCESSOR_CLASS (cls);" << endl; indent_down(); f_service_ << indent() << "GParamSpec *param_spec;" << endl << endl << indent() << "gobject_class->dispose = " << class_name_lc << "_dispose;" << endl << indent() << "gobject_class->finalize = " << class_name_lc << "_finalize;" << endl << indent() << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl << indent() << "gobject_class->get_property = " << class_name_lc << "_get_property;" << endl << endl << indent() << "dispatch_processor_class->dispatch_call = " << class_name_lc << "_dispatch_call;" << endl << indent() << "cls->dispatch_call = " << class_name_lc << "_dispatch_call;" << endl << endl << indent() << "param_spec = g_param_spec_object (\"handler\"," << endl; args_indent = indent() + string(34, ' '); f_service_ << args_indent << "\"Service handler implementation\"," << endl << args_indent << "\"The service handler implementation \"" << endl << args_indent << "\"to which method calls are dispatched.\"," << endl << args_indent << this->nspace_uc + "TYPE_" + service_name_uc + "_HANDLER," << endl << args_indent << "G_PARAM_READWRITE);" << endl; f_service_ << indent() << "g_object_class_install_property (gobject_class," << endl; args_indent = indent() + string(33, ' '); f_service_ << args_indent << "PROP_" << class_name_uc << "_HANDLER," << endl << args_indent << "param_spec);" << endl; scope_down(f_service_); } /** * Generates C code that represents a Thrift service server. */ void t_c_glib_generator::generate_service_server(t_service* tservice) { (void)tservice; // Generate the service's handler class generate_service_handler(tservice); // Generate the service's processor class generate_service_processor(tservice); } /** * Generates C code to represent a THrift structure as a GObject. */ void t_c_glib_generator::generate_object(t_struct* tstruct) { string name = tstruct->get_name(); string name_u = initial_caps_to_underscores(name); string name_uc = to_upper_case(name_u); string class_name = this->nspace + name; string class_name_lc = this->nspace_lc + initial_caps_to_underscores(name); string class_name_uc = to_upper_case(class_name_lc); string function_name; string args_indent; // write the instance definition f_types_ << "struct _" << this->nspace << name << endl << "{ " << endl << " ThriftStruct parent; " << endl << endl << " /* public */" << endl; // for each field, add a member variable vector::const_iterator m_iter; const vector& members = tstruct->get_members(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); f_types_ << " " << type_name(t) << " " << (*m_iter)->get_name() << ";" << endl; if ((*m_iter)->get_req() != t_field::T_REQUIRED) { f_types_ << " gboolean __isset_" << (*m_iter)->get_name() << ";" << endl; } } // close the structure definition and create a typedef f_types_ << "};" << endl << "typedef struct _" << this->nspace << name << " " << this->nspace << name << ";" << endl << endl; // write the class definition f_types_ << "struct _" << this->nspace << name << "Class" << endl << "{" << endl << " ThriftStructClass parent;" << endl << "};" << endl << "typedef struct _" << this->nspace << name << "Class " << this->nspace << name << "Class;" << endl << endl; // write the standard GObject boilerplate f_types_ << "GType " << this->nspace_lc << name_u << "_get_type (void);" << endl << "#define " << this->nspace_uc << "TYPE_" << name_uc << " (" << this->nspace_lc << name_u << "_get_type())" << endl << "#define " << this->nspace_uc << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "))" << endl << "#define " << this->nspace_uc << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "_TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl << "#define " << this->nspace_uc << "IS_" << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc << "IS_" << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc << name_uc << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl << endl; // start writing the object implementation .c file // generate properties enum if (members.size() > 0) { f_types_impl_ << "enum _" << class_name << "Properties" << endl << "{" << endl; indent_up(); f_types_impl_ << indent() << "PROP_" << class_name_uc << "_0"; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { string member_name_uc = to_upper_case(to_lower_case(initial_caps_to_underscores((*m_iter)->get_name()))); f_types_impl_ << "," << endl << indent() << "PROP_" << class_name_uc << "_" << member_name_uc; } f_types_impl_ << endl; indent_down(); f_types_impl_ << "};" << endl << endl; } // generate struct I/O methods string this_get = this->nspace + name + " * this_object = " + this->nspace_uc + name_uc + "(object);"; generate_struct_reader(f_types_impl_, tstruct, "this_object->", this_get); generate_struct_writer(f_types_impl_, tstruct, "this_object->", this_get); // generate property setter and getter if (members.size() > 0) { // generate property setter function_name = class_name_lc + "_set_property"; args_indent = string(function_name.length() + 2, ' '); f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl << args_indent << "guint property_id," << endl << args_indent << "const GValue *value," << endl << args_indent << "GParamSpec *pspec)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl << endl << indent() << "switch (property_id)" << endl; scope_up(f_types_impl_); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* member = (*m_iter); string member_name = member->get_name(); string member_name_uc = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name))); t_type* member_type = get_true_type(member->get_type()); string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc; f_types_impl_ << indent() << "case " << property_identifier + ":" << endl; indent_up(); if (member_type->is_base_type()) { t_base_type* base_type = ((t_base_type*)member_type); string assign_function_name; if (base_type->get_base() == t_base_type::TYPE_STRING) { string release_function_name; f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl; indent_up(); if (base_type->is_binary()) { release_function_name = "g_byte_array_unref"; assign_function_name = "g_value_dup_boxed"; } else { release_function_name = "g_free"; assign_function_name = "g_value_dup_string"; } f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");" << endl; indent_down(); } else { switch (base_type->get_base()) { case t_base_type::TYPE_BOOL: assign_function_name = "g_value_get_boolean"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: assign_function_name = "g_value_get_int"; break; case t_base_type::TYPE_I64: assign_function_name = "g_value_get_int64"; break; case t_base_type::TYPE_DOUBLE: assign_function_name = "g_value_get_double"; break; default: throw "compiler error: " "unrecognized base type \"" + base_type->get_name() + "\" " "for struct member \"" + member_name + "\""; break; } } f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name << " (value);" << endl; } else if (member_type->is_enum()) { f_types_impl_ << indent() << "self->" << member_name << " = g_value_get_int (value);" << endl; } else if (member_type->is_container()) { string release_function_name; string assign_function_name; if (member_type->is_list()) { t_type* elem_type = ((t_list*)member_type)->get_elem_type(); // Lists of base types other than strings are represented as GArrays; // all others as GPtrArrays if (is_numeric(elem_type)) { release_function_name = "g_array_unref"; } else { release_function_name = "g_ptr_array_unref"; } assign_function_name = "g_value_dup_boxed"; } else if (member_type->is_set() || member_type->is_map()) { release_function_name = "g_hash_table_unref"; assign_function_name = "g_value_dup_boxed"; } f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl; indent_up(); f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");" << endl; indent_down(); f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name << " (value);" << endl; } else if (member_type->is_struct() || member_type->is_xception()) { f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl; indent_up(); f_types_impl_ << indent() << "g_object_unref (self->" << member_name << ");" << endl; indent_down(); f_types_impl_ << indent() << "self->" << member_name << " = g_value_dup_object (value);" << endl; } if (member->get_req() != t_field::T_REQUIRED) { f_types_impl_ << indent() << "self->__isset_" << member_name << " = TRUE;" << endl; } f_types_impl_ << indent() << "break;" << endl << endl; indent_down(); } f_types_impl_ << indent() << "default:" << endl; indent_up(); f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" << endl << indent() << "break;" << endl; indent_down(); scope_down(f_types_impl_); scope_down(f_types_impl_); f_types_impl_ << endl; // generate property getter function_name = class_name_lc + "_get_property"; args_indent = string(function_name.length() + 2, ' '); f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl << args_indent << "guint property_id," << endl << args_indent << "GValue *value," << endl << args_indent << "GParamSpec *pspec)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl << endl << indent() << "switch (property_id)" << endl; scope_up(f_types_impl_); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* member = (*m_iter); string member_name = (*m_iter)->get_name(); string member_name_uc = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name))); t_type* member_type = get_true_type(member->get_type()); string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc; string setter_function_name; if (member_type->is_base_type()) { t_base_type* base_type = ((t_base_type*)member_type); switch (base_type->get_base()) { case t_base_type::TYPE_BOOL: setter_function_name = "g_value_set_boolean"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: setter_function_name = "g_value_set_int"; break; case t_base_type::TYPE_I64: setter_function_name = "g_value_set_int64"; break; case t_base_type::TYPE_DOUBLE: setter_function_name = "g_value_set_double"; break; case t_base_type::TYPE_STRING: if (base_type->is_binary()) { setter_function_name = "g_value_set_boxed"; } else { setter_function_name = "g_value_set_string"; } break; default: throw "compiler error: " "unrecognized base type \"" + base_type->get_name() + "\" " "for struct member \"" + member_name + "\""; break; } } else if (member_type->is_enum()) { setter_function_name = "g_value_set_int"; } else if (member_type->is_struct() || member_type->is_xception()) { setter_function_name = "g_value_set_object"; } else if (member_type->is_container()) { setter_function_name = "g_value_set_boxed"; } else { throw "compiler error: " "unrecognized type for struct member \"" + member_name + "\""; } f_types_impl_ << indent() << "case " << property_identifier + ":" << endl; indent_up(); f_types_impl_ << indent() << setter_function_name << " (value, self->" << member_name << ");" << endl << indent() << "break;" << endl << endl; indent_down(); } f_types_impl_ << indent() << "default:" << endl; indent_up(); f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" << endl << indent() << "break;" << endl; indent_down(); scope_down(f_types_impl_); scope_down(f_types_impl_); f_types_impl_ << endl; } // generate the instance init function f_types_impl_ << "static void " << endl << this->nspace_lc << name_u << "_instance_init (" << this->nspace << name << " * object)" << endl << "{" << endl; indent_up(); // generate default-value structures for container-type members bool constant_declaration_output = false; bool string_list_constant_output = false; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* member = *m_iter; t_const_value* member_value = member->get_value(); if (member_value != nullptr) { string member_name = member->get_name(); t_type* member_type = get_true_type(member->get_type()); if (member_type->is_list()) { const vector& list = member_value->get_list(); t_type* elem_type = ((t_list*)member_type)->get_elem_type(); // Generate an array with the list literal indent(f_types_impl_) << "static " << type_name(elem_type, false, true) << " __default_" << member_name << "[" << list.size() << "] = " << endl; indent_up(); f_types_impl_ << indent() << constant_literal(member_type, member_value) << ";" << endl; indent_down(); constant_declaration_output = true; // If we are generating values for a pointer array (i.e. a list of // strings), set a flag so we know to also declare an index variable to // use in pre-populating the array if (elem_type->is_string()) { string_list_constant_output = true; } } // TODO: Handle container types other than list } } if (constant_declaration_output) { if (string_list_constant_output) { indent(f_types_impl_) << "unsigned int list_index;" << endl; } f_types_impl_ << endl; } // satisfy compilers with -Wall turned on indent(f_types_impl_) << "/* satisfy -Wall */" << endl << indent() << "THRIFT_UNUSED_VAR (object);" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* member_type = (*m_iter)->get_type(); t_type* t = get_true_type(member_type); if (t->is_base_type()) { string dval = " = "; if (t->is_enum()) { dval += "(" + type_name(t) + ")"; } t_const_value* cv = (*m_iter)->get_value(); if (cv != nullptr) { dval += constant_value("", t, cv); } else { dval += t->is_string() ? "NULL" : "0"; } indent(f_types_impl_) << "object->" << (*m_iter)->get_name() << dval << ";" << endl; } else if (t->is_struct()) { string name = (*m_iter)->get_name(); t_program* type_program = member_type->get_program(); string type_nspace = type_program ? type_program->get_namespace("c_glib") : ""; string type_nspace_prefix = type_nspace.empty() ? "" : initial_caps_to_underscores(type_nspace) + "_"; string type_name_uc = to_upper_case(initial_caps_to_underscores(member_type->get_name())); indent(f_types_impl_) << "object->" << name << " = g_object_new (" << to_upper_case(type_nspace_prefix) << "TYPE_" << type_name_uc << ", NULL);" << endl; } else if (t->is_xception()) { string name = (*m_iter)->get_name(); indent(f_types_impl_) << "object->" << name << " = NULL;" << endl; } else if (t->is_container()) { string name = (*m_iter)->get_name(); string init_function; t_type* etype = nullptr; if (t->is_map()) { t_type* key = ((t_map*)t)->get_key_type(); t_type* value = ((t_map*)t)->get_val_type(); init_function = generate_new_hash_from_type(key, value); } else if (t->is_set()) { etype = ((t_set*)t)->get_elem_type(); init_function = generate_new_hash_from_type(etype, nullptr); } else if (t->is_list()) { etype = ((t_list*)t)->get_elem_type(); init_function = generate_new_array_from_type(etype); } indent(f_types_impl_) << "object->" << name << " = " << init_function << endl; // Pre-populate the container with the specified default values, if any if ((*m_iter)->get_value()) { t_const_value* member_value = (*m_iter)->get_value(); if (t->is_list()) { const vector& list = member_value->get_list(); if (is_numeric(etype)) { indent(f_types_impl_) << "g_array_append_vals (object->" << name << ", &__default_" << name << ", " << list.size() << ");" << endl; } else { indent(f_types_impl_) << "for (list_index = 0; list_index < " << list.size() << "; " << "list_index += 1)" << endl; indent_up(); indent(f_types_impl_) << "g_ptr_array_add (object->" << name << "," << endl << indent() << string(17, ' ') << "g_strdup (__default_" << name << "[list_index]));" << endl; indent_down(); } } // TODO: Handle container types other than list } } /* if not required, initialize the __isset variable */ if ((*m_iter)->get_req() != t_field::T_REQUIRED) { indent(f_types_impl_) << "object->__isset_" << (*m_iter)->get_name() << " = FALSE;" << endl; } } indent_down(); f_types_impl_ << "}" << endl << endl; /* create the destructor */ f_types_impl_ << "static void " << endl << this->nspace_lc << name_u << "_finalize (GObject *object)" << endl << "{" << endl; indent_up(); f_types_impl_ << indent() << this->nspace << name << " *tobject = " << this->nspace_uc << name_uc << " (object);" << endl << endl; f_types_impl_ << indent() << "/* satisfy -Wall in case we don't use tobject */" << endl << indent() << "THRIFT_UNUSED_VAR (tobject);" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if (t->is_container()) { string name = (*m_iter)->get_name(); if (t->is_map() || t->is_set()) { f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; f_types_impl_ << indent() << "{" << endl; indent_up(); f_types_impl_ << indent() << "g_hash_table_destroy (tobject->" << name << ");" << endl; f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; indent_down(); f_types_impl_ << indent() << "}" << endl; } else if (t->is_list()) { t_type* etype = ((t_list*)t)->get_elem_type(); string destructor_function = "g_ptr_array_unref"; if (etype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)etype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot determine array type"; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: destructor_function = "g_array_unref"; break; case t_base_type::TYPE_STRING: break; default: throw "compiler error: no array info for type"; } } else if (etype->is_enum()) { destructor_function = "g_array_unref"; } f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; f_types_impl_ << indent() << "{" << endl; indent_up(); f_types_impl_ << indent() << destructor_function << " (tobject->" << name << ");" << endl; f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; indent_down(); f_types_impl_ << indent() << "}" << endl; } } else if (t->is_struct() || t->is_xception()) { string name = (*m_iter)->get_name(); // TODO: g_clear_object needs glib >= 2.28 // f_types_impl_ << indent() << "g_clear_object (&(tobject->" << name << "));" << endl; // does g_object_unref the trick? f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; f_types_impl_ << indent() << "{" << endl; indent_up(); f_types_impl_ << indent() << "g_object_unref(tobject->" << name << ");" << endl; f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; indent_down(); f_types_impl_ << indent() << "}" << endl; } else if (t->is_string()) { string name = (*m_iter)->get_name(); f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl; f_types_impl_ << indent() << "{" << endl; indent_up(); f_types_impl_ << indent() << generate_free_func_from_type(t) << "(tobject->" << name << ");" << endl; f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl; indent_down(); f_types_impl_ << indent() << "}" << endl; } } indent_down(); f_types_impl_ << "}" << endl << endl; // generate the class init function f_types_impl_ << "static void" << endl << class_name_lc << "_class_init (" << class_name << "Class * cls)" << endl; scope_up(f_types_impl_); f_types_impl_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl << indent() << "ThriftStructClass *struct_class = " << "THRIFT_STRUCT_CLASS (cls);" << endl << endl << indent() << "struct_class->read = " << class_name_lc << "_read;" << endl << indent() << "struct_class->write = " << class_name_lc << "_write;" << endl << endl << indent() << "gobject_class->finalize = " << class_name_lc << "_finalize;" << endl; if (members.size() > 0) { f_types_impl_ << indent() << "gobject_class->get_property = " << class_name_lc << "_get_property;" << endl << indent() << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl; // install a property for each member for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* member = (*m_iter); string member_name = member->get_name(); string member_name_uc = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name))); t_type* member_type = get_true_type(member->get_type()); t_const_value* member_value = member->get_value(); string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc; f_types_impl_ << endl << indent() << "g_object_class_install_property" << endl; indent_up(); args_indent = indent() + ' '; f_types_impl_ << indent() << "(gobject_class," << endl << args_indent << property_identifier << "," << endl << args_indent; if (member_type->is_base_type()) { t_base_type::t_base base_type = ((t_base_type*)member_type)->get_base(); if (base_type == t_base_type::TYPE_STRING) { if (((t_base_type*)member_type)->is_binary()) { args_indent += string(20, ' '); f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << "G_TYPE_BYTE_ARRAY," << endl << args_indent << "G_PARAM_READWRITE));" << endl; } else { args_indent += string(21, ' '); f_types_impl_ << "g_param_spec_string (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << ((member_value != NULL) ? "\"" + member_value->get_string() + "\"" : "NULL") << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; } } else if (base_type == t_base_type::TYPE_BOOL) { args_indent += string(22, ' '); f_types_impl_ << "g_param_spec_boolean (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << (((member_value != NULL) && (member_value->get_integer() != 0)) ? "TRUE" : "FALSE") << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; } else if ((base_type == t_base_type::TYPE_I8) || (base_type == t_base_type::TYPE_I16) || (base_type == t_base_type::TYPE_I32) || (base_type == t_base_type::TYPE_I64) || (base_type == t_base_type::TYPE_DOUBLE)) { string param_spec_function_name = "g_param_spec_int"; string min_value; string max_value; ostringstream default_value; switch (base_type) { case t_base_type::TYPE_I8: min_value = "G_MININT8"; max_value = "G_MAXINT8"; break; case t_base_type::TYPE_I16: min_value = "G_MININT16"; max_value = "G_MAXINT16"; break; case t_base_type::TYPE_I32: min_value = "G_MININT32"; max_value = "G_MAXINT32"; break; case t_base_type::TYPE_I64: param_spec_function_name = "g_param_spec_int64"; min_value = "G_MININT64"; max_value = "G_MAXINT64"; break; case t_base_type::TYPE_DOUBLE: param_spec_function_name = "g_param_spec_double"; min_value = "-INFINITY"; max_value = "INFINITY"; break; default: throw "compiler error: " "unrecognized base type \"" + member_type->get_name() + "\" " "for struct member \"" + member_name + "\""; break; } if (member_value != nullptr) { default_value << (base_type == t_base_type::TYPE_DOUBLE ? member_value->get_double() : member_value->get_integer()); } else { default_value << "0"; } args_indent += string(param_spec_function_name.length() + 2, ' '); f_types_impl_ << param_spec_function_name << " (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << min_value << "," << endl << args_indent << max_value << "," << endl << args_indent << default_value.str() << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; } indent_down(); } else if (member_type->is_enum()) { t_enum_value* enum_min_value = ((t_enum*)member_type)->get_min_value(); t_enum_value* enum_max_value = ((t_enum*)member_type)->get_max_value(); int min_value = (enum_min_value != nullptr) ? enum_min_value->get_value() : 0; int max_value = (enum_max_value != nullptr) ? enum_max_value->get_value() : 0; args_indent += string(18, ' '); f_types_impl_ << "g_param_spec_int (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << min_value << "," << endl << args_indent << max_value << "," << endl << args_indent << min_value << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; indent_down(); } else if (member_type->is_struct() || member_type->is_xception()) { t_program* type_program = member_type->get_program(); string type_nspace = type_program ? type_program->get_namespace("c_glib") : ""; string type_nspace_prefix = type_nspace.empty() ? "" : initial_caps_to_underscores(type_nspace) + "_"; string param_type = to_upper_case(type_nspace_prefix) + "TYPE_" + to_upper_case(initial_caps_to_underscores(member_type->get_name())); args_indent += string(20, ' '); f_types_impl_ << "g_param_spec_object (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; indent_down(); } else if (member_type->is_list()) { t_type* elem_type = ((t_list*)member_type)->get_elem_type(); string param_type; if (elem_type->is_base_type() && !elem_type->is_string()) { param_type = "G_TYPE_ARRAY"; } else { param_type = "G_TYPE_PTR_ARRAY"; } args_indent += string(20, ' '); f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; indent_down(); } else if (member_type->is_set() || member_type->is_map()) { args_indent += string(20, ' '); f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent << "NULL," << endl << args_indent << "NULL," << endl << args_indent << "G_TYPE_HASH_TABLE," << endl << args_indent << "G_PARAM_READWRITE));" << endl; indent_down(); } } } scope_down(f_types_impl_); f_types_impl_ << endl; f_types_impl_ << "GType" << endl << this->nspace_lc << name_u << "_get_type (void)" << endl << "{" << endl << " static GType type = 0;" << endl << endl << " if (type == 0) " << endl << " {" << endl << " static const GTypeInfo type_info = " << endl << " {" << endl << " sizeof (" << this->nspace << name << "Class)," << endl << " NULL, /* base_init */" << endl << " NULL, /* base_finalize */" << endl << " (GClassInitFunc) " << this->nspace_lc << name_u << "_class_init," << endl << " NULL, /* class_finalize */" << endl << " NULL, /* class_data */" << endl << " sizeof (" << this->nspace << name << ")," << endl << " 0, /* n_preallocs */" << endl << " (GInstanceInitFunc) " << this->nspace_lc << name_u << "_instance_init," << endl << " NULL, /* value_table */" << endl << " };" << endl << endl << " type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl << " \"" << this->nspace << name << "Type\"," << endl << " &type_info, 0);" << endl << " }" << endl << endl << " return type;" << endl << "}" << endl << endl; } /** * Generates functions to write Thrift structures to a stream. */ void t_c_glib_generator::generate_struct_writer(ostream& out, t_struct* tstruct, string this_name, string this_get, bool is_function) { string name = tstruct->get_name(); string name_u = initial_caps_to_underscores(name); string name_uc = to_upper_case(name_u); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; int error_ret = 0; if (is_function) { error_ret = -1; indent(out) << "static gint32" << endl << this->nspace_lc << name_u << "_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl; } indent(out) << "{" << endl; indent_up(); out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << endl; indent(out) << this_get << endl; // satisfy -Wall in the case of an empty struct if (!this_get.empty()) { indent(out) << "THRIFT_UNUSED_VAR (this_object);" << endl; } out << indent() << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name << "\", error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_OPTIONAL) { indent(out) << "if (this_object->__isset_" << (*f_iter)->get_name() << " == TRUE) {" << endl; indent_up(); } out << indent() << "if ((ret = thrift_protocol_write_field_begin (protocol, " << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ", error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl; generate_serialize_field(out, *f_iter, this_name, "", error_ret); out << indent() << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl; if ((*f_iter)->get_req() == t_field::T_OPTIONAL) { indent_down(); indent(out) << "}" << endl; } } // write the struct map out << indent() << "if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl << indent() << "if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl << endl; if (is_function) { indent(out) << "return xfer;" << endl; } indent_down(); indent(out) << "}" << endl << endl; } /** * Generates code to read Thrift structures from a stream. */ void t_c_glib_generator::generate_struct_reader(ostream& out, t_struct* tstruct, string this_name, string this_get, bool is_function) { string name = tstruct->get_name(); string name_u = initial_caps_to_underscores(name); string name_uc = to_upper_case(name_u); int error_ret = 0; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; if (is_function) { error_ret = -1; indent(out) << "/* reads a " << name_u << " object */" << endl << "static gint32" << endl << this->nspace_lc << name_u << "_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl; } indent(out) << "{" << endl; indent_up(); // declare stack temp variables out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << indent() << "gchar *name = NULL;" << endl << indent() << "ThriftType ftype;" << endl << indent() << "gint16 fid;" << endl << indent() << "guint32 len = 0;" << endl << indent() << "gpointer data = NULL;" << endl << indent() << this_get << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { indent(out) << "gboolean isset_" << (*f_iter)->get_name() << " = FALSE;" << endl; } } out << endl; // satisfy -Wall in case we don't use some variables out << indent() << "/* satisfy -Wall in case these aren't used */" << endl << indent() << "THRIFT_UNUSED_VAR (len);" << endl << indent() << "THRIFT_UNUSED_VAR (data);" << endl; if (!this_get.empty()) { out << indent() << "THRIFT_UNUSED_VAR (this_object);" << endl; } out << endl; // read the beginning of the structure marker out << indent() << "/* read the struct begin marker */" << endl << indent() << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl << indent() << "{" << endl << indent() << " if (name) g_free (name);" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "}" << endl << indent() << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent() << "name = NULL;" << endl << endl; // read the struct fields out << indent() << "/* read the struct fields */" << endl << indent() << "while (1)" << endl; scope_up(out); // read beginning field marker out << indent() << "/* read the beginning of a field */" << endl << indent() << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)" << endl << indent() << "{" << endl << indent() << " if (name) g_free (name);" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "}" << endl << indent() << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent() << "name = NULL;" << endl << endl; // check for field STOP marker out << indent() << "/* break if we get a STOP field */" << endl << indent() << "if (ftype == T_STOP)" << endl << indent() << "{" << endl << indent() << " break;" << endl << indent() << "}" << endl << endl; // switch depending on the field type indent(out) << "switch (fid)" << endl; // start switch scope_up(out); // generate deserialization code for known types for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ")" << endl; indent(out) << "{" << endl; indent_up(); // generate deserialize field generate_deserialize_field(out, *f_iter, this_name, "", error_ret, false); indent_down(); out << indent() << "} else {" << endl << indent() << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << " xfer += ret;" << endl << indent() << "}" << endl << indent() << "break;" << endl; indent_down(); } // create the default case out << indent() << "default:" << endl << indent() << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << " xfer += ret;" << endl << indent() << " break;" << endl; // end switch scope_down(out); // read field end marker out << indent() << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl; // end while loop scope_down(out); out << endl; // read the end of the structure out << indent() << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl << endl; // if a required field is missing, throw an error for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl << indent() << "{" << endl << indent() << " g_set_error (error, THRIFT_PROTOCOL_ERROR," << endl << indent() << " THRIFT_PROTOCOL_ERROR_INVALID_DATA," << endl << indent() << " \"missing field\");" << endl << indent() << " return -1;" << endl << indent() << "}" << endl << endl; } } if (is_function) { indent(out) << "return xfer;" << endl; } // end the function/structure indent_down(); indent(out) << "}" << endl << endl; } void t_c_glib_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, string suffix, int error_ret) { t_type* type = get_true_type(tfield->get_type()); string name = prefix + tfield->get_name() + suffix; if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, name, error_ret); } else if (type->is_container()) { generate_serialize_container(out, type, name, error_ret); } else if (type->is_base_type() || type->is_enum()) { indent(out) << "if ((ret = thrift_protocol_write_"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_BOOL: out << "bool (protocol, " << name; break; case t_base_type::TYPE_I8: out << "byte (protocol, " << name; break; case t_base_type::TYPE_I16: out << "i16 (protocol, " << name; break; case t_base_type::TYPE_I32: out << "i32 (protocol, " << name; break; case t_base_type::TYPE_I64: out << "i64 (protocol, " << name; break; case t_base_type::TYPE_DOUBLE: out << "double (protocol, " << name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "binary (protocol, " << name << " ? ((GByteArray *) " << name << ")->data : NULL, " << name << " ? ((GByteArray *) " << name << ")->len : 0"; } else { out << "string (protocol, " << name; } break; default: throw "compiler error: no C writer for base type " + t_base_type::t_base_name(tbase) + name; } } else { out << "i32 (protocol, (gint32) " << name; } out << ", error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl << endl; } else { throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + name + "' TYPE '" + type_name(type)); } } void t_c_glib_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix, int error_ret) { (void)tstruct; out << indent() << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl << endl; } void t_c_glib_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix, int error_ret) { scope_up(out); if (ttype->is_map()) { t_type* tkey = ((t_map*)ttype)->get_key_type(); t_type* tval = ((t_map*)ttype)->get_val_type(); string tkey_name = type_name(tkey); string tval_name = type_name(tval); string tkey_ptr; string tval_ptr; string keyname = tmp("key"); string valname = tmp("val"); declore_local_variable_for_write(out, tkey, keyname); declore_local_variable_for_write(out, tval, valname); /* If either the key or value type is a typedef, find its underlying type so we can correctly determine how to generate a pointer to it */ tkey = get_true_type(tkey); tval = get_true_type(tval); tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*"; tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*"; /* * Some ugliness here. To maximize backwards compatibility, we * avoid using GHashTableIter and instead get a GList of all keys, * then copy it into a array on the stack, and free it. * This is because we may exit early before we get a chance to free the * GList. */ out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl << indent() << tkey_name << tkey_ptr << "* keys;" << endl << indent() << "int i = 0, key_count;" << endl << endl << indent() << "if ((ret = thrift_protocol_write_map_begin (protocol, " << type_to_enum(tkey) << ", " << type_to_enum(tval) << ", " << prefix << " ? " << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0" << ", error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl << indent() << "if (" << prefix << ")" << endl << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix << ", thrift_hash_table_get_keys, &key_list);" << endl << indent() << "key_count = g_list_length (key_list);" << endl << indent() << "keys = g_newa (" << tkey_name << tkey_ptr << ", key_count);" << endl << indent() << "for (iter = g_list_first (key_list); iter; " "iter = iter->next)" << endl; indent_up(); out << indent() << "keys[i++] = (" << tkey_name << tkey_ptr << ") iter->data;" << endl; indent_down(); out << indent() << "g_list_free (key_list);" << endl << endl << indent() << "for (i = 0; i < key_count; ++i)" << endl; scope_up(out); out << indent() << keyname << " = keys[i];" << endl << indent() << valname << " = (" << tval_name << tval_ptr << ") g_hash_table_lookup (((GHashTable *) " << prefix << "), (gpointer) " << keyname << ");" << endl << endl; generate_serialize_map_element(out, (t_map*)ttype, tkey_ptr + " " + keyname, tval_ptr + " " + valname, error_ret); scope_down(out); out << indent() << "if ((ret = thrift_protocol_write_map_end (protocol, " "error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl; } else if (ttype->is_set()) { t_type* telem = ((t_set*)ttype)->get_elem_type(); string telem_name = type_name(telem); string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*"; out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl << indent() << telem_name << telem_ptr << "* keys;" << endl << indent() << "int i = 0, key_count;" << endl << indent() << telem_name << telem_ptr << " elem;" << endl << indent() << "gpointer value;" << endl << indent() << "THRIFT_UNUSED_VAR (value);" << endl << endl << indent() << "if ((ret = thrift_protocol_write_set_begin (protocol, " << type_to_enum(telem) << ", " << prefix << " ? " << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0" << ", error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl << indent() << "if (" << prefix << ")" << endl << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix << ", thrift_hash_table_get_keys, &key_list);" << endl << indent() << "key_count = g_list_length (key_list);" << endl << indent() << "keys = g_newa (" << telem_name << telem_ptr << ", key_count);" << endl << indent() << "for (iter = g_list_first (key_list); iter; " "iter = iter->next)" << endl; indent_up(); out << indent() << "keys[i++] = (" << telem_name << telem_ptr << ") iter->data;" << endl; indent_down(); out << indent() << "g_list_free (key_list);" << endl << endl << indent() << "for (i = 0; i < key_count; ++i)" << endl; scope_up(out); out << indent() << "elem = keys[i];" << endl << indent() << "value = (gpointer) g_hash_table_lookup " "(((GHashTable *) " << prefix << "), (gpointer) elem);" << endl << endl; generate_serialize_set_element(out, (t_set*)ttype, telem_ptr + "elem", error_ret); scope_down(out); out << indent() << "if ((ret = thrift_protocol_write_set_end (protocol, " "error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl; } else if (ttype->is_list()) { string length = "(" + prefix + " ? " + prefix + "->len : 0)"; string i = tmp("i"); out << indent() << "guint " << i << ";" << endl << endl << indent() << "if ((ret = thrift_protocol_write_list_begin (protocol, " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", (gint32) " << length << ", error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl << indent() << "for (" << i << " = 0; " << i << " < " << length << "; " << i << "++)" << endl; scope_up(out); generate_serialize_list_element(out, (t_list*)ttype, prefix, i, error_ret); scope_down(out); out << indent() << "if ((ret = thrift_protocol_write_list_end (protocol, " "error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl; } scope_down(out); } void t_c_glib_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string key, string value, int error_ret) { t_field kfield(tmap->get_key_type(), key); generate_serialize_field(out, &kfield, "", "", error_ret); t_field vfield(tmap->get_val_type(), value); generate_serialize_field(out, &vfield, "", "", error_ret); } void t_c_glib_generator::generate_serialize_set_element(ostream& out, t_set* tset, string element, int error_ret) { t_field efield(tset->get_elem_type(), element); generate_serialize_field(out, &efield, "", "", error_ret); } void t_c_glib_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string list, string index, int error_ret) { t_type* ttype = get_true_type(tlist->get_elem_type()); // cast to non-const string cast = ""; string name = "g_ptr_array_index ((GPtrArray *) " + list + ", " + index + ")"; if (ttype->is_void()) { throw std::runtime_error("compiler error: list element type cannot be void"); } else if (is_numeric(ttype)) { name = "g_array_index (" + list + ", " + base_type_name(ttype) + ", " + index + ")"; } else if (ttype->is_string()) { cast = "(gchar*)"; } else if (ttype->is_map() || ttype->is_set()) { cast = "(GHashTable*)"; } else if (ttype->is_list()) { t_type* etype = ((t_list*)ttype)->get_elem_type(); if (etype->is_void()) { throw std::runtime_error("compiler error: list element type cannot be void"); } cast = is_numeric(etype) ? "(GArray*)" : "(GPtrArray*)"; } t_field efield(ttype, "(" + cast + name + ")"); generate_serialize_field(out, &efield, "", "", error_ret); } /* deserializes a field of any type. */ void t_c_glib_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, string suffix, int error_ret, bool allocate) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw std::runtime_error("CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name()); } string name = prefix + tfield->get_name() + suffix; if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name, error_ret, allocate); } else if (type->is_container()) { generate_deserialize_container(out, type, name, error_ret); } else if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); if (tbase == t_base_type::TYPE_STRING) { indent(out) << "if (" << name << " != NULL)" << endl << indent() << "{" << endl; indent_up(); indent(out) << "g_free(" << name << ");" << endl << indent() << name << " = NULL;" << endl; indent_down(); indent(out) << "}" << endl << endl; } indent(out) << "if ((ret = thrift_protocol_read_"; switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "binary (protocol, &data, &len"; } else { out << "string (protocol, &" << name; } break; case t_base_type::TYPE_BOOL: out << "bool (protocol, &" << name; break; case t_base_type::TYPE_I8: out << "byte (protocol, &" << name; break; case t_base_type::TYPE_I16: out << "i16 (protocol, &" << name; break; case t_base_type::TYPE_I32: out << "i32 (protocol, &" << name; break; case t_base_type::TYPE_I64: out << "i64 (protocol, &" << name; break; case t_base_type::TYPE_DOUBLE: out << "double (protocol, &" << name; break; default: throw "compiler error: no C reader for base type " + t_base_type::t_base_name(tbase) + name; } out << ", error)) < 0)" << endl; out << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl; // load the byte array with the data if (tbase == t_base_type::TYPE_STRING && type->is_binary()) { indent(out) << name << " = g_byte_array_new();" << endl; indent(out) << "g_byte_array_append (" << name << ", (guint8 *) data, (guint) len);" << endl; indent(out) << "g_free (data);" << endl; } } else if (type->is_enum()) { string t = tmp("ecast"); out << indent() << "gint32 " << t << ";" << endl << indent() << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t << ", error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl; } else { throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + tfield->get_name() + "' TYPE '" + type_name(type)); } // if the type is not required and this is a thrift struct (no prefix), // set the isset variable. if the type is required, then set the // local variable indicating the value was set, so that we can do // validation later. if (prefix != "" && tfield->get_req() != t_field::T_REQUIRED) { indent(out) << prefix << "__isset_" << tfield->get_name() << suffix << " = TRUE;" << endl; } else if (prefix != "" && tfield->get_req() == t_field::T_REQUIRED) { indent(out) << "isset_" << tfield->get_name() << " = TRUE;" << endl; } } void t_c_glib_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix, int error_ret, bool allocate) { string name_uc = to_upper_case(initial_caps_to_underscores(tstruct->get_name())); if (tstruct->is_xception()) { out << indent() << "/* This struct is an exception */" << endl; allocate = true; } if (allocate) { out << indent() << "if ( " << prefix << " != NULL)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "g_object_unref (" << prefix << ");" << endl; indent_down(); out << indent() << "}" << endl << indent() << prefix << " = g_object_new (" << this->nspace_uc << "TYPE_" << name_uc << ", NULL);" << endl; } out << indent() << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl << indent() << "{" << endl; indent_up(); if (allocate) { indent(out) << "g_object_unref (" << prefix << ");" << endl; if (tstruct->is_xception()) { indent(out) << prefix << " = NULL;" << endl; } } out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "}" << endl << indent() << "xfer += ret;" << endl; } void t_c_glib_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix, int error_ret) { scope_up(out); if (ttype->is_map()) { out << indent() << "guint32 size;" << endl << indent() << "guint32 i;" << endl << indent() << "ThriftType key_type;" << endl << indent() << "ThriftType value_type;" << endl << endl << indent() << "/* read the map begin marker */" << endl << indent() << "if ((ret = thrift_protocol_read_map_begin (protocol, " "&key_type, &value_type, &size, error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl << endl; // iterate over map elements out << indent() << "/* iterate through each of the map's fields */" << endl << indent() << "for (i = 0; i < size; i++)" << endl; scope_up(out); generate_deserialize_map_element(out, (t_map*)ttype, prefix, error_ret); scope_down(out); out << endl; // read map end out << indent() << "/* read the map end marker */" << endl << indent() << "if ((ret = thrift_protocol_read_map_end (protocol, " "error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl; } else if (ttype->is_set()) { out << indent() << "guint32 size;" << endl << indent() << "guint32 i;" << endl << indent() << "ThriftType element_type;" << endl << endl << indent() << "if ((ret = thrift_protocol_read_set_begin (protocol, " "&element_type, &size, error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl << endl; // iterate over the elements out << indent() << "/* iterate through the set elements */" << endl << indent() << "for (i = 0; i < size; ++i)" << endl; scope_up(out); generate_deserialize_set_element(out, (t_set*)ttype, prefix, error_ret); scope_down(out); // read set end out << indent() << "if ((ret = thrift_protocol_read_set_end (protocol, " "error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl << endl; } else if (ttype->is_list()) { out << indent() << "guint32 size;" << endl << indent() << "guint32 i;" << endl << indent() << "ThriftType element_type;" << endl << endl << indent() << "if ((ret = thrift_protocol_read_list_begin (protocol, " "&element_type,&size, error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl << endl; // iterate over the elements out << indent() << "/* iterate through list elements */" << endl << indent() << "for (i = 0; i < size; i++)" << endl; scope_up(out); generate_deserialize_list_element(out, (t_list*)ttype, prefix, "i", error_ret); scope_down(out); // read list end out << indent() << "if ((ret = thrift_protocol_read_list_end (protocol, " "error)) < 0)" << endl; indent_up(); out << indent() << "return " << error_ret << ";" << endl; indent_down(); out << indent() << "xfer += ret;" << endl; } scope_down(out); } void t_c_glib_generator::declare_local_variable(ostream& out, t_type* ttype, string& name, bool for_hash_table) { string tname = type_name(ttype); /* If the given type is a typedef, find its underlying type so we can correctly determine how to generate a pointer to it */ ttype = get_true_type(ttype); string ptr = !is_numeric(ttype) ? "" : "*"; if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; out << indent() << tname << ptr << " " << name << " = " << generate_new_hash_from_type(tmap->get_key_type(), tmap->get_val_type()) << endl; } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; out << indent() << tname << ptr << " " << name << " = " << generate_new_array_from_type(tlist->get_elem_type()) << endl; } else if (for_hash_table && ttype->is_enum()) { out << indent() << tname << " " << name << ";" << endl; } else { out << indent() << tname << ptr << " " << name << (ptr != "" ? " = g_new (" + tname + ", 1)" : " = NULL") << ";" << endl; } } void t_c_glib_generator::declore_local_variable_for_write(ostream& out, t_type* ttype, string& name) { string tname = type_name(ttype); ttype = get_true_type(ttype); string ptr = ttype->is_string() || !ttype->is_base_type() ? " " : "* "; string init_val = ttype->is_enum() ? "" : " = NULL"; out << indent() << tname << ptr << name << init_val << ";" << endl; } void t_c_glib_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix, int error_ret) { t_type* tkey = tmap->get_key_type(); t_type* tval = tmap->get_val_type(); string keyname = tmp("key"); string valname = tmp("val"); declare_local_variable(out, tkey, keyname, true); declare_local_variable(out, tval, valname, true); /* If either the key or value type is a typedef, find its underlying type so we can correctly determine how to generate a pointer to it */ tkey = get_true_type(tkey); tval = get_true_type(tval); string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*"; string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*"; // deserialize the fields of the map element t_field fkey(tkey, tkey_ptr + keyname); generate_deserialize_field(out, &fkey, "", "", error_ret); t_field fval(tval, tval_ptr + valname); generate_deserialize_field(out, &fval, "", "", error_ret); indent(out) << "if (" << prefix << " && " << keyname << ")" << endl; indent_up(); indent(out) << "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer) " << keyname << ", (gpointer) " << valname << ");" << endl; indent_down(); } void t_c_glib_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix, int error_ret) { t_type* telem = tset->get_elem_type(); string elem = tmp("_elem"); string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*"; declare_local_variable(out, telem, elem, true); t_field felem(telem, telem_ptr + elem); generate_deserialize_field(out, &felem, "", "", error_ret); indent(out) << "if (" << prefix << " && " << elem << ")" << endl; indent_up(); indent(out) << "g_hash_table_insert ((GHashTable *) " << prefix << ", (gpointer) " << elem << ", (gpointer) " << elem << ");" << endl; indent_down(); } void t_c_glib_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix, string index, int error_ret) { (void)index; t_type* ttype = get_true_type(tlist->get_elem_type()); string elem = tmp("_elem"); string telem_ptr = !is_numeric(ttype) ? "" : "*"; declare_local_variable(out, ttype, elem, false); t_field felem(ttype, telem_ptr + elem); generate_deserialize_field(out, &felem, "", "", error_ret); if (ttype->is_void()) { throw std::runtime_error("compiler error: list element type cannot be void"); } else if (is_numeric(ttype)) { indent(out) << "g_array_append_vals (" << prefix << ", " << elem << ", 1);" << endl; indent(out) << "g_free (" << elem << ");" << endl; } else { indent(out) << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl; } } string t_c_glib_generator::generate_free_func_from_type(t_type* ttype) { if (ttype == nullptr) return "NULL"; if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot determine hash type"; break; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: return "g_free"; case t_base_type::TYPE_STRING: if (((t_base_type*)ttype)->is_binary()) { return "thrift_string_free"; } return "g_free"; default: throw "compiler error: no hash table info for type"; } } else if (ttype->is_enum()) { return "NULL"; } else if (ttype->is_map() || ttype->is_set()) { return "(GDestroyNotify) thrift_safe_hash_table_destroy"; } else if (ttype->is_struct()) { return "g_object_unref"; } else if (ttype->is_list()) { t_type* etype = ((t_list*)ttype)->get_elem_type(); if (etype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)etype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot determine array type"; break; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: return "(GDestroyNotify) g_array_unref"; case t_base_type::TYPE_STRING: return "(GDestroyNotify) g_ptr_array_unref"; default: throw "compiler error: no array info for type"; } } else if (etype->is_container() || etype->is_struct()) { return "(GDestroyNotify) g_ptr_array_unref"; ; } else if (etype->is_enum()) { return "(GDestroyNotify) g_array_unref"; } printf("Type not expected inside the array: %s\n", etype->get_name().c_str()); throw "Type not expected inside array"; } else if (ttype->is_typedef()) { return generate_free_func_from_type(((t_typedef*)ttype)->get_type()); } printf("Type not expected: %s\n", ttype->get_name().c_str()); throw "Type not expected"; } string t_c_glib_generator::generate_hash_func_from_type(t_type* ttype) { if (ttype == nullptr) return "NULL"; if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot determine hash type"; break; case t_base_type::TYPE_BOOL: return "thrift_boolean_hash"; case t_base_type::TYPE_I8: return "thrift_int8_hash"; case t_base_type::TYPE_I16: return "thrift_int16_hash"; case t_base_type::TYPE_I32: return "g_int_hash"; case t_base_type::TYPE_I64: return "g_int64_hash"; case t_base_type::TYPE_DOUBLE: return "g_double_hash"; case t_base_type::TYPE_STRING: return "g_str_hash"; default: throw "compiler error: no hash table info for type"; } } else if (ttype->is_enum()) { return "g_direct_hash"; } else if (ttype->is_container() || ttype->is_struct()) { return "g_direct_hash"; } else if (ttype->is_typedef()) { return generate_hash_func_from_type(((t_typedef*)ttype)->get_type()); } printf("Type not expected: %s\n", ttype->get_name().c_str()); throw "Type not expected"; } string t_c_glib_generator::generate_cmp_func_from_type(t_type* ttype) { if (ttype == nullptr) return "NULL"; if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot determine hash type"; break; case t_base_type::TYPE_BOOL: return "thrift_boolean_equal"; case t_base_type::TYPE_I8: return "thrift_int8_equal"; case t_base_type::TYPE_I16: return "thrift_int16_equal"; case t_base_type::TYPE_I32: return "g_int_equal"; case t_base_type::TYPE_I64: return "g_int64_equal"; case t_base_type::TYPE_DOUBLE: return "g_double_equal"; case t_base_type::TYPE_STRING: return "g_str_equal"; default: throw "compiler error: no hash table info for type"; } } else if (ttype->is_enum()) { return "g_direct_equal"; } else if (ttype->is_container() || ttype->is_struct()) { return "g_direct_equal"; } else if (ttype->is_typedef()) { return generate_cmp_func_from_type(((t_typedef*)ttype)->get_type()); } printf("Type not expected: %s\n", ttype->get_name().c_str()); throw "Type not expected"; } string t_c_glib_generator::generate_new_hash_from_type(t_type* key, t_type* value) { string hash_func = generate_hash_func_from_type(key); string cmp_func = generate_cmp_func_from_type(key); string key_free_func = generate_free_func_from_type(key); string value_free_func = generate_free_func_from_type(value); return "g_hash_table_new_full (" + hash_func + ", " + cmp_func + ", " + key_free_func + ", " + value_free_func + ");"; } string t_c_glib_generator::generate_new_array_from_type(t_type* ttype) { if (ttype->is_void()) { throw std::runtime_error("compiler error: cannot determine array type"); } else if (is_numeric(ttype)) { return "g_array_new (0, 1, sizeof (" + base_type_name(ttype) + "));"; } else { string free_func = generate_free_func_from_type(ttype); return "g_ptr_array_new_with_free_func (" + free_func + ");"; } } /*************************************** * UTILITY FUNCTIONS * ***************************************/ /** * Upper case a string. */ string to_upper_case(string name) { string s(name); std::transform(s.begin(), s.end(), s.begin(), ::toupper); return s; } /** * Lower case a string. */ string to_lower_case(string name) { string s(name); std::transform(s.begin(), s.end(), s.begin(), ::tolower); return s; } /** * Makes a string friendly to C code standards by lowercasing and adding * underscores, with the exception of the first character. For example: * * Input: "ZomgCamelCase" * Output: "zomg_camel_case" */ string initial_caps_to_underscores(string name) { string ret; const char* tmp = name.c_str(); int pos = 0; /* the first character isn't underscored if uppercase, just lowercased */ ret += tolower(tmp[pos]); pos++; for (unsigned int i = pos; i < name.length(); i++) { char lc = tolower(tmp[i]); if (lc != tmp[i]) { ret += '_'; } ret += lc; } return ret; } /** * Performs the reverse operation of initial_caps_to_underscores: The first * character of the string is made uppercase, along with each character that * follows an underscore (which is removed). Useful for converting Thrift * service-method names into GObject-style class names. * * Input: "zomg_camel_case" * Output: "ZomgCamelCase" */ string underscores_to_initial_caps(string name) { string ret; const char* tmp = name.c_str(); bool uppercase_next = true; for (unsigned int i = 0; i < name.length(); i++) { char c = tmp[i]; if (c == '_') { uppercase_next = true; } else { if (uppercase_next) { ret += toupper(c); uppercase_next = false; } else { ret += c; } } } return ret; } /* register this generator with the main program */ THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_cl_generator.cc000066400000000000000000000421531420101504100246420ustar00rootroot00000000000000/* * Copyright (c) 2008- Patrick Collison * Copyright (c) 2006- Facebook * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "t_oop_generator.h" using namespace std; /** * Common Lisp code generator. * * @author Patrick Collison */ class t_cl_generator : public t_oop_generator { public: t_cl_generator( t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { no_asd = false; system_prefix = "thrift-gen-"; std::map::const_iterator iter; for(iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if(iter->first.compare("no_asd") == 0) { no_asd = true; } else if (iter->first.compare("sys_pref") == 0) { system_prefix = iter->second; } else { throw "unknown option cl:" + iter->first; } } out_dir_base_ = "gen-cl"; copy_options_ = option_string; } void init_generator() override; void close_generator() override; void generate_typedef (t_typedef* ttypedef) override; void generate_enum (t_enum* tenum) override; void generate_const (t_const* tconst) override; void generate_struct (t_struct* tstruct) override; void generate_xception (t_struct* txception) override; void generate_service (t_service* tservice) override; void generate_cl_struct (std::ostream& out, t_struct* tstruct, bool is_exception); void generate_cl_struct_internal (std::ostream& out, t_struct* tstruct, bool is_exception); void generate_exception_sig(std::ostream& out, t_function* f); std::string render_const_value(t_type* type, t_const_value* value); std::string cl_autogen_comment(); void asdf_def(std::ostream &out); void package_def(std::ostream &out); void package_in(std::ostream &out); std::string generated_package(); std::string prefix(std::string name); std::string package_of(t_program* program); std::string package(); std::string render_includes(); std::string type_name(t_type* ttype); std::string typespec (t_type *t); std::string function_signature(t_function* tfunction); std::string argument_list(t_struct* tstruct); std::string cl_docstring(std::string raw); private: int temporary_var; /** * Isolate the variable definitions, as they can require structure definitions */ ofstream_with_content_based_conditional_update f_asd_; ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_vars_; std::string copy_options_; bool no_asd; std::string system_prefix; }; void t_cl_generator::init_generator() { MKDIR(get_out_dir().c_str()); string program_dir = get_out_dir() + "/" + program_name_; MKDIR(program_dir.c_str()); temporary_var = 0; string f_types_name = program_dir + "/" + program_name_ + "-types.lisp"; string f_vars_name = program_dir + "/" + program_name_ + "-vars.lisp"; f_types_.open(f_types_name); f_types_ << cl_autogen_comment() << endl; f_vars_.open(f_vars_name); f_vars_ << cl_autogen_comment() << endl; package_def(f_types_); package_in(f_types_); package_in(f_vars_); if (!no_asd) { string f_asd_name = program_dir + "/" + system_prefix + program_name_ + ".asd"; f_asd_.open(f_asd_name); f_asd_ << cl_autogen_comment() << endl; asdf_def(f_asd_); } } /** * Renders all the imports necessary for including another Thrift program */ string t_cl_generator::render_includes() { const vector& includes = program_->get_includes(); string result = ""; result += ":depends-on (:thrift"; for (auto include : includes) { result += " :" + system_prefix + underscore(include->get_name()); } result += ")\n"; return result; } string t_cl_generator::package_of(t_program* program) { string prefix = program->get_namespace("cl"); return prefix.empty() ? "thrift-generated" : prefix; } string t_cl_generator::package() { return package_of(program_); } string t_cl_generator::prefix(string symbol) { return "\"" + symbol + "\""; } string t_cl_generator::cl_autogen_comment() { return std::string(";;; ") + "Autogenerated by Thrift\n" + ";;; DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + ";;; options string: " + copy_options_ + "\n"; } string t_cl_generator::cl_docstring(string raw) { replace(raw.begin(), raw.end(), '"', '\''); return raw; } void t_cl_generator::close_generator() { f_asd_.close(); f_types_.close(); f_vars_.close(); } string t_cl_generator::generated_package() { return program_->get_namespace("cpp"); } void t_cl_generator::asdf_def(std::ostream &out) { out << "(asdf:defsystem #:" << system_prefix << program_name_ << endl; indent_up(); out << indent() << render_includes() << indent() << ":serial t" << endl << indent() << ":components (" << "(:file \"" << program_name_ << "-types\") " << "(:file \"" << program_name_ << "-vars\")))" << endl; indent_down(); } /*** * Generate a package definition. Add use references equivalent to the idl file's include statements. */ void t_cl_generator::package_def(std::ostream &out) { const vector& includes = program_->get_includes(); out << "(thrift:def-package :" << package(); if ( includes.size() > 0 ) { out << " :use ("; for (auto include : includes) { out << " :" << include->get_name(); } out << ")"; } out << ")" << endl << endl; } void t_cl_generator::package_in(std::ostream &out) { out << "(cl:in-package :" << package() << ")" << endl << endl; } /** * Generates a typedef. This is not done in Common Lisp, types are all implicit. * * @param ttypedef The type definition */ void t_cl_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } void t_cl_generator::generate_enum(t_enum* tenum) { f_types_ << "(thrift:def-enum " << prefix(tenum->get_name()) << endl; vector constants = tenum->get_constants(); vector::iterator c_iter; int value = -1; indent_up(); f_types_ << indent() << "("; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { value = (*c_iter)->get_value(); if(c_iter != constants.begin()) f_types_ << endl << indent() << " "; f_types_ << "(\"" << (*c_iter)->get_name() << "\" . " << value << ")"; } indent_down(); f_types_ << "))" << endl << endl; } /** * Generate a constant value */ void t_cl_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); f_vars_ << "(thrift:def-constant " << prefix(name) << " " << render_const_value(type, value) << ")" << endl << endl; } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_cl_generator::render_const_value(t_type* type, t_const_value* value) { type = get_true_type(type); std::ostringstream out; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << "\"" << value->get_string() << "\""; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "t" : "nil"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { indent(out) << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << (type->is_struct() ? "(make-instance '" : "(make-exception '") << lowercase(type->get_name()) << " " << endl; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } out << indent() << ":" << v_iter->first->get_string() << " " << render_const_value(field_type, v_iter->second) << endl; } out << indent() << ")"; indent_down(); } else if (type->is_map()) { // emit an hash form with both keys and values to be evaluated t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); out << "(thrift:map "; indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << endl << indent() << "(cl:cons " << render_const_value(ktype, v_iter->first) << " " << render_const_value(vtype, v_iter->second) << ")"; } indent_down(); out << indent() << ")"; } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } if (type->is_set()) { out << "(thrift:set" << endl; } else { out << "(thrift:list" << endl; } indent_up(); indent_up(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent() << render_const_value(etype, *v_iter) << endl; } out << indent() << ")"; indent_down(); indent_down(); } else { throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); } return out.str(); } void t_cl_generator::generate_struct(t_struct* tstruct) { generate_cl_struct(f_types_, tstruct, false); } void t_cl_generator::generate_xception(t_struct* txception) { generate_cl_struct(f_types_, txception, true); } void t_cl_generator::generate_cl_struct_internal(std::ostream& out, t_struct* tstruct, bool is_exception) { (void)is_exception; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; out << "("; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_const_value* value = (*m_iter)->get_value(); t_type* type = (*m_iter)->get_type(); if (m_iter != members.begin()) { out << endl << indent() << " "; } out << "(" << prefix((*m_iter)->get_name()) << " " << ( (nullptr != value) ? render_const_value(type, value) : "nil" ) << " :id " << (*m_iter)->get_key(); if ( type->is_base_type() && "string" == typespec(type) ) if ( ((t_base_type*)type)->is_binary() ) out << " :type binary"; else out << " :type string"; else out << " :type " << typespec(type); if ( (*m_iter)->get_req() == t_field::T_OPTIONAL ) { out << " :optional t"; } if ( (*m_iter)->has_doc()) { out << " :documentation \"" << cl_docstring((*m_iter)->get_doc()) << "\""; } out <<")"; } out << ")"; } void t_cl_generator::generate_cl_struct(std::ostream& out, t_struct* tstruct, bool is_exception = false) { std::string name = type_name(tstruct); out << (is_exception ? "(thrift:def-exception " : "(thrift:def-struct ") << prefix(name) << endl; indent_up(); if ( tstruct->has_doc() ) { out << indent() ; out << "\"" << cl_docstring(tstruct->get_doc()) << "\"" << endl; } out << indent() ; generate_cl_struct_internal(out, tstruct, is_exception); indent_down(); out << ")" << endl << endl; } void t_cl_generator::generate_exception_sig(std::ostream& out, t_function* f) { generate_cl_struct_internal(out, f->get_xceptions(), true); } void t_cl_generator::generate_service(t_service* tservice) { string extends_client; vector functions = tservice->get_functions(); vector::iterator f_iter; if (tservice->get_extends() != nullptr) { extends_client = type_name(tservice->get_extends()); } extends_client = extends_client.empty() ? "nil" : prefix(extends_client); f_types_ << "(thrift:def-service " << prefix(service_name_) << " " << extends_client; indent_up(); if ( tservice->has_doc()) { f_types_ << endl << indent() << "(:documentation \"" << cl_docstring(tservice->get_doc()) << "\")"; } for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_function* function = *f_iter; string fname = function->get_name(); string signature = function_signature(function); t_struct* exceptions = function->get_xceptions(); const vector& xmembers = exceptions->get_members(); f_types_ << endl << indent() << "(:method " << prefix(fname); f_types_ << " (" << signature << " " << typespec((*f_iter)->get_returntype()) << ")"; if (xmembers.size() > 0) { f_types_ << endl << indent() << " :exceptions " ; generate_exception_sig(f_types_, function); } if ( (*f_iter)->is_oneway() ) { f_types_ << endl << indent() << " :oneway t"; } if ( (*f_iter)->has_doc() ) { f_types_ << endl << indent() << " :documentation \"" << cl_docstring((*f_iter)->get_doc()) << "\""; } f_types_ << ")"; } f_types_ << ")" << endl << endl; indent_down(); } string t_cl_generator::typespec(t_type *t) { t = get_true_type(t); if (t -> is_binary()){ return "binary"; } else if (t->is_base_type()) { return type_name(t); } else if (t->is_map()) { t_map *m = (t_map*) t; return "(thrift:map " + typespec(m->get_key_type()) + " " + typespec(m->get_val_type()) + ")"; } else if (t->is_struct() || t->is_xception()) { return "(struct " + prefix(type_name(t)) + ")"; } else if (t->is_list()) { return "(thrift:list " + typespec(((t_list*) t)->get_elem_type()) + ")"; } else if (t->is_set()) { return "(thrift:set " + typespec(((t_set*) t)->get_elem_type()) + ")"; } else if (t->is_enum()) { return "(enum \"" + ((t_enum*) t)->get_name() + "\")"; } else { throw "Sorry, I don't know how to generate this: " + type_name(t); } } string t_cl_generator::function_signature(t_function* tfunction) { return argument_list(tfunction->get_arglist()); } string t_cl_generator::argument_list(t_struct* tstruct) { stringstream res; res << "("; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { res << " "; } res << "(" + prefix((*f_iter)->get_name()) << " " << typespec((*f_iter)->get_type()) << " " << (*f_iter)->get_key() << ")"; } res << ")"; return res.str(); } string t_cl_generator::type_name(t_type* ttype) { string prefix = ""; t_program* program = ttype->get_program(); if (program != nullptr && program != program_) prefix = package_of(program) == package() ? "" : package_of(program) + ":"; string name = ttype->get_name(); if (ttype->is_struct() || ttype->is_xception()) name = lowercase(ttype->get_name()); return prefix + name; } THRIFT_REGISTER_GENERATOR( cl, "Common Lisp", " no_asd: Do not define ASDF systems for each generated Thrift program.\n" " sys_pref= The prefix to give ASDF system names. Default: thrift-gen-\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_cpp_generator.cc000066400000000000000000005524371420101504100250410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ofstream; using std::ostream; using std::string; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * C++ code generator. This is legitimacy incarnate. * */ class t_cpp_generator : public t_oop_generator { public: t_cpp_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; gen_pure_enums_ = false; use_include_prefix_ = false; gen_cob_style_ = false; gen_no_client_completion_ = false; gen_no_default_operators_ = false; gen_templates_ = false; gen_templates_only_ = false; gen_moveable_ = false; gen_no_ostream_operators_ = false; gen_no_skeleton_ = false; has_members_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("pure_enums") == 0) { gen_pure_enums_ = true; } else if( iter->first.compare("include_prefix") == 0) { use_include_prefix_ = true; } else if( iter->first.compare("cob_style") == 0) { gen_cob_style_ = true; } else if( iter->first.compare("no_client_completion") == 0) { gen_no_client_completion_ = true; } else if( iter->first.compare("no_default_operators") == 0) { gen_no_default_operators_ = true; } else if( iter->first.compare("templates") == 0) { gen_templates_ = true; gen_templates_only_ = (iter->second == "only"); } else if( iter->first.compare("moveable_types") == 0) { gen_moveable_ = true; } else if ( iter->first.compare("no_ostream_operators") == 0) { gen_no_ostream_operators_ = true; } else if ( iter->first.compare("no_skeleton") == 0) { gen_no_skeleton_ = true; } else { throw "unknown option cpp:" + iter->first; } } out_dir_base_ = "gen-cpp"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; void generate_consts(std::vector consts) override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_enum_ostream_operator_decl(std::ostream& out, t_enum* tenum); void generate_enum_ostream_operator(std::ostream& out, t_enum* tenum); void generate_enum_to_string_helper_function_decl(std::ostream& out, t_enum* tenum); void generate_enum_to_string_helper_function(std::ostream& out, t_enum* tenum); void generate_forward_declaration(t_struct* tstruct) override; void generate_struct(t_struct* tstruct) override { generate_cpp_struct(tstruct, false); } void generate_xception(t_struct* txception) override { generate_cpp_struct(txception, true); } void generate_cpp_struct(t_struct* tstruct, bool is_exception); void generate_service(t_service* tservice) override; void print_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value); std::string render_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value); void generate_struct_declaration(std::ostream& out, t_struct* tstruct, bool is_exception = false, bool pointers = false, bool read = true, bool write = true, bool swap = false, bool is_user_struct = false); void generate_struct_definition(std::ostream& out, std::ostream& force_cpp_out, t_struct* tstruct, bool setters = true, bool is_user_struct = false); void generate_copy_constructor(std::ostream& out, t_struct* tstruct, bool is_exception); void generate_move_constructor(std::ostream& out, t_struct* tstruct, bool is_exception); void generate_constructor_helper(std::ostream& out, t_struct* tstruct, bool is_excpetion, bool is_move); void generate_assignment_operator(std::ostream& out, t_struct* tstruct); void generate_move_assignment_operator(std::ostream& out, t_struct* tstruct); void generate_assignment_helper(std::ostream& out, t_struct* tstruct, bool is_move); void generate_struct_reader(std::ostream& out, t_struct* tstruct, bool pointers = false); void generate_struct_writer(std::ostream& out, t_struct* tstruct, bool pointers = false); void generate_struct_result_writer(std::ostream& out, t_struct* tstruct, bool pointers = false); void generate_struct_swap(std::ostream& out, t_struct* tstruct); void generate_struct_print_method(std::ostream& out, t_struct* tstruct); void generate_exception_what_method(std::ostream& out, t_struct* tstruct); /** * Service-level generation functions */ void generate_service_interface(t_service* tservice, string style); void generate_service_interface_factory(t_service* tservice, string style); void generate_service_null(t_service* tservice, string style); void generate_service_multiface(t_service* tservice); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice, string style); void generate_service_processor(t_service* tservice, string style); void generate_service_skeleton(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction, string style, bool specialized = false); void generate_function_helpers(t_service* tservice, t_function* tfunction); void generate_service_async_skeleton(t_service* tservice); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", std::string suffix = ""); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "", bool pointer = false); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix, bool push_back, std::string index); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", std::string suffix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "", bool pointer = false); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string iter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); void generate_function_call(ostream& out, t_function* tfunction, string target, string iface, string arg_prefix); /* * Helper rendering functions */ std::string namespace_prefix(std::string ns); std::string namespace_open(std::string ns); std::string namespace_close(std::string ns); std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false); std::string base_type_name(t_base_type::t_base tbase); std::string declare_field(t_field* tfield, bool init = false, bool pointer = false, bool constant = false, bool reference = false); std::string function_signature(t_function* tfunction, std::string style, std::string prefix = "", bool name_params = true); std::string cob_function_signature(t_function* tfunction, std::string prefix = "", bool name_params = true); std::string argument_list(t_struct* tstruct, bool name_params = true, bool start_comma = false); std::string type_to_enum(t_type* ttype); void generate_enum_constant_list(std::ostream& f, const vector& constants, const char* prefix, const char* suffix, bool include_values); void generate_struct_ostream_operator_decl(std::ostream& f, t_struct* tstruct); void generate_struct_ostream_operator(std::ostream& f, t_struct* tstruct); void generate_struct_print_method_decl(std::ostream& f, t_struct* tstruct); void generate_exception_what_method_decl(std::ostream& f, t_struct* tstruct, bool external = false); bool is_reference(t_field* tfield) { return tfield->get_reference(); } bool is_complex_type(t_type* ttype) { ttype = get_true_type(ttype); return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || (ttype->is_base_type() && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING)); } void set_use_include_prefix(bool use_include_prefix) { use_include_prefix_ = use_include_prefix; } /** * The compiler option "no_thrift_ostream_impl" can be used to prevent * the compiler from emitting implementations for operator <<. In this * case the consuming application must provide any needed to build. * * To disable this on a per structure bases, one can alternatively set * the annotation "cpp.customostream" to prevent thrift from emitting an * operator << (std::ostream&). * * See AnnotationTest for validation of this annotation feature. */ bool has_custom_ostream(t_type* ttype) const { return (gen_no_ostream_operators_) || (ttype->annotations_.find("cpp.customostream") != ttype->annotations_.end()); } /** * Determine if all fields of t_struct's storage do not throw * Move/Copy Constructors and Assignments applicable for 'noexcept' * Move defaults to 'noexcept' */ bool is_struct_storage_not_throwing(t_struct* tstruct) const; private: /** * Returns the include prefix to use for a file generated by program, or the * empty string if no include prefix should be used. */ std::string get_include_prefix(const t_program& program) const; /** * Returns the legal program name to use for a file generated by program, if the * program name contains dots then replace it with underscores, otherwise return the * original program name. */ std::string get_legal_program_name(std::string program_name); /** * True if we should generate pure enums for Thrift enums, instead of wrapper classes. */ bool gen_pure_enums_; /** * True if we should generate templatized reader/writer methods. */ bool gen_templates_; /** * True iff we should generate process function pointers for only templatized * reader/writer methods. */ bool gen_templates_only_; /** * True if we should generate move constructors & assignment operators. */ bool gen_moveable_; /** * True if we should generate ostream definitions */ bool gen_no_ostream_operators_; /** * True iff we should use a path prefix in our #include statements for other * thrift-generated header files. */ bool use_include_prefix_; /** * True if we should generate "Continuation OBject"-style classes as well. */ bool gen_cob_style_; /** * True if we should omit calls to completion__() in CobClient class. */ bool gen_no_client_completion_; /** * True if we should omit generating the default opeartors ==, != and <. */ bool gen_no_default_operators_; /** * True if we should generate skeleton. */ bool gen_no_skeleton_; /** * True if thrift has member(s) */ bool has_members_; /** * Strings for namespace, computed once up front then used directly */ std::string ns_open_; std::string ns_close_; /** * File streams, stored here to avoid passing them as parameters to every * function. */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_types_impl_; ofstream_with_content_based_conditional_update f_types_tcc_; ofstream_with_content_based_conditional_update f_header_; ofstream_with_content_based_conditional_update f_service_; ofstream_with_content_based_conditional_update f_service_tcc_; // The ProcessorGenerator is used to generate parts of the code, // so it needs access to many of our protected members and methods. // // TODO: The code really should be cleaned up so that helper methods for // writing to the output files are separate from the generator classes // themselves. friend class ProcessorGenerator; }; /** * Prepares for file generation by opening up the necessary file output * streams. */ void t_cpp_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); program_name_ = get_legal_program_name(program_name_); // Make output file string f_types_name = get_out_dir() + program_name_ + "_types.h"; f_types_.open(f_types_name); string f_types_impl_name = get_out_dir() + program_name_ + "_types.cpp"; f_types_impl_.open(f_types_impl_name.c_str()); if (gen_templates_) { // If we don't open the stream, it appears to just discard data, // which is fine. string f_types_tcc_name = get_out_dir() + program_name_ + "_types.tcc"; f_types_tcc_.open(f_types_tcc_name.c_str()); } // Print header f_types_ << autogen_comment(); f_types_impl_ << autogen_comment(); f_types_tcc_ << autogen_comment(); // Start ifndef f_types_ << "#ifndef " << program_name_ << "_TYPES_H" << endl << "#define " << program_name_ << "_TYPES_H" << endl << endl; f_types_tcc_ << "#ifndef " << program_name_ << "_TYPES_TCC" << endl << "#define " << program_name_ << "_TYPES_TCC" << endl << endl; // Include base types f_types_ << "#include " << endl << endl << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl << endl; // Include C++xx compatibility header f_types_ << "#include " << endl; f_types_ << "#include " << endl; // Include other Thrift includes const vector& includes = program_->get_includes(); for (auto include : includes) { f_types_ << "#include \"" << get_include_prefix(*include) << include->get_name() << "_types.h\"" << endl; // XXX(simpkins): If gen_templates_ is enabled, we currently assume all // included files were also generated with templates enabled. f_types_tcc_ << "#include \"" << get_include_prefix(*include) << include->get_name() << "_types.tcc\"" << endl; } f_types_ << endl; // Include custom headers const vector& cpp_includes = program_->get_cpp_includes(); for (const auto & cpp_include : cpp_includes) { if (cpp_include[0] == '<') { f_types_ << "#include " << cpp_include << endl; } else { f_types_ << "#include \"" << cpp_include << "\"" << endl; } } f_types_ << endl; // Include the types file f_types_impl_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\"" << endl << endl; f_types_tcc_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\"" << endl << endl; // The swap() code needs for std::swap() f_types_impl_ << "#include " << endl; // for operator<< f_types_impl_ << "#include " << endl << endl; f_types_impl_ << "#include " << endl << endl; // Open namespace ns_open_ = namespace_open(program_->get_namespace("cpp")); ns_close_ = namespace_close(program_->get_namespace("cpp")); f_types_ << ns_open_ << endl << endl; f_types_impl_ << ns_open_ << endl << endl; f_types_tcc_ << ns_open_ << endl << endl; } /** * Closes the output files. */ void t_cpp_generator::close_generator() { // Close namespace f_types_ << ns_close_ << endl << endl; f_types_impl_ << ns_close_ << endl; f_types_tcc_ << ns_close_ << endl << endl; // Include the types.tcc file from the types header file, // so clients don't have to explicitly include the tcc file. // TODO(simpkins): Make this a separate option. if (gen_templates_) { f_types_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.tcc\"" << endl << endl; } // Close ifndef f_types_ << "#endif" << endl; f_types_tcc_ << "#endif" << endl; // Close output file f_types_.close(); f_types_impl_.close(); f_types_tcc_.close(); string f_types_impl_name = get_out_dir() + program_name_ + "_types.cpp"; if (!has_members_) { remove(f_types_impl_name.c_str()); } } /** * Generates a typedef. This is just a simple 1-liner in C++ * * @param ttypedef The type definition */ void t_cpp_generator::generate_typedef(t_typedef* ttypedef) { generate_java_doc(f_types_, ttypedef); f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << ttypedef->get_symbolic() << ";" << endl << endl; } void t_cpp_generator::generate_enum_constant_list(std::ostream& f, const vector& constants, const char* prefix, const char* suffix, bool include_values) { f << " {" << endl; indent_up(); vector::const_iterator c_iter; bool first = true; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { if (first) { first = false; } else { f << "," << endl; } generate_java_doc(f, *c_iter); indent(f) << prefix << (*c_iter)->get_name() << suffix; if (include_values) { f << " = " << (*c_iter)->get_value(); } } f << endl; indent_down(); indent(f) << "};" << endl; } /** * Generates code for an enumerated type. In C++, this is essentially the same * as the thrift definition itself, using the enum keyword in C++. * * @param tenum The enumeration */ void t_cpp_generator::generate_enum(t_enum* tenum) { vector constants = tenum->get_constants(); std::string enum_name = tenum->get_name(); if (!gen_pure_enums_) { enum_name = "type"; generate_java_doc(f_types_, tenum); f_types_ << indent() << "struct " << tenum->get_name() << " {" << endl; indent_up(); } f_types_ << indent() << "enum " << enum_name; generate_enum_constant_list(f_types_, constants, "", "", true); if (!gen_pure_enums_) { indent_down(); f_types_ << "};" << endl; } f_types_ << endl; /** Generate a character array of enum names for debugging purposes. */ std::string prefix = ""; if (!gen_pure_enums_) { prefix = tenum->get_name() + "::"; } f_types_impl_ << indent() << "int _k" << tenum->get_name() << "Values[] ="; generate_enum_constant_list(f_types_impl_, constants, prefix.c_str(), "", false); f_types_impl_ << indent() << "const char* _k" << tenum->get_name() << "Names[] ="; generate_enum_constant_list(f_types_impl_, constants, "\"", "\"", false); f_types_ << indent() << "extern const std::map _" << tenum->get_name() << "_VALUES_TO_NAMES;" << endl << endl; f_types_impl_ << indent() << "const std::map _" << tenum->get_name() << "_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(" << constants.size() << ", _k" << tenum->get_name() << "Values" << ", _k" << tenum->get_name() << "Names), " << "::apache::thrift::TEnumIterator(-1, nullptr, nullptr));" << endl << endl; generate_enum_ostream_operator_decl(f_types_, tenum); generate_enum_ostream_operator(f_types_impl_, tenum); generate_enum_to_string_helper_function_decl(f_types_, tenum); generate_enum_to_string_helper_function(f_types_impl_, tenum); has_members_ = true; } void t_cpp_generator::generate_enum_ostream_operator_decl(std::ostream& out, t_enum* tenum) { out << "std::ostream& operator<<(std::ostream& out, const "; if (gen_pure_enums_) { out << tenum->get_name(); } else { out << tenum->get_name() << "::type&"; } out << " val);" << endl; out << endl; } void t_cpp_generator::generate_enum_ostream_operator(std::ostream& out, t_enum* tenum) { // If we've been told the consuming application will provide an ostream // operator definition then we only make a declaration: if (!has_custom_ostream(tenum)) { out << "std::ostream& operator<<(std::ostream& out, const "; if (gen_pure_enums_) { out << tenum->get_name(); } else { out << tenum->get_name() << "::type&"; } out << " val) "; scope_up(out); out << indent() << "std::map::const_iterator it = _" << tenum->get_name() << "_VALUES_TO_NAMES.find(val);" << endl; out << indent() << "if (it != _" << tenum->get_name() << "_VALUES_TO_NAMES.end()) {" << endl; indent_up(); out << indent() << "out << it->second;" << endl; indent_down(); out << indent() << "} else {" << endl; indent_up(); out << indent() << "out << static_cast(val);" << endl; indent_down(); out << indent() << "}" << endl; out << indent() << "return out;" << endl; scope_down(out); out << endl; } } void t_cpp_generator::generate_enum_to_string_helper_function_decl(std::ostream& out, t_enum* tenum) { out << "std::string to_string(const "; if (gen_pure_enums_) { out << tenum->get_name(); } else { out << tenum->get_name() << "::type&"; } out << " val);" << endl; out << endl; } void t_cpp_generator::generate_enum_to_string_helper_function(std::ostream& out, t_enum* tenum) { if (!has_custom_ostream(tenum)) { out << "std::string to_string(const "; if (gen_pure_enums_) { out << tenum->get_name(); } else { out << tenum->get_name() << "::type&"; } out << " val) " ; scope_up(out); out << indent() << "std::map::const_iterator it = _" << tenum->get_name() << "_VALUES_TO_NAMES.find(val);" << endl; out << indent() << "if (it != _" << tenum->get_name() << "_VALUES_TO_NAMES.end()) {" << endl; indent_up(); out << indent() << "return std::string(it->second);" << endl; indent_down(); out << indent() << "} else {" << endl; indent_up(); out << indent() << "return std::to_string(static_cast(val));" << endl; indent_down(); out << indent() << "}" << endl; scope_down(out); out << endl; } } /** * Generates a class that holds all the constants. */ void t_cpp_generator::generate_consts(std::vector consts) { string f_consts_name = get_out_dir() + program_name_ + "_constants.h"; ofstream_with_content_based_conditional_update f_consts; if (consts.size() > 0) { f_consts.open(f_consts_name); string f_consts_impl_name = get_out_dir() + program_name_ + "_constants.cpp"; ofstream_with_content_based_conditional_update f_consts_impl; f_consts_impl.open(f_consts_impl_name); // Print header f_consts << autogen_comment(); f_consts_impl << autogen_comment(); // Start ifndef f_consts << "#ifndef " << program_name_ << "_CONSTANTS_H" << endl << "#define " << program_name_ << "_CONSTANTS_H" << endl << endl << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\"" << endl << endl << ns_open_ << endl << endl; f_consts_impl << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_constants.h\"" << endl << endl << ns_open_ << endl << endl; f_consts << "class " << program_name_ << "Constants {" << endl << " public:" << endl << " " << program_name_ << "Constants();" << endl << endl; indent_up(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { string name = (*c_iter)->get_name(); t_type* type = (*c_iter)->get_type(); f_consts << indent() << type_name(type) << " " << name << ";" << endl; } indent_down(); f_consts << "};" << endl; f_consts_impl << "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl << endl << program_name_ << "Constants::" << program_name_ << "Constants() {" << endl; indent_up(); for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { print_const_value(f_consts_impl, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value()); } indent_down(); indent(f_consts_impl) << "}" << endl; f_consts << endl << "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl << endl << ns_close_ << endl << endl << "#endif" << endl; f_consts.close(); f_consts_impl << endl << ns_close_ << endl << endl; f_consts_impl.close(); } } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ void t_cpp_generator::print_const_value(ostream& out, string name, t_type* type, t_const_value* value) { type = get_true_type(type); if (type->is_base_type()) { string v2 = render_const_value(out, name, type, value); indent(out) << name << " = " << v2 << ";" << endl << endl; } else if (type->is_enum()) { indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl << endl; } else if (type->is_struct() || type->is_xception()) { const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; bool is_nonrequired_field = false; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; is_nonrequired_field = false; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); is_nonrequired_field = (*f_iter)->get_req() != t_field::T_REQUIRED; } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string val = render_const_value(out, name, field_type, v_iter->second); indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl; if (is_nonrequired_field) { indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl; } } out << endl; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(out, name, ktype, v_iter->first); string val = render_const_value(out, name, vtype, v_iter->second); indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl; } out << endl; } else if (type->is_list()) { t_type* etype = ((t_list*)type)->get_elem_type(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(out, name, etype, *v_iter); indent(out) << name << ".push_back(" << val << ");" << endl; } out << endl; } else if (type->is_set()) { t_type* etype = ((t_set*)type)->get_elem_type(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(out, name, etype, *v_iter); indent(out) << name << ".insert(" << val << ");" << endl; } out << endl; } else { throw "INVALID TYPE IN print_const_value: " + type->get_name(); } } /** * */ string t_cpp_generator::render_const_value(ostream& out, string name, t_type* type, t_const_value* value) { (void)name; std::ostringstream render; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: render << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: render << value->get_integer(); break; case t_base_type::TYPE_I64: render << value->get_integer() << "LL"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << "static_cast(" << value->get_integer() << ")"; } else { render << emit_double_as_string(value->get_double()); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { render << "(" << type_name(type) << ")" << value->get_integer(); } else { string t = tmp("tmp"); indent(out) << type_name(type) << " " << t << ";" << endl; print_const_value(out, t, type, value); render << t; } return render.str(); } void t_cpp_generator::generate_forward_declaration(t_struct* tstruct) { // Forward declare struct def f_types_ << indent() << "class " << tstruct->get_name() << ";" << endl << endl; } /** * Generates a struct definition for a thrift data type. This is a class * with data members and a read/write() function, plus a mirroring isset * inner class. * * @param tstruct The struct definition */ void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) { generate_struct_declaration(f_types_, tstruct, is_exception, false, true, true, true, true); generate_struct_definition(f_types_impl_, f_types_impl_, tstruct, true, true); std::ostream& out = (gen_templates_ ? f_types_tcc_ : f_types_impl_); generate_struct_reader(out, tstruct); generate_struct_writer(out, tstruct); generate_struct_swap(f_types_impl_, tstruct); generate_copy_constructor(f_types_impl_, tstruct, is_exception); if (gen_moveable_) { generate_move_constructor(f_types_impl_, tstruct, is_exception); } generate_assignment_operator(f_types_impl_, tstruct); if (gen_moveable_) { generate_move_assignment_operator(f_types_impl_, tstruct); } if (!has_custom_ostream(tstruct)) { generate_struct_print_method(f_types_impl_, tstruct); } if (is_exception) { generate_exception_what_method(f_types_impl_, tstruct); } has_members_ = true; } void t_cpp_generator::generate_copy_constructor(ostream& out, t_struct* tstruct, bool is_exception) { generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/false); } void t_cpp_generator::generate_move_constructor(ostream& out, t_struct* tstruct, bool is_exception) { generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/true); } namespace { // Helper to convert a variable to rvalue, if move is enabled std::string maybeMove(std::string const& other, bool move) { if (move) { return "std::move(" + other + ")"; } return other; } } void t_cpp_generator::generate_constructor_helper(ostream& out, t_struct* tstruct, bool is_exception, bool is_move) { std::string tmp_name = tmp("other"); indent(out) << tstruct->get_name() << "::" << tstruct->get_name(); if (is_move) { out << "(" << tstruct->get_name() << "&& "; } else { out << "(const " << tstruct->get_name() << "& "; } out << tmp_name << ") "; if(is_move || is_struct_storage_not_throwing(tstruct)) out << "noexcept "; if (is_exception) out << ": TException() "; out << "{" << endl; indent_up(); const vector& members = tstruct->get_members(); // eliminate compiler unused warning if (members.empty()) indent(out) << "(void) " << tmp_name << ";" << endl; vector::const_iterator f_iter; bool has_nonrequired_fields = false; for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { if ((*f_iter)->get_req() != t_field::T_REQUIRED) has_nonrequired_fields = true; indent(out) << (*f_iter)->get_name() << " = " << maybeMove( tmp_name + "." + (*f_iter)->get_name(), is_move && is_complex_type((*f_iter)->get_type())) << ";" << endl; } if (has_nonrequired_fields) { indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", false) << ";" << endl; } indent_down(); indent(out) << "}" << endl; } void t_cpp_generator::generate_assignment_operator(ostream& out, t_struct* tstruct) { generate_assignment_helper(out, tstruct, /*is_move=*/false); } void t_cpp_generator::generate_move_assignment_operator(ostream& out, t_struct* tstruct) { generate_assignment_helper(out, tstruct, /*is_move=*/true); } void t_cpp_generator::generate_assignment_helper(ostream& out, t_struct* tstruct, bool is_move) { std::string tmp_name = tmp("other"); indent(out) << tstruct->get_name() << "& " << tstruct->get_name() << "::operator=("; if (is_move) { out << tstruct->get_name() << "&& "; } else { out << "const " << tstruct->get_name() << "& "; } out << tmp_name << ") "; if(is_move || is_struct_storage_not_throwing(tstruct)) out << "noexcept "; out << "{" << endl; indent_up(); const vector& members = tstruct->get_members(); // eliminate compiler unused warning if (members.empty()) indent(out) << "(void) " << tmp_name << ";" << endl; vector::const_iterator f_iter; bool has_nonrequired_fields = false; for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { if ((*f_iter)->get_req() != t_field::T_REQUIRED) has_nonrequired_fields = true; indent(out) << (*f_iter)->get_name() << " = " << maybeMove( tmp_name + "." + (*f_iter)->get_name(), is_move && is_complex_type((*f_iter)->get_type())) << ";" << endl; } if (has_nonrequired_fields) { indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", false) << ";" << endl; } indent(out) << "return *this;" << endl; indent_down(); indent(out) << "}" << endl; } /** * Writes the struct declaration into the header file * * @param out Output stream * @param tstruct The struct */ void t_cpp_generator::generate_struct_declaration(ostream& out, t_struct* tstruct, bool is_exception, bool pointers, bool read, bool write, bool swap, bool is_user_struct) { string extends = ""; if (is_exception) { extends = " : public ::apache::thrift::TException"; } else { if (is_user_struct && !gen_templates_) { extends = " : public virtual ::apache::thrift::TBase"; } } // Get members vector::const_iterator m_iter; const vector& members = tstruct->get_members(); // Write the isset structure declaration outside the class. This makes // the generated code amenable to processing by SWIG. // We only declare the struct if it gets used in the class. // Isset struct has boolean fields, but only for non-required fields. bool has_nonrequired_fields = false; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_REQUIRED) has_nonrequired_fields = true; } if (has_nonrequired_fields && (!pointers || read)) { out << indent() << "typedef struct _" << tstruct->get_name() << "__isset {" << endl; indent_up(); indent(out) << "_" << tstruct->get_name() << "__isset() "; bool first = true; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() == t_field::T_REQUIRED) { continue; } string isSet = ((*m_iter)->get_value() != nullptr) ? "true" : "false"; if (first) { first = false; out << ": " << (*m_iter)->get_name() << "(" << isSet << ")"; } else { out << ", " << (*m_iter)->get_name() << "(" << isSet << ")"; } } out << " {}" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_REQUIRED) { indent(out) << "bool " << (*m_iter)->get_name() << " :1;" << endl; } } indent_down(); indent(out) << "} _" << tstruct->get_name() << "__isset;" << endl; } out << endl; generate_java_doc(out, tstruct); // Open struct def out << indent() << "class " << tstruct->get_name() << extends << " {" << endl << indent() << " public:" << endl << endl; indent_up(); if (!pointers) { bool ok_noexcept = is_struct_storage_not_throwing(tstruct); // Copy constructor indent(out) << tstruct->get_name() << "(const " << tstruct->get_name() << "&)" << (ok_noexcept? " noexcept" : "") << ';' << endl; // Move constructor if (gen_moveable_) { indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&) noexcept;" << endl; } // Assignment Operator indent(out) << tstruct->get_name() << "& operator=(const " << tstruct->get_name() << "&)" << (ok_noexcept? " noexcept" : "") << ';' << endl; // Move assignment operator if (gen_moveable_) { indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&) noexcept;" << endl; } bool has_default_value = false; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if (is_reference(*m_iter) || t->is_string()) { t_const_value* cv = (*m_iter)->get_value(); if (cv != nullptr) { has_default_value = true; break; } } } // Default constructor std::string clsname_ctor = tstruct->get_name() + "()"; indent(out) << clsname_ctor << (has_default_value ? "" : " noexcept"); bool init_ctor = false; std::string args_indent( indent().size() + clsname_ctor.size() + (has_default_value ? 3 : -1), ' '); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if (t->is_base_type() || t->is_enum() || is_reference(*m_iter)) { string dval; t_const_value* cv = (*m_iter)->get_value(); if (cv != nullptr) { dval += render_const_value(out, (*m_iter)->get_name(), t, cv); } else if (t->is_enum()) { dval += "static_cast<" + type_name(t) + ">(0)"; } else { dval += (t->is_string() || is_reference(*m_iter)) ? "" : "0"; } if (!init_ctor) { init_ctor = true; if(has_default_value) { out << " : "; } else { out << '\n' << args_indent << ": "; args_indent.append(" "); } } else { out << ",\n" << args_indent; } out << (*m_iter)->get_name() << "(" << dval << ")"; } } out << " {" << endl; indent_up(); // TODO(dreiss): When everything else in Thrift is perfect, // do more of these in the initializer list. for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if (!t->is_base_type()) { t_const_value* cv = (*m_iter)->get_value(); if (cv != nullptr) { print_const_value(out, (*m_iter)->get_name(), t, cv); } } } scope_down(out); } if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) { out << endl << indent() << "virtual ~" << tstruct->get_name() << "() noexcept;" << endl; } // Declare all fields for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_java_doc(out, *m_iter); indent(out) << declare_field(*m_iter, false, (pointers && !(*m_iter)->get_type()->is_xception()), !read) << endl; } // Add the __isset data member if we need it, using the definition from above if (has_nonrequired_fields && (!pointers || read)) { out << endl << indent() << "_" << tstruct->get_name() << "__isset __isset;" << endl; } // Create a setter function for each field for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (pointers) { continue; } if (is_reference((*m_iter))) { out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "(::std::shared_ptr<" << type_name((*m_iter)->get_type(), false, false) << ">"; out << " val);" << endl; } else { out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type(), false, true); out << " val);" << endl; } } out << endl; if (!pointers) { // Should we generate default operators? if (!gen_no_default_operators_) { // Generate an equality testing operator. Make it inline since the compiler // will do a better job than we would when deciding whether to inline it. out << indent() << "bool operator == (const " << tstruct->get_name() << " & " << (members.size() > 0 ? "rhs" : "/* rhs */") << ") const" << endl; scope_up(out); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { // Most existing Thrift code does not use isset or optional/required, // so we treat "default" fields as required. if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { out << indent() << "if (!(" << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name() << "))" << endl << indent() << " return false;" << endl; } else { out << indent() << "if (__isset." << (*m_iter)->get_name() << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl << indent() << " return false;" << endl << indent() << "else if (__isset." << (*m_iter)->get_name() << " && !(" << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name() << "))" << endl << indent() << " return false;" << endl; } } indent(out) << "return true;" << endl; scope_down(out); out << indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl << indent() << " return !(*this == rhs);" << endl << indent() << "}" << endl << endl; // Generate the declaration of a less-than operator. This must be // implemented by the application developer if they wish to use it. (They // will get a link error if they try to use it without an implementation.) out << indent() << "bool operator < (const " << tstruct->get_name() << " & ) const;" << endl << endl; } } if (read) { if (gen_templates_) { out << indent() << "template " << endl << indent() << "uint32_t read(Protocol_* iprot);" << endl; } else { out << indent() << "uint32_t read(" << "::apache::thrift::protocol::TProtocol* iprot)"; if(!is_exception && !extends.empty()) out << " override"; out << ';' << endl; } } if (write) { if (gen_templates_) { out << indent() << "template " << endl << indent() << "uint32_t write(Protocol_* oprot) const;" << endl; } else { out << indent() << "uint32_t write(" << "::apache::thrift::protocol::TProtocol* oprot) const"; if(!is_exception && !extends.empty()) out << " override"; out << ';' << endl; } } out << endl; if (is_user_struct && !has_custom_ostream(tstruct)) { out << indent() << "virtual "; generate_struct_print_method_decl(out, nullptr); out << ";" << endl; } // std::exception::what() if (is_exception) { out << indent() << "mutable std::string thriftTExceptionMessageHolder_;" << endl; out << indent(); generate_exception_what_method_decl(out, tstruct, false); out << ";" << endl; } indent_down(); indent(out) << "};" << endl << endl; if (swap) { // Generate a namespace-scope swap() function if (tstruct->get_name() == "a" || tstruct->get_name() == "b") { out << indent() << "void swap(" << tstruct->get_name() << " &a1, " << tstruct->get_name() << " &a2);" << endl << endl; } else { out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name() << " &b);" << endl << endl; } } if (is_user_struct) { generate_struct_ostream_operator_decl(out, tstruct); } } void t_cpp_generator::generate_struct_definition(ostream& out, ostream& force_cpp_out, t_struct* tstruct, bool setters, bool is_user_struct) { // Get members vector::const_iterator m_iter; const vector& members = tstruct->get_members(); // Destructor if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) { force_cpp_out << endl << indent() << tstruct->get_name() << "::~" << tstruct->get_name() << "() noexcept {" << endl; indent_up(); indent_down(); force_cpp_out << indent() << "}" << endl << endl; } // Create a setter function for each field if (setters) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (is_reference((*m_iter))) { out << endl << indent() << "void " << tstruct->get_name() << "::__set_" << (*m_iter)->get_name() << "(::std::shared_ptr<" << type_name((*m_iter)->get_type(), false, false) << ">"; out << " val) {" << endl; } else { out << endl << indent() << "void " << tstruct->get_name() << "::__set_" << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type(), false, true); out << " val) {" << endl; } indent_up(); out << indent() << "this->" << (*m_iter)->get_name() << " = val;" << endl; indent_down(); // assume all fields are required except optional fields. // for optional fields change __isset.name to true bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; if (is_optional) { out << indent() << indent() << "__isset." << (*m_iter)->get_name() << " = true;" << endl; } out << indent() << "}" << endl; } } if (is_user_struct) { generate_struct_ostream_operator(out, tstruct); } out << endl; } /** * Makes a helper function to gen a struct reader. * * @param out Stream to write to * @param tstruct The struct */ void t_cpp_generator::generate_struct_reader(ostream& out, t_struct* tstruct, bool pointers) { if (gen_templates_) { out << indent() << "template " << endl << indent() << "uint32_t " << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl; } else { indent(out) << "uint32_t " << tstruct->get_name() << "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl; } indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // Declare stack tmp variables out << endl << indent() << "::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot);" << endl << indent() << "uint32_t xfer = 0;" << endl << indent() << "std::string fname;" << endl << indent() << "::apache::thrift::protocol::TType ftype;" << endl << indent() << "int16_t fid;" << endl << endl << indent() << "xfer += iprot->readStructBegin(fname);" << endl << endl << indent() << "using ::apache::thrift::protocol::TProtocolException;" << endl << endl; // Required variables aren't in __isset, so we need tmp vars to check them. for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl; } out << endl; // Loop over reading in fields indent(out) << "while (true)" << endl; scope_up(out); // Read beginning field marker indent(out) << "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl; // Check for field STOP marker out << indent() << "if (ftype == ::apache::thrift::protocol::T_STOP) {" << endl << indent() << " break;" << endl << indent() << "}" << endl; if (fields.empty()) { out << indent() << "xfer += iprot->skip(ftype);" << endl; } else { // Switch statement on the field we are reading indent(out) << "switch (fid)" << endl; scope_up(out); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); const char* isset_prefix = ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." : "isset_"; #if 0 // This code throws an exception if the same field is encountered twice. // We've decided to leave it out for performance reasons. // TODO(dreiss): Generate this code and "if" it out to make it easier // for people recompiling thrift to include it. out << indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl << indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; #endif if (pointers && !(*f_iter)->get_type()->is_xception()) { generate_deserialize_field(out, *f_iter, "(*(this->", "))"); } else { generate_deserialize_field(out, *f_iter, "this->"); } out << indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl; indent_down(); out << indent() << "} else {" << endl << indent() << " xfer += iprot->skip(ftype);" << endl << // TODO(dreiss): Make this an option when thrift structs // have a common base class. // indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl << indent() << "}" << endl << indent() << "break;" << endl; indent_down(); } // In the default case we skip the field out << indent() << "default:" << endl << indent() << " xfer += iprot->skip(ftype);" << endl << indent() << " break;" << endl; scope_down(out); } //!fields.empty() // Read field end marker indent(out) << "xfer += iprot->readFieldEnd();" << endl; scope_down(out); out << endl << indent() << "xfer += iprot->readStructEnd();" << endl; // Throw if any required fields are missing. // We do this after reading the struct end so that // there might possibly be a chance of continuing. out << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) out << indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl << indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; } indent(out) << "return xfer;" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates the write function. * * @param out Stream to write to * @param tstruct The struct */ void t_cpp_generator::generate_struct_writer(ostream& out, t_struct* tstruct, bool pointers) { string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; if (gen_templates_) { out << indent() << "template " << endl << indent() << "uint32_t " << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl; } else { indent(out) << "uint32_t " << tstruct->get_name() << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl; } indent_up(); out << indent() << "uint32_t xfer = 0;" << endl; indent(out) << "::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot);" << endl; indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool check_if_set = (*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_type()->is_xception(); if (check_if_set) { out << endl << indent() << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl; indent_up(); } else { out << endl; } // Write field header out << indent() << "xfer += oprot->writeFieldBegin(" << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ");" << endl; // Write field contents if (pointers && !(*f_iter)->get_type()->is_xception()) { generate_serialize_field(out, *f_iter, "(*(this->", "))"); } else { generate_serialize_field(out, *f_iter, "this->"); } // Write field closer indent(out) << "xfer += oprot->writeFieldEnd();" << endl; if (check_if_set) { indent_down(); indent(out) << '}'; } } out << endl; // Write the struct map out << indent() << "xfer += oprot->writeFieldStop();" << endl << indent() << "xfer += oprot->writeStructEnd();" << endl << indent() << "return xfer;" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Struct writer for result of a function, which can have only one of its * fields set and does a conditional if else look up into the __isset field * of the struct. * * @param out Output stream * @param tstruct The result struct */ void t_cpp_generator::generate_struct_result_writer(ostream& out, t_struct* tstruct, bool pointers) { string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; if (gen_templates_) { out << indent() << "template " << endl << indent() << "uint32_t " << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl; } else { indent(out) << "uint32_t " << tstruct->get_name() << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl; } indent_up(); out << endl << indent() << "uint32_t xfer = 0;" << endl << endl; indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; out << endl << indent() << "if "; } else { out << " else if "; } out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl; indent_up(); // Write field header out << indent() << "xfer += oprot->writeFieldBegin(" << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ");" << endl; // Write field contents if (pointers) { generate_serialize_field(out, *f_iter, "(*(this->", "))"); } else { generate_serialize_field(out, *f_iter, "this->"); } // Write field closer indent(out) << "xfer += oprot->writeFieldEnd();" << endl; indent_down(); indent(out) << "}"; } // Write the struct map out << endl << indent() << "xfer += oprot->writeFieldStop();" << endl << indent() << "xfer += oprot->writeStructEnd();" << endl << indent() << "return xfer;" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates the swap function. * * @param out Stream to write to * @param tstruct The struct */ void t_cpp_generator::generate_struct_swap(ostream& out, t_struct* tstruct) { if (tstruct->get_name() == "a" || tstruct->get_name() == "b") { out << indent() << "void swap(" << tstruct->get_name() << " &a1, " << tstruct->get_name() << " &a2) {" << endl; } else { out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name() << " &b) {" << endl; } indent_up(); // Let argument-dependent name lookup find the correct swap() function to // use based on the argument types. If none is found in the arguments' // namespaces, fall back to ::std::swap(). out << indent() << "using ::std::swap;" << endl; bool has_nonrequired_fields = false; const vector& fields = tstruct->get_members(); for (auto tfield : fields) { if (tfield->get_req() != t_field::T_REQUIRED) { has_nonrequired_fields = true; } if (tstruct->get_name() == "a" || tstruct->get_name() == "b") { out << indent() << "swap(a1." << tfield->get_name() << ", a2." << tfield->get_name() << ");" << endl; } else { out << indent() << "swap(a." << tfield->get_name() << ", b." << tfield->get_name() << ");" << endl; } } if (has_nonrequired_fields) { if (tstruct->get_name() == "a" || tstruct->get_name() == "b") { out << indent() << "swap(a1.__isset, a2.__isset);" << endl; } else { out << indent() << "swap(a.__isset, b.__isset);" << endl; } } // handle empty structs if (fields.size() == 0) { if (tstruct->get_name() == "a" || tstruct->get_name() == "b") { out << indent() << "(void) a1;" << endl; out << indent() << "(void) a2;" << endl; } else { out << indent() << "(void) a;" << endl; out << indent() << "(void) b;" << endl; } } scope_down(out); out << endl; } void t_cpp_generator::generate_struct_ostream_operator_decl(std::ostream& out, t_struct* tstruct) { out << "std::ostream& operator<<(std::ostream& out, const " << tstruct->get_name() << "& obj);" << endl; out << endl; } void t_cpp_generator::generate_struct_ostream_operator(std::ostream& out, t_struct* tstruct) { if (!has_custom_ostream(tstruct)) { // thrift defines this behavior out << "std::ostream& operator<<(std::ostream& out, const " << tstruct->get_name() << "& obj)" << endl; scope_up(out); out << indent() << "obj.printTo(out);" << endl << indent() << "return out;" << endl; scope_down(out); out << endl; } } void t_cpp_generator::generate_struct_print_method_decl(std::ostream& out, t_struct* tstruct) { out << "void "; if (tstruct) { out << tstruct->get_name() << "::"; } out << "printTo(std::ostream& out) const"; } void t_cpp_generator::generate_exception_what_method_decl(std::ostream& out, t_struct* tstruct, bool external) { out << "const char* "; if (external) { out << tstruct->get_name() << "::"; } out << "what() const noexcept"; if(!external) out << " override"; } namespace struct_ostream_operator_generator { void generate_required_field_value(std::ostream& out, const t_field* field) { out << " << to_string(" << field->get_name() << ")"; } void generate_optional_field_value(std::ostream& out, const t_field* field) { out << "; (__isset." << field->get_name() << " ? (out"; generate_required_field_value(out, field); out << ") : (out << \"\"))"; } void generate_field_value(std::ostream& out, const t_field* field) { if (field->get_req() == t_field::T_OPTIONAL) generate_optional_field_value(out, field); else generate_required_field_value(out, field); } void generate_field_name(std::ostream& out, const t_field* field) { out << "\"" << field->get_name() << "=\""; } void generate_field(std::ostream& out, const t_field* field) { generate_field_name(out, field); generate_field_value(out, field); } void generate_fields(std::ostream& out, const vector& fields, const std::string& indent) { const vector::const_iterator beg = fields.begin(); const vector::const_iterator end = fields.end(); for (vector::const_iterator it = beg; it != end; ++it) { out << indent << "out << "; if (it != beg) { out << "\", \" << "; } generate_field(out, *it); out << ";" << endl; } } } /** * Generates operator<< */ void t_cpp_generator::generate_struct_print_method(std::ostream& out, t_struct* tstruct) { out << indent(); generate_struct_print_method_decl(out, tstruct); out << " {" << endl; indent_up(); out << indent() << "using ::apache::thrift::to_string;" << endl; out << indent() << "out << \"" << tstruct->get_name() << "(\";" << endl; struct_ostream_operator_generator::generate_fields(out, tstruct->get_members(), indent()); out << indent() << "out << \")\";" << endl; indent_down(); out << "}" << endl << endl; } /** * Generates what() method for exceptions */ void t_cpp_generator::generate_exception_what_method(std::ostream& out, t_struct* tstruct) { out << indent(); generate_exception_what_method_decl(out, tstruct, true); out << " {" << endl; indent_up(); out << indent() << "try {" << endl; indent_up(); out << indent() << "std::stringstream ss;" << endl; out << indent() << "ss << \"TException - service has thrown: \" << *this;" << endl; out << indent() << "this->thriftTExceptionMessageHolder_ = ss.str();" << endl; out << indent() << "return this->thriftTExceptionMessageHolder_.c_str();" << endl; indent_down(); out << indent() << "} catch (const std::exception&) {" << endl; indent_up(); out << indent() << "return \"TException - service has thrown: " << tstruct->get_name() << "\";" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << "}" << endl << endl; } /** * Generates a thrift service. In C++, this comprises an entirely separate * header and source file. The header file defines the methods and includes * the data types defined in the main header file, and the implementation * file contains implementations of the basic printer and default interfaces. * * @param tservice The service definition */ void t_cpp_generator::generate_service(t_service* tservice) { string svcname = tservice->get_name(); // Make output files string f_header_name = get_out_dir() + svcname + ".h"; f_header_.open(f_header_name.c_str()); // Print header file includes f_header_ << autogen_comment(); f_header_ << "#ifndef " << svcname << "_H" << endl << "#define " << svcname << "_H" << endl << endl; if (gen_cob_style_) { f_header_ << "#include " << endl // TMemoryBuffer << "#include " << endl << "namespace apache { namespace thrift { namespace async {" << endl << "class TAsyncChannel;" << endl << "}}}" << endl; } f_header_ << "#include " << endl; if (gen_cob_style_) { f_header_ << "#include " << endl; } f_header_ << "#include " << endl; f_header_ << "#include " << endl; f_header_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\"" << endl; t_service* extends_service = tservice->get_extends(); if (extends_service != nullptr) { f_header_ << "#include \"" << get_include_prefix(*(extends_service->get_program())) << extends_service->get_name() << ".h\"" << endl; } f_header_ << endl << ns_open_ << endl << endl; f_header_ << "#ifdef _MSC_VER\n" " #pragma warning( push )\n" " #pragma warning (disable : 4250 ) //inheriting methods via dominance \n" "#endif\n\n"; // Service implementation file includes string f_service_name = get_out_dir() + svcname + ".cpp"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment(); f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl; if (gen_cob_style_) { f_service_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl; } if (gen_templates_) { f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\"" << endl; string f_service_tcc_name = get_out_dir() + svcname + ".tcc"; f_service_tcc_.open(f_service_tcc_name.c_str()); f_service_tcc_ << autogen_comment(); f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl; f_service_tcc_ << "#ifndef " << svcname << "_TCC" << endl << "#define " << svcname << "_TCC" << endl << endl; if (gen_cob_style_) { f_service_tcc_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl; } } f_service_ << endl << ns_open_ << endl << endl; f_service_tcc_ << endl << ns_open_ << endl << endl; // Generate all the components generate_service_interface(tservice, ""); generate_service_interface_factory(tservice, ""); generate_service_null(tservice, ""); generate_service_helpers(tservice); generate_service_client(tservice, ""); generate_service_processor(tservice, ""); generate_service_multiface(tservice); generate_service_client(tservice, "Concurrent"); // Generate skeleton if (!gen_no_skeleton_) { generate_service_skeleton(tservice); } // Generate all the cob components if (gen_cob_style_) { generate_service_interface(tservice, "CobCl"); generate_service_interface(tservice, "CobSv"); generate_service_interface_factory(tservice, "CobSv"); generate_service_null(tservice, "CobSv"); generate_service_client(tservice, "Cob"); generate_service_processor(tservice, "Cob"); if (!gen_no_skeleton_) { generate_service_async_skeleton(tservice); } } f_header_ << "#ifdef _MSC_VER\n" " #pragma warning( pop )\n" "#endif\n\n"; // Close the namespace f_service_ << ns_close_ << endl << endl; f_service_tcc_ << ns_close_ << endl << endl; f_header_ << ns_close_ << endl << endl; // TODO(simpkins): Make this a separate option if (gen_templates_) { f_header_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\"" << endl << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.tcc\"" << endl << endl; } f_header_ << "#endif" << endl; f_service_tcc_ << "#endif" << endl; // Close the files f_service_tcc_.close(); f_service_.close(); f_header_.close(); } /** * Generates helper functions for a service. Basically, this generates types * for all the arguments and results to functions. * * @param tservice The service to generate a header definition for */ void t_cpp_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); string name_orig = ts->get_name(); // TODO(dreiss): Why is this stuff not in generate_function_helpers? ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args"); generate_struct_declaration(f_header_, ts, false); generate_struct_definition(out, f_service_, ts, false); generate_struct_reader(out, ts); generate_struct_writer(out, ts); ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs"); generate_struct_declaration(f_header_, ts, false, true, false, true); generate_struct_definition(out, f_service_, ts, false); generate_struct_writer(out, ts, true); ts->set_name(name_orig); generate_function_helpers(tservice, *f_iter); } } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_cpp_generator::generate_service_interface(t_service* tservice, string style) { string service_if_name = service_name_ + style + "If"; if (style == "CobCl") { // Forward declare the client. string client_name = service_name_ + "CobClient"; if (gen_templates_) { client_name += "T"; service_if_name += "T"; indent(f_header_) << "template " << endl; } indent(f_header_) << "class " << client_name << ";" << endl << endl; } string extends = ""; if (tservice->get_extends() != nullptr) { extends = " : virtual public " + type_name(tservice->get_extends()) + style + "If"; if (style == "CobCl" && gen_templates_) { // TODO(simpkins): If gen_templates_ is enabled, we currently assume all // parent services were also generated with templates enabled. extends += "T"; } } if (style == "CobCl" && gen_templates_) { f_header_ << "template " << endl; } generate_java_doc(f_header_, tservice); f_header_ << "class " << service_if_name << extends << " {" << endl << " public:" << endl; indent_up(); f_header_ << indent() << "virtual ~" << service_if_name << "() {}" << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { if ((*f_iter)->has_doc()) f_header_ << endl; generate_java_doc(f_header_, *f_iter); f_header_ << indent() << "virtual " << function_signature(*f_iter, style) << " = 0;" << endl; } indent_down(); f_header_ << "};" << endl << endl; if (style == "CobCl" && gen_templates_) { // generate a backwards-compatible typedef for clients that do not // know about the new template-style code f_header_ << "typedef " << service_if_name << "< ::apache::thrift::protocol::TProtocol> " << service_name_ << style << "If;" << endl << endl; } } /** * Generates a service interface factory. * * @param tservice The service to generate an interface factory for. */ void t_cpp_generator::generate_service_interface_factory(t_service* tservice, string style) { string service_if_name = service_name_ + style + "If"; // Figure out the name of the upper-most parent class. // Getting everything to work out properly with inheritance is annoying. // Here's what we're doing for now: // // - All handlers implement getHandler(), but subclasses use covariant return // types to return their specific service interface class type. We have to // use raw pointers because of this; shared_ptr<> can't be used for // covariant return types. // // - Since we're not using shared_ptr<>, we also provide a releaseHandler() // function that must be called to release a pointer to a handler obtained // via getHandler(). // // releaseHandler() always accepts a pointer to the upper-most parent class // type. This is necessary since the parent versions of releaseHandler() // may accept any of the parent types, not just the most specific subclass // type. Implementations can use dynamic_cast to cast the pointer to the // subclass type if desired. t_service* base_service = tservice; while (base_service->get_extends() != nullptr) { base_service = base_service->get_extends(); } string base_if_name = type_name(base_service) + style + "If"; // Generate the abstract factory class string factory_name = service_if_name + "Factory"; string extends; if (tservice->get_extends() != nullptr) { extends = " : virtual public " + type_name(tservice->get_extends()) + style + "IfFactory"; } f_header_ << "class " << factory_name << extends << " {" << endl << " public:" << endl; indent_up(); f_header_ << indent() << "typedef " << service_if_name << " Handler;" << endl << endl << indent() << "virtual ~" << factory_name << "() {}" << endl << endl << indent() << "virtual " << service_if_name << "* getHandler(" << "const ::apache::thrift::TConnectionInfo& connInfo)" << (extends.empty() ? "" : " override") << " = 0;" << endl << indent() << "virtual void releaseHandler(" << base_if_name << "* /* handler */)" << (extends.empty() ? "" : " override") << " = 0;" << endl << indent(); indent_down(); f_header_ << "};" << endl << endl; // Generate the singleton factory class string singleton_factory_name = service_if_name + "SingletonFactory"; f_header_ << "class " << singleton_factory_name << " : virtual public " << factory_name << " {" << endl << " public:" << endl; indent_up(); f_header_ << indent() << singleton_factory_name << "(const ::std::shared_ptr<" << service_if_name << ">& iface) : iface_(iface) {}" << endl << indent() << "virtual ~" << singleton_factory_name << "() {}" << endl << endl << indent() << "virtual " << service_if_name << "* getHandler(" << "const ::apache::thrift::TConnectionInfo&) override {" << endl << indent() << " return iface_.get();" << endl << indent() << "}" << endl << indent() << "virtual void releaseHandler(" << base_if_name << "* /* handler */) override {}" << endl; f_header_ << endl << " protected:" << endl << indent() << "::std::shared_ptr<" << service_if_name << "> iface_;" << endl; indent_down(); f_header_ << "};" << endl << endl; } /** * Generates a null implementation of the service. * * @param tservice The service to generate a header definition for */ void t_cpp_generator::generate_service_null(t_service* tservice, string style) { string extends = ""; if (tservice->get_extends() != nullptr) { extends = " , virtual public " + type_name(tservice->get_extends()) + style + "Null"; } f_header_ << "class " << service_name_ << style << "Null : virtual public " << service_name_ << style << "If" << extends << " {" << endl << " public:" << endl; indent_up(); f_header_ << indent() << "virtual ~" << service_name_ << style << "Null() {}" << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_header_ << indent() << function_signature(*f_iter, style, "", false) << " override {" << endl; indent_up(); t_type* returntype = (*f_iter)->get_returntype(); t_field returnfield(returntype, "_return"); if (style == "") { if (returntype->is_void() || is_complex_type(returntype)) { f_header_ << indent() << "return;" << endl; } else { f_header_ << indent() << declare_field(&returnfield, true) << endl << indent() << "return _return;" << endl; } } else if (style == "CobSv") { if (returntype->is_void()) { f_header_ << indent() << "return cob();" << endl; } else { t_field returnfield(returntype, "_return"); f_header_ << indent() << declare_field(&returnfield, true) << endl << indent() << "return cob(_return);" << endl; } } else { throw "UNKNOWN STYLE"; } indent_down(); f_header_ << indent() << "}" << endl; } indent_down(); f_header_ << "};" << endl << endl; } void t_cpp_generator::generate_function_call(ostream& out, t_function* tfunction, string target, string iface, string arg_prefix) { bool first = true; t_type* ret_type = get_true_type(tfunction->get_returntype()); out << indent(); if (!tfunction->is_oneway() && !ret_type->is_void()) { if (is_complex_type(ret_type)) { first = false; out << iface << "->" << tfunction->get_name() << "(" << target; } else { out << target << " = " << iface << "->" << tfunction->get_name() << "("; } } else { out << iface << "->" << tfunction->get_name() << "("; } const std::vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { out << ", "; } out << arg_prefix << (*f_iter)->get_name(); } out << ");" << endl; } void t_cpp_generator::generate_service_async_skeleton(t_service* tservice) { string svcname = tservice->get_name(); // Service implementation file includes string f_skeleton_name = get_out_dir() + svcname + "_async_server.skeleton.cpp"; string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp")); ofstream_with_content_based_conditional_update f_skeleton; f_skeleton.open(f_skeleton_name.c_str()); f_skeleton << "// This autogenerated skeleton file illustrates one way to adapt a synchronous" << endl << "// interface into an asynchronous interface. You should copy it to another" << endl << "// filename to avoid overwriting it and rewrite as asynchronous any functions" << endl << "// that would otherwise introduce unwanted latency." << endl << endl << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl << endl << "using namespace ::apache::thrift;" << endl << "using namespace ::apache::thrift::protocol;" << endl << "using namespace ::apache::thrift::transport;" << endl << "using namespace ::apache::thrift::async;" << endl << endl; // the following code would not compile: // using namespace ; // using namespace ::; if ((!ns.empty()) && (ns.compare(" ::") != 0)) { f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl; } f_skeleton << "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl << " public:" << endl; indent_up(); f_skeleton << indent() << svcname << "Handler() {" << endl << indent() << " // Your initialization goes here" << endl << indent() << "}" << endl << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_java_doc(f_skeleton, *f_iter); f_skeleton << indent() << function_signature(*f_iter, "") << " {" << endl << indent() << " // Your implementation goes here" << endl << indent() << " printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl << indent() << "}" << endl << endl; } indent_down(); f_skeleton << "};" << endl << endl; f_skeleton << "class " << svcname << "AsyncHandler : " << "public " << svcname << "CobSvIf {" << endl << " public:" << endl; indent_up(); f_skeleton << indent() << svcname << "AsyncHandler() {" << endl << indent() << " syncHandler_ = std::unique_ptr<" << svcname << "Handler>(new " << svcname << "Handler);" << endl << indent() << " // Your initialization goes here" << endl << indent() << "}" << endl; f_skeleton << indent() << "virtual ~" << service_name_ << "AsyncHandler();" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_skeleton << endl << indent() << function_signature(*f_iter, "CobSv", "", true) << " {" << endl; indent_up(); t_type* returntype = (*f_iter)->get_returntype(); t_field returnfield(returntype, "_return"); string target = returntype->is_void() ? "" : "_return"; if (!returntype->is_void()) { f_skeleton << indent() << declare_field(&returnfield, true) << endl; } generate_function_call(f_skeleton, *f_iter, target, "syncHandler_", ""); f_skeleton << indent() << "return cob(" << target << ");" << endl; scope_down(f_skeleton); } f_skeleton << endl << " protected:" << endl << indent() << "std::unique_ptr<" << svcname << "Handler> syncHandler_;" << endl; indent_down(); f_skeleton << "};" << endl << endl; f_skeleton << indent() << "int main(int argc, char **argv) {" << endl; indent_up(); f_skeleton << indent() << "int port = 9090;" << endl << indent() << "::std::shared_ptr<" << svcname << "AsyncHandler> handler(new " << svcname << "AsyncHandler());" << endl << indent() << "::std::shared_ptr<" << svcname << "AsyncProcessor> processor(new " << svcname << "AsyncProcessor(handler));" << endl << indent() << "::std::shared_ptr protocolFactory(new TBinaryProtocolFactory());" << endl << indent() << "::std::shared_ptr protocolProcessor(new TAsyncProtocolProcessor(processor, protocolFactory));" << endl << endl << indent() << "TEvhttpServer server(protocolProcessor, port);" << endl << indent() << "server.serve();" << endl << indent() << "return 0;" << endl; indent_down(); f_skeleton << "}" << endl << endl; } /** * Generates a multiface, which is a single server that just takes a set * of objects implementing the interface and calls them all, returning the * value of the last one to be called. * * @param tservice The service to generate a multiserver for. */ void t_cpp_generator::generate_service_multiface(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_multiface = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_multiface = ", public " + extends + "Multiface"; } string list_type = string("std::vector >"; // Generate the header portion f_header_ << "class " << service_name_ << "Multiface : " << "virtual public " << service_name_ << "If" << extends_multiface << " {" << endl << " public:" << endl; indent_up(); f_header_ << indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl; if (!extends.empty()) { f_header_ << indent() << " std::vector >::iterator iter;" << endl << indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl << indent() << " " << extends << "Multiface::add(*iter);" << endl << indent() << " }" << endl; } f_header_ << indent() << "}" << endl << indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl; indent_down(); // Protected data members f_header_ << " protected:" << endl; indent_up(); f_header_ << indent() << list_type << " ifaces_;" << endl << indent() << service_name_ << "Multiface() {}" << endl << indent() << "void add(::std::shared_ptr<" << service_name_ << "If> iface) {" << endl; if (!extends.empty()) { f_header_ << indent() << " " << extends << "Multiface::add(iface);" << endl; } f_header_ << indent() << " ifaces_.push_back(iface);" << endl << indent() << "}" << endl; indent_down(); f_header_ << indent() << " public:" << endl; indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_java_doc(f_header_, *f_iter); t_struct* arglist = (*f_iter)->get_arglist(); const vector& args = arglist->get_members(); vector::const_iterator a_iter; string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "("; bool first = true; if (is_complex_type((*f_iter)->get_returntype())) { call += "_return"; first = false; } for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { if (first) { first = false; } else { call += ", "; } call += (*a_iter)->get_name(); } call += ")"; f_header_ << indent() << function_signature(*f_iter, "") << " override {" << endl; indent_up(); f_header_ << indent() << "size_t sz = ifaces_.size();" << endl << indent() << "size_t i = 0;" << endl << indent() << "for (; i < (sz - 1); ++i) {" << endl; indent_up(); f_header_ << indent() << call << ";" << endl; indent_down(); f_header_ << indent() << "}" << endl; if (!(*f_iter)->get_returntype()->is_void()) { if (is_complex_type((*f_iter)->get_returntype())) { f_header_ << indent() << call << ";" << endl << indent() << "return;" << endl; } else { f_header_ << indent() << "return " << call << ";" << endl; } } else { f_header_ << indent() << call << ";" << endl; } indent_down(); f_header_ << indent() << "}" << endl << endl; } indent_down(); f_header_ << indent() << "};" << endl << endl; } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_cpp_generator::generate_service_client(t_service* tservice, string style) { string ifstyle; if (style == "Cob") { ifstyle = "CobCl"; } std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_); string template_header, template_suffix, short_suffix, protocol_type, _this; string const prot_factory_type = "::apache::thrift::protocol::TProtocolFactory"; if (gen_templates_) { template_header = "template \n"; short_suffix = "T"; template_suffix = "T"; protocol_type = "Protocol_"; _this = "this->"; } else { protocol_type = "::apache::thrift::protocol::TProtocol"; } string prot_ptr = "std::shared_ptr< " + protocol_type + ">"; string client_suffix = "Client" + template_suffix; string if_suffix = "If"; if (style == "Cob") { if_suffix += template_suffix; } string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { // TODO(simpkins): If gen_templates_ is enabled, we currently assume all // parent services were also generated with templates enabled. extends = type_name(tservice->get_extends()); extends_client = ", public " + extends + style + client_suffix; } // Generate the header portion if (style == "Concurrent") { f_header_ << "// The \'concurrent\' client is a thread safe client that correctly handles\n" "// out of order responses. It is slower than the regular client, so should\n" "// only be used when you need to share a connection among multiple threads\n"; } f_header_ << template_header << "class " << service_name_ << style << "Client" << short_suffix << " : " << "virtual public " << service_name_ << ifstyle << if_suffix << extends_client << " {" << endl << " public:" << endl; indent_up(); if (style != "Cob") { f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr << " prot"; if (style == "Concurrent") { f_header_ << ", std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync"; } f_header_ << ") "; if (extends.empty()) { if (style == "Concurrent") { f_header_ << ": sync_(sync)" << endl; } f_header_ << "{" << endl; f_header_ << indent() << " setProtocol" << short_suffix << "(prot);" << endl << indent() << "}" << endl; } else { f_header_ << ":" << endl; f_header_ << indent() << " " << extends << style << client_suffix << "(prot, prot"; if (style == "Concurrent") { f_header_ << ", sync"; } f_header_ << ") {}" << endl; } f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr << " iprot, " << prot_ptr << " oprot"; if (style == "Concurrent") { f_header_ << ", std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync"; } f_header_ << ") "; if (extends.empty()) { if (style == "Concurrent") { f_header_ << ": sync_(sync)" << endl; } f_header_ << "{" << endl; f_header_ << indent() << " setProtocol" << short_suffix << "(iprot,oprot);" << endl << indent() << "}" << endl; } else { f_header_ << ":" << indent() << " " << extends << style << client_suffix << "(iprot, oprot"; if (style == "Concurrent") { f_header_ << ", sync"; } f_header_ << ") {}" << endl; } // create the setProtocol methods if (extends.empty()) { f_header_ << " private:" << endl; // 1: one parameter f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " prot) {" << endl; f_header_ << indent() << "setProtocol" << short_suffix << "(prot,prot);" << endl; f_header_ << indent() << "}" << endl; // 2: two parameter f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " iprot, " << prot_ptr << " oprot) {" << endl; f_header_ << indent() << " piprot_=iprot;" << endl << indent() << " poprot_=oprot;" << endl << indent() << " iprot_ = iprot.get();" << endl << indent() << " oprot_ = oprot.get();" << endl; f_header_ << indent() << "}" << endl; f_header_ << " public:" << endl; } // Generate getters for the protocols. // Note that these are not currently templated for simplicity. // TODO(simpkins): should they be templated? f_header_ << indent() << "std::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() {" << endl << indent() << " return " << _this << "piprot_;" << endl << indent() << "}" << endl; f_header_ << indent() << "std::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() {" << endl << indent() << " return " << _this << "poprot_;" << endl << indent() << "}" << endl; } else /* if (style == "Cob") */ { f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << "std::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel, " << "::apache::thrift::protocol::TProtocolFactory* protocolFactory) :" << endl; if (extends.empty()) { f_header_ << indent() << " channel_(channel)," << endl << indent() << " itrans_(new ::apache::thrift::transport::TMemoryBuffer())," << endl << indent() << " otrans_(new ::apache::thrift::transport::TMemoryBuffer())," << endl; if (gen_templates_) { // TProtocolFactory classes return generic TProtocol pointers. // We have to dynamic cast to the Protocol_ type we are expecting. f_header_ << indent() << " piprot_(::std::dynamic_pointer_cast(" << "protocolFactory->getProtocol(itrans_)))," << endl << indent() << " poprot_(::std::dynamic_pointer_cast(" << "protocolFactory->getProtocol(otrans_))) {" << endl; // Throw a TException if either dynamic cast failed. f_header_ << indent() << " if (!piprot_ || !poprot_) {" << endl << indent() << " throw ::apache::thrift::TException(\"" << "TProtocolFactory returned unexpected protocol type in " << service_name_ << style << "Client" << short_suffix << " constructor\");" << endl << indent() << " }" << endl; } else { f_header_ << indent() << " piprot_(protocolFactory->getProtocol(itrans_))," << endl << indent() << " poprot_(protocolFactory->getProtocol(otrans_)) {" << endl; } f_header_ << indent() << " iprot_ = piprot_.get();" << endl << indent() << " oprot_ = poprot_.get();" << endl << indent() << "}" << endl; } else { f_header_ << indent() << " " << extends << style << client_suffix << "(channel, protocolFactory) {}" << endl; } } if (style == "Cob") { generate_java_doc(f_header_, tservice); f_header_ << indent() << "::std::shared_ptr< ::apache::thrift::async::TAsyncChannel> getChannel() {" << endl << indent() << " return " << _this << "channel_;" << endl << indent() << "}" << endl; if (!gen_no_client_completion_) { f_header_ << indent() << "virtual void completed__(bool /* success */) {}" << endl; } } vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_java_doc(f_header_, *f_iter); indent(f_header_) << function_signature(*f_iter, ifstyle) << " override;" << endl; // TODO(dreiss): Use private inheritance to avoid generating thise in cob-style. if (style == "Concurrent" && !(*f_iter)->is_oneway()) { // concurrent clients need to move the seqid from the send function to the // recv function. Oneway methods don't have a recv function, so we don't need to // move the seqid for them. Attempting to do so would result in a seqid leak. t_function send_function(g_type_i32, /*returning seqid*/ string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); indent(f_header_) << function_signature(&send_function, "") << ";" << endl; } else { t_function send_function(g_type_void, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); indent(f_header_) << function_signature(&send_function, "") << ";" << endl; } if (!(*f_iter)->is_oneway()) { if (style == "Concurrent") { t_field seqIdArg(g_type_i32, "seqid"); t_struct seqIdArgStruct(program_); seqIdArgStruct.append(&seqIdArg); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &seqIdArgStruct); indent(f_header_) << function_signature(&recv_function, "") << ";" << endl; } else { t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); indent(f_header_) << function_signature(&recv_function, "") << ";" << endl; } } } indent_down(); if (extends.empty()) { f_header_ << " protected:" << endl; indent_up(); if (style == "Cob") { f_header_ << indent() << "::std::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel_;" << endl << indent() << "::std::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> itrans_;" << endl << indent() << "::std::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> otrans_;" << endl; } f_header_ << indent() << prot_ptr << " piprot_;" << endl << indent() << prot_ptr << " poprot_;" << endl << indent() << protocol_type << "* iprot_;" << endl << indent() << protocol_type << "* oprot_;" << endl; if (style == "Concurrent") { f_header_ << indent() << "std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync_;"< " << service_name_ << style << "Client;" << endl << endl; } string scope = service_name_ + style + client_suffix + "::"; // Generate client method implementations for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string seqIdCapture; string seqIdUse; string seqIdCommaUse; if (style == "Concurrent" && !(*f_iter)->is_oneway()) { seqIdCapture = "int32_t seqid = "; seqIdUse = "seqid"; seqIdCommaUse = ", seqid"; } string funname = (*f_iter)->get_name(); // Open function if (gen_templates_) { indent(out) << template_header; } indent(out) << function_signature(*f_iter, ifstyle, scope) << endl; scope_up(out); indent(out) << seqIdCapture << "send_" << funname << "("; // Get the struct of function call params t_struct* arg_struct = (*f_iter)->get_arglist(); // Declare the function arguments const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; bool first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { out << ", "; } out << (*fld_iter)->get_name(); } out << ");" << endl; if (style != "Cob") { if (!(*f_iter)->is_oneway()) { out << indent(); if (!(*f_iter)->get_returntype()->is_void()) { if (is_complex_type((*f_iter)->get_returntype())) { out << "recv_" << funname << "(_return" << seqIdCommaUse << ");" << endl; } else { out << "return recv_" << funname << "(" << seqIdUse << ");" << endl; } } else { out << "recv_" << funname << "(" << seqIdUse << ");" << endl; } } } else { if (!(*f_iter)->is_oneway()) { out << indent() << _this << "channel_->sendAndRecvMessage(" << "::std::bind(cob, this), " << _this << "otrans_.get(), " << _this << "itrans_.get());" << endl; } else { out << indent() << _this << "channel_->sendMessage(" << "::std::bind(cob, this), " << _this << "otrans_.get());" << endl; } } scope_down(out); out << endl; // if (style != "Cob") // TODO(dreiss): Libify the client and don't generate this for cob-style if (true) { t_type* send_func_return_type = g_type_void; if (style == "Concurrent" && !(*f_iter)->is_oneway()) { send_func_return_type = g_type_i32; } // Function for sending t_function send_function(send_func_return_type, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); // Open the send function if (gen_templates_) { indent(out) << template_header; } indent(out) << function_signature(&send_function, "", scope) << endl; scope_up(out); // Function arguments and results string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs"; string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult"; string cseqidVal = "0"; if (style == "Concurrent") { if (!(*f_iter)->is_oneway()) { cseqidVal = "this->sync_->generateSeqId()"; } } // Serialize the request out << indent() << "int32_t cseqid = " << cseqidVal << ";" << endl; if(style == "Concurrent") { out << indent() << "::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get());" << endl; } if (style == "Cob") { out << indent() << _this << "otrans_->resetBuffer();" << endl; } out << indent() << _this << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", ::apache::thrift::protocol::" << ((*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL") << ", cseqid);" << endl << endl << indent() << argsname << " args;" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { out << indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl; } out << indent() << "args.write(" << _this << "oprot_);" << endl << endl << indent() << _this << "oprot_->writeMessageEnd();" << endl << indent() << _this << "oprot_->getTransport()->writeEnd();" << endl << indent() << _this << "oprot_->getTransport()->flush();" << endl; if (style == "Concurrent") { out << endl << indent() << "sentry.commit();" << endl; if (!(*f_iter)->is_oneway()) { out << indent() << "return cseqid;" << endl; } } scope_down(out); out << endl; // Generate recv function only if not an oneway function if (!(*f_iter)->is_oneway()) { t_struct noargs(program_); t_field seqIdArg(g_type_i32, "seqid"); t_struct seqIdArgStruct(program_); seqIdArgStruct.append(&seqIdArg); t_struct* recv_function_args = &noargs; if (style == "Concurrent") { recv_function_args = &seqIdArgStruct; } t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), recv_function_args); // Open the recv function if (gen_templates_) { indent(out) << template_header; } indent(out) << function_signature(&recv_function, "", scope) << endl; scope_up(out); out << endl << indent() << "int32_t rseqid = 0;" << endl << indent() << "std::string fname;" << endl << indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl; if(style == "Concurrent") { out << endl << indent() << "// the read mutex gets dropped and reacquired as part of waitForWork()" << endl << indent() << "// The destructor of this sentry wakes up other clients" << endl << indent() << "::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid);" << endl; } if (style == "Cob" && !gen_no_client_completion_) { out << indent() << "bool completed = false;" << endl << endl << indent() << "try {"; indent_up(); } out << endl; if (style == "Concurrent") { out << indent() << "while(true) {" << endl << indent() << " if(!this->sync_->getPending(fname, mtype, rseqid)) {" << endl; indent_up(); indent_up(); } out << indent() << _this << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl; if (style == "Concurrent") { scope_down(out); out << indent() << "if(seqid == rseqid) {" << endl; indent_up(); } out << indent() << "if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {" << endl << indent() << " ::apache::thrift::TApplicationException x;" << endl << indent() << " x.read(" << _this << "iprot_);" << endl << indent() << " " << _this << "iprot_->readMessageEnd();" << endl << indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; if (style == "Cob" && !gen_no_client_completion_) { out << indent() << " completed = true;" << endl << indent() << " completed__(true);" << endl; } if (style == "Concurrent") { out << indent() << " sentry.commit();" << endl; } out << indent() << " throw x;" << endl << indent() << "}" << endl << indent() << "if (mtype != ::apache::thrift::protocol::T_REPLY) {" << endl << indent() << " " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl << indent() << " " << _this << "iprot_->readMessageEnd();" << endl << indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; if (style == "Cob" && !gen_no_client_completion_) { out << indent() << " completed = true;" << endl << indent() << " completed__(false);" << endl; } out << indent() << "}" << endl << indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl << indent() << " " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl << indent() << " " << _this << "iprot_->readMessageEnd();" << endl << indent() << " " << _this << "iprot_->getTransport()->readEnd();" << endl; if (style == "Cob" && !gen_no_client_completion_) { out << indent() << " completed = true;" << endl << indent() << " completed__(false);" << endl; } if (style == "Concurrent") { out << endl << indent() << " // in a bad state, don't commit" << endl << indent() << " using ::apache::thrift::protocol::TProtocolException;" << endl << indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl; } out << indent() << "}" << endl; if (!(*f_iter)->get_returntype()->is_void() && !is_complex_type((*f_iter)->get_returntype())) { t_field returnfield((*f_iter)->get_returntype(), "_return"); out << indent() << declare_field(&returnfield) << endl; } out << indent() << resultname << " result;" << endl; if (!(*f_iter)->get_returntype()->is_void()) { out << indent() << "result.success = &_return;" << endl; } out << indent() << "result.read(" << _this << "iprot_);" << endl << indent() << _this << "iprot_->readMessageEnd();" << endl << indent() << _this << "iprot_->getTransport()->readEnd();" << endl << endl; // Careful, only look for _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { if (is_complex_type((*f_iter)->get_returntype())) { out << indent() << "if (result.__isset.success) {" << endl; out << indent() << " // _return pointer has now been filled" << endl; if (style == "Cob" && !gen_no_client_completion_) { out << indent() << " completed = true;" << endl << indent() << " completed__(true);" << endl; } if (style == "Concurrent") { out << indent() << " sentry.commit();" << endl; } out << indent() << " return;" << endl << indent() << "}" << endl; } else { out << indent() << "if (result.__isset.success) {" << endl; if (style == "Cob" && !gen_no_client_completion_) { out << indent() << " completed = true;" << endl << indent() << " completed__(true);" << endl; } if (style == "Concurrent") { out << indent() << " sentry.commit();" << endl; } out << indent() << " return _return;" << endl << indent() << "}" << endl; } } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl; if (style == "Cob" && !gen_no_client_completion_) { out << indent() << " completed = true;" << endl << indent() << " completed__(true);" << endl; } if (style == "Concurrent") { out << indent() << " sentry.commit();" << endl; } out << indent() << " throw result." << (*x_iter)->get_name() << ";" << endl << indent() << "}" << endl; } // We only get here if we are a void function if ((*f_iter)->get_returntype()->is_void()) { if (style == "Cob" && !gen_no_client_completion_) { out << indent() << "completed = true;" << endl << indent() << "completed__(true);" << endl; } if (style == "Concurrent") { out << indent() << "sentry.commit();" << endl; } indent(out) << "return;" << endl; } else { if (style == "Cob" && !gen_no_client_completion_) { out << indent() << "completed = true;" << endl << indent() << "completed__(true);" << endl; } if (style == "Concurrent") { out << indent() << "// in a bad state, don't commit" << endl; } out << indent() << "throw " "::apache::thrift::TApplicationException(::apache::thrift::" "TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; } if (style == "Concurrent") { indent_down(); indent_down(); out << indent() << " }" << endl << indent() << " // seqid != rseqid" << endl << indent() << " this->sync_->updatePending(fname, mtype, rseqid);" << endl << endl << indent() << " // this will temporarily unlock the readMutex, and let other clients get work done" << endl << indent() << " this->sync_->waitForWork(seqid);" << endl << indent() << "} // end while(true)" << endl; } if (style == "Cob" && !gen_no_client_completion_) { indent_down(); out << indent() << "} catch (...) {" << endl << indent() << " if (!completed) {" << endl << indent() << " completed__(false);" << endl << indent() << " }" << endl << indent() << " throw;" << endl << indent() << "}" << endl; } // Close function scope_down(out); out << endl; } } } } class ProcessorGenerator { public: ProcessorGenerator(t_cpp_generator* generator, t_service* service, const string& style); void run() { generate_class_definition(); // Generate the dispatchCall() function generate_dispatch_call(false); if (generator_->gen_templates_) { generate_dispatch_call(true); } // Generate all of the process subfunctions generate_process_functions(); generate_factory(); } void generate_class_definition(); void generate_dispatch_call(bool template_protocol); void generate_process_functions(); void generate_factory(); protected: std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false) { return generator_->type_name(ttype, in_typedef, arg); } std::string indent() { return generator_->indent(); } std::ostream& indent(std::ostream& os) { return generator_->indent(os); } void indent_up() { generator_->indent_up(); } void indent_down() { generator_->indent_down(); } t_cpp_generator* generator_; t_service* service_; std::ostream& f_header_; std::ostream& f_out_; string service_name_; string style_; string pstyle_; string class_name_; string if_name_; string factory_class_name_; string finish_cob_; string finish_cob_decl_; string ret_type_; string call_context_; string cob_arg_; string call_context_arg_; string call_context_decl_; string template_header_; string template_suffix_; string typename_str_; string class_suffix_; string extends_; }; ProcessorGenerator::ProcessorGenerator(t_cpp_generator* generator, t_service* service, const string& style) : generator_(generator), service_(service), f_header_(generator->f_header_), f_out_(generator->gen_templates_ ? generator->f_service_tcc_ : generator->f_service_), service_name_(generator->service_name_), style_(style) { if (style_ == "Cob") { pstyle_ = "Async"; class_name_ = service_name_ + pstyle_ + "Processor"; if_name_ = service_name_ + "CobSvIf"; finish_cob_ = "::std::function cob, "; finish_cob_decl_ = "::std::function, "; cob_arg_ = "cob, "; ret_type_ = "void "; } else { class_name_ = service_name_ + "Processor"; if_name_ = service_name_ + "If"; ret_type_ = "bool "; // TODO(edhall) callContext should eventually be added to TAsyncProcessor call_context_ = ", void* callContext"; call_context_arg_ = ", callContext"; call_context_decl_ = ", void*"; } factory_class_name_ = class_name_ + "Factory"; if (generator->gen_templates_) { template_header_ = "template \n"; template_suffix_ = ""; typename_str_ = "typename "; class_name_ += "T"; factory_class_name_ += "T"; } if (service_->get_extends() != nullptr) { extends_ = type_name(service_->get_extends()) + pstyle_ + "Processor"; if (generator_->gen_templates_) { // TODO(simpkins): If gen_templates_ is enabled, we currently assume all // parent services were also generated with templates enabled. extends_ += "T"; } } } void ProcessorGenerator::generate_class_definition() { // Generate the dispatch methods vector functions = service_->get_functions(); vector::iterator f_iter; string parent_class; if (service_->get_extends() != nullptr) { parent_class = extends_; } else { if (style_ == "Cob") { parent_class = "::apache::thrift::async::TAsyncDispatchProcessor"; } else { parent_class = "::apache::thrift::TDispatchProcessor"; } if (generator_->gen_templates_) { parent_class += "T"; } } // Generate the header portion f_header_ << template_header_ << "class " << class_name_ << " : public " << parent_class << " {" << endl; // Protected data members f_header_ << " protected:" << endl; indent_up(); f_header_ << indent() << "::std::shared_ptr<" << if_name_ << "> iface_;" << endl; f_header_ << indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_ << "::apache::thrift::protocol::TProtocol* iprot, " << "::apache::thrift::protocol::TProtocol* oprot, " << "const std::string& fname, int32_t seqid" << call_context_ << ") override;" << endl; if (generator_->gen_templates_) { f_header_ << indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" << finish_cob_ << "Protocol_* iprot, Protocol_* oprot, " << "const std::string& fname, int32_t seqid" << call_context_ << ");" << endl; } indent_down(); // Process function declarations f_header_ << " private:" << endl; indent_up(); // Declare processMap_ f_header_ << indent() << "typedef void (" << class_name_ << "::*" << "ProcessFunction)(" << finish_cob_decl_ << "int32_t, " << "::apache::thrift::protocol::TProtocol*, " << "::apache::thrift::protocol::TProtocol*" << call_context_decl_ << ");" << endl; if (generator_->gen_templates_) { f_header_ << indent() << "typedef void (" << class_name_ << "::*" << "SpecializedProcessFunction)(" << finish_cob_decl_ << "int32_t, " << "Protocol_*, Protocol_*" << call_context_decl_ << ");" << endl << indent() << "struct ProcessFunctions {" << endl << indent() << " ProcessFunction generic;" << endl << indent() << " SpecializedProcessFunction specialized;" << endl << indent() << " ProcessFunctions(ProcessFunction g, " << "SpecializedProcessFunction s) :" << endl << indent() << " generic(g)," << endl << indent() << " specialized(s) {}" << endl << indent() << " ProcessFunctions() : generic(nullptr), specialized(nullptr) " << "{}" << endl << indent() << "};" << endl << indent() << "typedef std::map " << "ProcessMap;" << endl; } else { f_header_ << indent() << "typedef std::map " << "ProcessMap;" << endl; } f_header_ << indent() << "ProcessMap processMap_;" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ << "int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, " "::apache::thrift::protocol::TProtocol* oprot" << call_context_ << ");" << endl; if (generator_->gen_templates_) { indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ << "int32_t seqid, Protocol_* iprot, Protocol_* oprot" << call_context_ << ");" << endl; } if (style_ == "Cob") { // XXX Factor this out, even if it is a pain. string ret_arg = ((*f_iter)->get_returntype()->is_void() ? "" : ", const " + type_name((*f_iter)->get_returntype()) + "& _return"); f_header_ << indent() << "void return_" << (*f_iter)->get_name() << "(::std::function cob, int32_t seqid, " << "::apache::thrift::protocol::TProtocol* oprot, " << "void* ctx" << ret_arg << ");" << endl; if (generator_->gen_templates_) { f_header_ << indent() << "void return_" << (*f_iter)->get_name() << "(::std::function cob, int32_t seqid, " << "Protocol_* oprot, void* ctx" << ret_arg << ");" << endl; } // XXX Don't declare throw if it doesn't exist f_header_ << indent() << "void throw_" << (*f_iter)->get_name() << "(::std::function cob, int32_t seqid, " << "::apache::thrift::protocol::TProtocol* oprot, void* ctx, " << "::apache::thrift::TDelayedException* _throw);" << endl; if (generator_->gen_templates_) { f_header_ << indent() << "void throw_" << (*f_iter)->get_name() << "(::std::function cob, int32_t seqid, " << "Protocol_* oprot, void* ctx, " << "::apache::thrift::TDelayedException* _throw);" << endl; } } } f_header_ << " public:" << endl << indent() << class_name_ << "(::std::shared_ptr<" << if_name_ << "> iface) :" << endl; if (!extends_.empty()) { f_header_ << indent() << " " << extends_ << "(iface)," << endl; } f_header_ << indent() << " iface_(iface) {" << endl; indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_header_ << indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = "; if (generator_->gen_templates_) { f_header_ << "ProcessFunctions(" << endl; if (generator_->gen_templates_only_) { indent(f_header_) << " nullptr," << endl; } else { indent(f_header_) << " &" << class_name_ << "::process_" << (*f_iter)->get_name() << "," << endl; } indent(f_header_) << " &" << class_name_ << "::process_" << (*f_iter)->get_name() << ")"; } else { f_header_ << "&" << class_name_ << "::process_" << (*f_iter)->get_name(); } f_header_ << ";" << endl; } indent_down(); f_header_ << indent() << "}" << endl << endl << indent() << "virtual ~" << class_name_ << "() {}" << endl; indent_down(); f_header_ << "};" << endl << endl; if (generator_->gen_templates_) { // Generate a backwards compatible typedef, for callers who don't know // about the new template-style code. // // We can't use TProtocol as the template parameter, since ProcessorT // provides overloaded versions of most methods, one of which accepts // TProtocol pointers, and one which accepts Protocol_ pointers. This // results in a compile error if instantiated with Protocol_ == TProtocol. // Therefore, we define TDummyProtocol solely so we can use it as the // template parameter here. f_header_ << "typedef " << class_name_ << "< ::apache::thrift::protocol::TDummyProtocol > " << service_name_ << pstyle_ << "Processor;" << endl << endl; } } void ProcessorGenerator::generate_dispatch_call(bool template_protocol) { string protocol = "::apache::thrift::protocol::TProtocol"; string function_suffix; if (template_protocol) { protocol = "Protocol_"; // We call the generic version dispatchCall(), and the specialized // version dispatchCallTemplated(). We can't call them both // dispatchCall(), since this will cause the compiler to issue a warning if // a service that doesn't use templates inherits from a service that does // use templates: the compiler complains that the subclass only implements // the generic version of dispatchCall(), and hides the templated version. // Using different names for the two functions prevents this. function_suffix = "Templated"; } f_out_ << template_header_ << ret_type_ << class_name_ << template_suffix_ << "::dispatchCall" << function_suffix << "(" << finish_cob_ << protocol << "* iprot, " << protocol << "* oprot, " << "const std::string& fname, int32_t seqid" << call_context_ << ") {" << endl; indent_up(); // HOT: member function pointer map f_out_ << indent() << typename_str_ << "ProcessMap::iterator pfn;" << endl << indent() << "pfn = processMap_.find(fname);" << endl << indent() << "if (pfn == processMap_.end()) {" << endl; if (extends_.empty()) { f_out_ << indent() << " iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl << indent() << " iprot->readMessageEnd();" << endl << indent() << " iprot->getTransport()->readEnd();" << endl << indent() << " ::apache::thrift::TApplicationException " "x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: " "'\"+fname+\"'\");" << endl << indent() << " oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent() << " x.write(oprot);" << endl << indent() << " oprot->writeMessageEnd();" << endl << indent() << " oprot->getTransport()->writeEnd();" << endl << indent() << " oprot->getTransport()->flush();" << endl << indent() << (style_ == "Cob" ? " return cob(true);" : " return true;") << endl; } else { f_out_ << indent() << " return " << extends_ << "::dispatchCall(" << (style_ == "Cob" ? "cob, " : "") << "iprot, oprot, fname, seqid" << call_context_arg_ << ");" << endl; } f_out_ << indent() << "}" << endl; if (template_protocol) { f_out_ << indent() << "(this->*(pfn->second.specialized))"; } else { if (generator_->gen_templates_only_) { // TODO: This is a null pointer, so nothing good will come from calling // it. Throw an exception instead. f_out_ << indent() << "(this->*(pfn->second.generic))"; } else if (generator_->gen_templates_) { f_out_ << indent() << "(this->*(pfn->second.generic))"; } else { f_out_ << indent() << "(this->*(pfn->second))"; } } f_out_ << "(" << cob_arg_ << "seqid, iprot, oprot" << call_context_arg_ << ");" << endl; // TODO(dreiss): return pfn ret? if (style_ == "Cob") { f_out_ << indent() << "return;" << endl; } else { f_out_ << indent() << "return true;" << endl; } indent_down(); f_out_ << "}" << endl << endl; } void ProcessorGenerator::generate_process_functions() { vector functions = service_->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { if (generator_->gen_templates_) { generator_->generate_process_function(service_, *f_iter, style_, false); generator_->generate_process_function(service_, *f_iter, style_, true); } else { generator_->generate_process_function(service_, *f_iter, style_, false); } } } void ProcessorGenerator::generate_factory() { string if_factory_name = if_name_ + "Factory"; // Generate the factory class definition f_header_ << template_header_ << "class " << factory_class_name_ << " : public ::apache::thrift::" << (style_ == "Cob" ? "async::TAsyncProcessorFactory" : "TProcessorFactory") << " {" << endl << " public:" << endl; indent_up(); f_header_ << indent() << factory_class_name_ << "(const ::std::shared_ptr< " << if_factory_name << " >& handlerFactory) noexcept :" << endl << indent() << " handlerFactory_(handlerFactory) {}" << endl << endl << indent() << "::std::shared_ptr< ::apache::thrift::" << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " << "getProcessor(const ::apache::thrift::TConnectionInfo& connInfo) override;" << endl; f_header_ << endl << " protected:" << endl << indent() << "::std::shared_ptr< " << if_factory_name << " > handlerFactory_;" << endl; indent_down(); f_header_ << "};" << endl << endl; // If we are generating templates, output a typedef for the plain // factory name. if (generator_->gen_templates_) { f_header_ << "typedef " << factory_class_name_ << "< ::apache::thrift::protocol::TDummyProtocol > " << service_name_ << pstyle_ << "ProcessorFactory;" << endl << endl; } // Generate the getProcessor() method f_out_ << template_header_ << indent() << "::std::shared_ptr< ::apache::thrift::" << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " << factory_class_name_ << template_suffix_ << "::getProcessor(" << "const ::apache::thrift::TConnectionInfo& connInfo) {" << endl; indent_up(); f_out_ << indent() << "::apache::thrift::ReleaseHandler< " << if_factory_name << " > cleanup(handlerFactory_);" << endl << indent() << "::std::shared_ptr< " << if_name_ << " > handler(" << "handlerFactory_->getHandler(connInfo), cleanup);" << endl << indent() << "::std::shared_ptr< ::apache::thrift::" << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > " << "processor(new " << class_name_ << template_suffix_ << "(handler));" << endl << indent() << "return processor;" << endl; indent_down(); f_out_ << indent() << "}" << endl << endl; } /** * Generates a service processor definition. * * @param tservice The service to generate a processor for. */ void t_cpp_generator::generate_service_processor(t_service* tservice, string style) { ProcessorGenerator generator(this, tservice, style); generator.run(); } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function* tfunction) { if (tfunction->is_oneway()) { return; } std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_); t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_struct_declaration(f_header_, &result, false); generate_struct_definition(out, f_service_, &result, false); generate_struct_reader(out, &result); generate_struct_result_writer(out, &result); result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult"); generate_struct_declaration(f_header_, &result, false, true, true, gen_cob_style_); generate_struct_definition(out, f_service_, &result, false); generate_struct_reader(out, &result, true); if (gen_cob_style_) { generate_struct_writer(out, &result, true); } } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_cpp_generator::generate_process_function(t_service* tservice, t_function* tfunction, string style, bool specialized) { t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; string service_func_name = "\"" + tservice->get_name() + "." + tfunction->get_name() + "\""; std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_); string prot_type = (specialized ? "Protocol_" : "::apache::thrift::protocol::TProtocol"); string class_suffix; if (gen_templates_) { class_suffix = "T"; } // I tried to do this as one function. I really did. But it was too hard. if (style != "Cob") { // Open function if (gen_templates_) { out << indent() << "template " << endl; } const bool unnamed_oprot_seqid = tfunction->is_oneway() && !(gen_templates_ && !specialized); out << "void " << tservice->get_name() << "Processor" << class_suffix << "::" << "process_" << tfunction->get_name() << "(" << "int32_t" << (unnamed_oprot_seqid ? ", " : " seqid, ") << prot_type << "* iprot, " << prot_type << "*" << (unnamed_oprot_seqid ? ", " : " oprot, ") << "void* callContext)" << endl; scope_up(out); string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args"; string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result"; if (tfunction->is_oneway() && !unnamed_oprot_seqid) { out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl; } out << indent() << "void* ctx = nullptr;" << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " ctx = this->eventHandler_->getContext(" << service_func_name << ", callContext);" << endl << indent() << "}" << endl << indent() << "::apache::thrift::TProcessorContextFreer freer(" << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl << endl << indent() << argsname << " args;" << endl << indent() << "args.read(iprot);" << endl << indent() << "iprot->readMessageEnd();" << endl << indent() << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl << indent() << "}" << endl << endl; // Declare result if (!tfunction->is_oneway()) { out << indent() << resultname << " result;" << endl; } // Try block for functions with exceptions out << indent() << "try {" << endl; indent_up(); // Generate the function call bool first = true; out << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { if (is_complex_type(tfunction->get_returntype())) { first = false; out << "iface_->" << tfunction->get_name() << "(result.success"; } else { out << "result.success = iface_->" << tfunction->get_name() << "("; } } else { out << "iface_->" << tfunction->get_name() << "("; } for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { out << ", "; } out << "args." << (*f_iter)->get_name(); } out << ");" << endl; // Set isset on success field if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { out << indent() << "result.__isset.success = true;" << endl; } indent_down(); out << indent() << "}"; if (!tfunction->is_oneway()) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() << ") {" << endl; if (!tfunction->is_oneway()) { indent_up(); out << indent() << "result." << (*x_iter)->get_name() << " = std::move(" << (*x_iter)->get_name() << ");" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl; indent_down(); out << indent() << "}"; } else { out << "}"; } } } if (!tfunction->is_oneway()) { out << " catch (const std::exception& e) {" << endl; } else { out << " catch (const std::exception&) {" << endl; } indent_up(); out << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl; if (!tfunction->is_oneway()) { out << endl << indent() << "::apache::thrift::TApplicationException x(e.what());" << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent() << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl << indent() << "oprot->getTransport()->writeEnd();" << endl << indent() << "oprot->getTransport()->flush();" << endl; } out << indent() << "return;" << endl; indent_down(); out << indent() << "}" << endl << endl; // Shortcut out here for oneway functions if (tfunction->is_oneway()) { out << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl << endl << indent() << "return;" << endl; indent_down(); out << "}" << endl << endl; return; } // Serialize the result into a struct out << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl << indent() << "bytes = oprot->getTransport()->writeEnd();" << endl << indent() << "oprot->getTransport()->flush();" << endl << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl << indent() << "}" << endl; // Close function scope_down(out); out << endl; } // Cob style. else { // Processor entry point. // TODO(edhall) update for callContext when TEventServer is ready if (gen_templates_) { out << indent() << "template " << endl; } out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::process_" << tfunction->get_name() << "(::std::function cob, int32_t seqid, " << prot_type << "* iprot, " << prot_type << "* oprot)" << endl; scope_up(out); // TODO(simpkins): we could try to consoldate this // with the non-cob code above if (gen_templates_ && !specialized) { // If these are instances of Protocol_, instead of any old TProtocol, // use the specialized process function instead. out << indent() << "Protocol_* _iprot = dynamic_cast(iprot);" << endl << indent() << "Protocol_* _oprot = dynamic_cast(oprot);" << endl << indent() << "if (_iprot && _oprot) {" << endl << indent() << " return process_" << tfunction->get_name() << "(cob, seqid, _iprot, _oprot);" << endl << indent() << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, iprot, _iprot);" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl; } if (tfunction->is_oneway()) { out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl; } out << indent() << tservice->get_name() + "_" + tfunction->get_name() << "_args args;" << endl << indent() << "void* ctx = nullptr;" << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " ctx = this->eventHandler_->getContext(" << service_func_name << ", nullptr);" << endl << indent() << "}" << endl << indent() << "::apache::thrift::TProcessorContextFreer freer(" << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl << indent() << "try {" << endl; indent_up(); out << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl << indent() << "args.read(iprot);" << endl << indent() << "iprot->readMessageEnd();" << endl << indent() << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl << indent() << "}" << endl; scope_down(out); // TODO(dreiss): Handle TExceptions? Expose to server? out << indent() << "catch (const std::exception&) {" << endl << indent() << " if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl << indent() << " }" << endl << indent() << " return cob(false);" << endl << indent() << "}" << endl; if (tfunction->is_oneway()) { out << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl; } // TODO(dreiss): Figure out a strategy for exceptions in async handlers. out << indent() << "freer.unregister();" << endl; if (tfunction->is_oneway()) { // No return. Just hand off our cob. // TODO(dreiss): Call the cob immediately? out << indent() << "iface_->" << tfunction->get_name() << "(" << "::std::bind(cob, true)" << endl; indent_up(); indent_up(); } else { string ret_arg, ret_placeholder; if (!tfunction->get_returntype()->is_void()) { ret_arg = ", const " + type_name(tfunction->get_returntype()) + "& _return"; ret_placeholder = ", ::std::placeholders::_1"; } // When gen_templates_ is true, the return_ and throw_ functions are // overloaded. We have to declare pointers to them so that the compiler // can resolve the correct overloaded version. out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix << "::*return_fn)(::std::function " << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx" << ret_arg << ") =" << endl; out << indent() << " &" << tservice->get_name() << "AsyncProcessor" << class_suffix << "::return_" << tfunction->get_name() << ";" << endl; if (!xceptions.empty()) { out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix << "::*throw_fn)(::std::function " << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx, " << "::apache::thrift::TDelayedException* _throw) =" << endl; out << indent() << " &" << tservice->get_name() << "AsyncProcessor" << class_suffix << "::throw_" << tfunction->get_name() << ";" << endl; } out << indent() << "iface_->" << tfunction->get_name() << "(" << endl; indent_up(); indent_up(); out << indent() << "::std::bind(return_fn, this, cob, seqid, oprot, ctx" << ret_placeholder << ")"; if (!xceptions.empty()) { out << ',' << endl << indent() << "::std::bind(throw_fn, this, cob, seqid, oprot, " << "ctx, ::std::placeholders::_1)"; } } // XXX Whitespace cleanup. for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { out << ',' << endl << indent() << "args." << (*f_iter)->get_name(); } out << ");" << endl; indent_down(); indent_down(); scope_down(out); out << endl; // Normal return. if (!tfunction->is_oneway()) { string ret_arg_decl, ret_arg_name; if (!tfunction->get_returntype()->is_void()) { ret_arg_decl = ", const " + type_name(tfunction->get_returntype()) + "& _return"; ret_arg_name = ", _return"; } if (gen_templates_) { out << indent() << "template " << endl; } out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::return_" << tfunction->get_name() << "(::std::function cob, int32_t seqid, " << prot_type << "* oprot, void* ctx" << ret_arg_decl << ')' << endl; scope_up(out); if (gen_templates_ && !specialized) { // If oprot is a Protocol_ instance, // use the specialized return function instead. out << indent() << "Protocol_* _oprot = dynamic_cast(oprot);" << endl << indent() << "if (_oprot) {" << endl << indent() << " return return_" << tfunction->get_name() << "(cob, seqid, _oprot, ctx" << ret_arg_name << ");" << endl << indent() << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl; } out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_presult result;" << endl; if (!tfunction->get_returntype()->is_void()) { // The const_cast here is unfortunate, but it would be a pain to avoid, // and we only do a write with this struct, which is const-safe. out << indent() << "result.success = const_cast<" << type_name(tfunction->get_returntype()) << "*>(&_return);" << endl << indent() << "result.__isset.success = true;" << endl; } // Serialize the result into a struct out << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " ctx = this->eventHandler_->getContext(" << service_func_name << ", nullptr);" << endl << indent() << "}" << endl << indent() << "::apache::thrift::TProcessorContextFreer freer(" << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl << indent() << "oprot->getTransport()->flush();" << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl << indent() << "}" << endl << indent() << "return cob(true);" << endl; scope_down(out); out << endl; } // Exception return. if (!tfunction->is_oneway() && !xceptions.empty()) { if (gen_templates_) { out << indent() << "template " << endl; } out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::throw_" << tfunction->get_name() << "(::std::function cob, int32_t seqid, " << prot_type << "* oprot, void* ctx, " << "::apache::thrift::TDelayedException* _throw)" << endl; scope_up(out); if (gen_templates_ && !specialized) { // If oprot is a Protocol_ instance, // use the specialized throw function instead. out << indent() << "Protocol_* _oprot = dynamic_cast(oprot);" << endl << indent() << "if (_oprot) {" << endl << indent() << " return throw_" << tfunction->get_name() << "(cob, seqid, _oprot, ctx, _throw);" << endl << indent() << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl; } // Get the event handler context out << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " ctx = this->eventHandler_->getContext(" << service_func_name << ", nullptr);" << endl << indent() << "}" << endl << indent() << "::apache::thrift::TProcessorContextFreer freer(" << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl; // Throw the TDelayedException, and catch the result out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_result result;" << endl << endl << indent() << "try {" << endl; indent_up(); out << indent() << "_throw->throw_it();" << endl << indent() << "return cob(false);" << endl; // Is this possible? TBD. indent_down(); out << indent() << '}'; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() << ") {" << endl; indent_up(); out << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl; scope_down(out); } // Handle the case where an undeclared exception is thrown out << " catch (std::exception& e) {" << endl; indent_up(); out << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl << endl << indent() << "::apache::thrift::TApplicationException x(e.what());" << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent() << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl << indent() << "oprot->getTransport()->writeEnd();" << endl << indent() << "oprot->getTransport()->flush();" << endl << // We pass true to the cob here, since we did successfully write a // response, even though it is an exception response. // It looks like the argument is currently ignored, anyway. indent() << "return cob(true);" << endl; scope_down(out); // Serialize the result into a struct out << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl << indent() << "oprot->getTransport()->flush();" << endl << indent() << "if (this->eventHandler_.get() != nullptr) {" << endl << indent() << " this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl << indent() << "}" << endl << indent() << "return cob(true);" << endl; scope_down(out); out << endl; } // for each function } // cob style } /** * Generates a skeleton file of a server * * @param tservice The service to generate a server for. */ void t_cpp_generator::generate_service_skeleton(t_service* tservice) { string svcname = tservice->get_name(); // Service implementation file includes string f_skeleton_name = get_out_dir() + svcname + "_server.skeleton.cpp"; string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp")); ofstream_with_content_based_conditional_update f_skeleton; f_skeleton.open(f_skeleton_name.c_str()); f_skeleton << "// This autogenerated skeleton file illustrates how to build a server." << endl << "// You should copy it to another filename to avoid overwriting it." << endl << endl << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl << endl << "using namespace ::apache::thrift;" << endl << "using namespace ::apache::thrift::protocol;" << endl << "using namespace ::apache::thrift::transport;" << endl << "using namespace ::apache::thrift::server;" << endl << endl; // the following code would not compile: // using namespace ; // using namespace ::; if ((!ns.empty()) && (ns.compare(" ::") != 0)) { f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl; } f_skeleton << "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl << " public:" << endl; indent_up(); f_skeleton << indent() << svcname << "Handler() {" << endl << indent() << " // Your initialization goes here" << endl << indent() << "}" << endl << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_java_doc(f_skeleton, *f_iter); f_skeleton << indent() << function_signature(*f_iter, "") << " {" << endl << indent() << " // Your implementation goes here" << endl << indent() << " printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl << indent() << "}" << endl << endl; } indent_down(); f_skeleton << "};" << endl << endl; f_skeleton << indent() << "int main(int argc, char **argv) {" << endl; indent_up(); f_skeleton << indent() << "int port = 9090;" << endl << indent() << "::std::shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl << indent() << "::std::shared_ptr processor(new " << svcname << "Processor(handler));" << endl << indent() << "::std::shared_ptr serverTransport(new TServerSocket(port));" << endl << indent() << "::std::shared_ptr transportFactory(new TBufferedTransportFactory());" << endl << indent() << "::std::shared_ptr protocolFactory(new TBinaryProtocolFactory());" << endl << endl << indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl << indent() << "server.serve();" << endl << indent() << "return 0;" << endl; indent_down(); f_skeleton << "}" << endl << endl; // Close the files f_skeleton.close(); } /** * Deserializes a field of any type. */ void t_cpp_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, string suffix) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + tfield->get_name() + suffix; if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name, is_reference(tfield)); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type()) { indent(out) << "xfer += iprot->"; t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "readBinary(" << name << ");"; } else { out << "readString(" << name << ");"; } break; case t_base_type::TYPE_BOOL: out << "readBool(" << name << ");"; break; case t_base_type::TYPE_I8: out << "readByte(" << name << ");"; break; case t_base_type::TYPE_I16: out << "readI16(" << name << ");"; break; case t_base_type::TYPE_I32: out << "readI32(" << name << ");"; break; case t_base_type::TYPE_I64: out << "readI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble(" << name << ");"; break; default: throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name; } out << endl; } else if (type->is_enum()) { string t = tmp("ecast"); out << indent() << "int32_t " << t << ";" << endl << indent() << "xfer += iprot->readI32(" << t << ");" << endl << indent() << name << " = static_cast<" << type_name(type) << ">(" << t << ");" << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str()); } } /** * Generates an unserializer for a variable. This makes two key assumptions, * first that there is a const char* variable named data that points to the * buffer for deserialization, and that there is a variable protocol which * is a reference to a TProtocol serialization object. */ void t_cpp_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix, bool pointer) { if (pointer) { indent(out) << "if (!" << prefix << ") { " << endl; indent(out) << " " << prefix << " = ::std::shared_ptr<" << type_name(tstruct) << ">(new " << type_name(tstruct) << ");" << endl; indent(out) << "}" << endl; indent(out) << "xfer += " << prefix << "->read(iprot);" << endl; indent(out) << "bool wasSet = false;" << endl; const vector& members = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { indent(out) << "if (" << prefix << "->__isset." << (*f_iter)->get_name() << ") { wasSet = true; }" << endl; } indent(out) << "if (!wasSet) { " << prefix << ".reset(); }" << endl; } else { indent(out) << "xfer += " << prefix << ".read(iprot);" << endl; } } void t_cpp_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); string size = tmp("_size"); string ktype = tmp("_ktype"); string vtype = tmp("_vtype"); string etype = tmp("_etype"); t_container* tcontainer = (t_container*)ttype; bool use_push = tcontainer->has_cpp_name(); indent(out) << prefix << ".clear();" << endl << indent() << "uint32_t " << size << ";" << endl; // Declare variables, read header if (ttype->is_map()) { out << indent() << "::apache::thrift::protocol::TType " << ktype << ";" << endl << indent() << "::apache::thrift::protocol::TType " << vtype << ";" << endl << indent() << "xfer += iprot->readMapBegin(" << ktype << ", " << vtype << ", " << size << ");" << endl; } else if (ttype->is_set()) { out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent() << "xfer += iprot->readSetBegin(" << etype << ", " << size << ");" << endl; } else if (ttype->is_list()) { out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent() << "xfer += iprot->readListBegin(" << etype << ", " << size << ");" << endl; if (!use_push) { indent(out) << prefix << ".resize(" << size << ");" << endl; } } // For loop iterates over elements string i = tmp("_i"); out << indent() << "uint32_t " << i << ";" << endl << indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl; scope_up(out); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix, use_push, i); } scope_down(out); // Read container end if (ttype->is_map()) { indent(out) << "xfer += iprot->readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "xfer += iprot->readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "xfer += iprot->readListEnd();" << endl; } scope_down(out); } /** * Generates code to deserialize a map */ void t_cpp_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); out << indent() << declare_field(&fkey) << endl; generate_deserialize_field(out, &fkey); indent(out) << declare_field(&fval, false, false, false, true) << " = " << prefix << "[" << key << "];" << endl; generate_deserialize_field(out, &fval); } void t_cpp_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".insert(" << elem << ");" << endl; } void t_cpp_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix, bool use_push, string index) { if (use_push) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".push_back(" << elem << ");" << endl; } else { t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]"); generate_deserialize_field(out, &felem); } } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_cpp_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, string suffix) { t_type* type = get_true_type(tfield->get_type()); string name = prefix + tfield->get_name() + suffix; // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, name, is_reference(tfield)); } else if (type->is_container()) { generate_serialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << "xfer += oprot->"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "writeBinary(" << name << ");"; } else { out << "writeString(" << name << ");"; } break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ");"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ");"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ");"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ");"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ");"; break; default: throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + name; } } else if (type->is_enum()) { out << "writeI32(static_cast(" << name << "));"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", name.c_str(), type_name(type).c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_cpp_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix, bool pointer) { if (pointer) { indent(out) << "if (" << prefix << ") {" << endl; indent(out) << " xfer += " << prefix << "->write(oprot); " << endl; indent(out) << "} else {" << "oprot->writeStructBegin(\"" << tstruct->get_name() << "\"); " << endl; indent(out) << " oprot->writeStructEnd();" << endl; indent(out) << " oprot->writeFieldStop();" << endl; indent(out) << "}" << endl; } else { indent(out) << "xfer += " << prefix << ".write(oprot);" << endl; } } void t_cpp_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); if (ttype->is_map()) { indent(out) << "xfer += oprot->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "static_cast(" << prefix << ".size()));" << endl; } else if (ttype->is_set()) { indent(out) << "xfer += oprot->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << "static_cast(" << prefix << ".size()));" << endl; } else if (ttype->is_list()) { indent(out) << "xfer += oprot->writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << "static_cast(" << prefix << ".size()));" << endl; } string iter = tmp("_iter"); out << indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl << indent() << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl; scope_up(out); if (ttype->is_map()) { generate_serialize_map_element(out, (t_map*)ttype, iter); } else if (ttype->is_set()) { generate_serialize_set_element(out, (t_set*)ttype, iter); } else if (ttype->is_list()) { generate_serialize_list_element(out, (t_list*)ttype, iter); } scope_down(out); if (ttype->is_map()) { indent(out) << "xfer += oprot->writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "xfer += oprot->writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "xfer += oprot->writeListEnd();" << endl; } scope_down(out); } /** * Serializes the members of a map. * */ void t_cpp_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter) { t_field kfield(tmap->get_key_type(), iter + "->first"); generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), iter + "->second"); generate_serialize_field(out, &vfield, ""); } /** * Serializes the members of a set. */ void t_cpp_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), "(*" + iter + ")"); generate_serialize_field(out, &efield, ""); } /** * Serializes the members of a list. */ void t_cpp_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), "(*" + iter + ")"); generate_serialize_field(out, &efield, ""); } /** * Makes a :: prefix for a namespace * * @param ns The namespace, w/ periods in it * @return Namespaces */ string t_cpp_generator::namespace_prefix(string ns) { // Always start with "::", to avoid possible name collisions with // other names in one of the current namespaces. // // We also need a leading space, in case the name is used inside of a // template parameter. "MyTemplate<::foo::Bar>" is not valid C++, // since "<:" is an alternative token for "[". string result = " ::"; if (ns.size() == 0) { return result; } string::size_type loc; while ((loc = ns.find(".")) != string::npos) { result += ns.substr(0, loc); result += "::"; ns = ns.substr(loc + 1); } if (ns.size() > 0) { result += ns + "::"; } return result; } /** * Opens namespace. * * @param ns The namespace, w/ periods in it * @return Namespaces */ string t_cpp_generator::namespace_open(string ns) { if (ns.size() == 0) { return ""; } string result = ""; string separator = ""; string::size_type loc; while ((loc = ns.find(".")) != string::npos) { result += separator; result += "namespace "; result += ns.substr(0, loc); result += " {"; separator = " "; ns = ns.substr(loc + 1); } if (ns.size() > 0) { result += separator + "namespace " + ns + " {"; } return result; } /** * Closes namespace. * * @param ns The namespace, w/ periods in it * @return Namespaces */ string t_cpp_generator::namespace_close(string ns) { if (ns.size() == 0) { return ""; } string result = "}"; string::size_type loc; while ((loc = ns.find(".")) != string::npos) { result += "}"; ns = ns.substr(loc + 1); } result += " // namespace"; return result; } /** * Returns a C++ type name * * @param ttype The type * @return String of the type name, i.e. std::set */ string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) { if (ttype->is_base_type()) { string bname = base_type_name(((t_base_type*)ttype)->get_base()); std::map::iterator it = ttype->annotations_.find("cpp.type"); if (it != ttype->annotations_.end()) { bname = it->second; } if (!arg) { return bname; } if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) { return "const " + bname + "&"; } else { return "const " + bname; } } // Check for a custom overloaded C++ name if (ttype->is_container()) { string cname; t_container* tcontainer = (t_container*)ttype; if (tcontainer->has_cpp_name()) { cname = tcontainer->get_cpp_name(); } else if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; cname = "std::map<" + type_name(tmap->get_key_type(), in_typedef) + ", " + type_name(tmap->get_val_type(), in_typedef) + "> "; } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> "; } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> "; } if (arg) { return "const " + cname + "&"; } else { return cname; } } string class_prefix; if (in_typedef && (ttype->is_struct() || ttype->is_xception())) { class_prefix = "class "; } // Check if it needs to be namespaced string pname; t_program* program = ttype->get_program(); if (program != nullptr && program != program_) { pname = class_prefix + namespace_prefix(program->get_namespace("cpp")) + ttype->get_name(); } else { pname = class_prefix + ttype->get_name(); } if (ttype->is_enum() && !gen_pure_enums_) { pname += "::type"; } if (arg) { if (is_complex_type(ttype)) { return "const " + pname + "&"; } else { return "const " + pname; } } else { return pname; } } /** * Returns the C++ type that corresponds to the thrift type. * * @param tbase The base type * @return Explicit C++ type, i.e. "int32_t" */ string t_cpp_generator::base_type_name(t_base_type::t_base tbase) { switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: return "std::string"; case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: return "int8_t"; case t_base_type::TYPE_I16: return "int16_t"; case t_base_type::TYPE_I32: return "int32_t"; case t_base_type::TYPE_I64: return "int64_t"; case t_base_type::TYPE_DOUBLE: return "double"; default: throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase); } } /** * Declares a field, which may include initialization as necessary. * * @param ttype The type * @return Field declaration, i.e. int x = 0; */ string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant, bool reference) { // TODO(mcslee): do we ever need to initialize the field? string result = ""; if (constant) { result += "const "; } result += type_name(tfield->get_type()); if (is_reference(tfield)) { result = "::std::shared_ptr<" + result + ">"; } if (pointer) { result += "*"; } if (reference) { result += "&"; } result += " " + tfield->get_name(); if (init) { t_type* type = get_true_type(tfield->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: case t_base_type::TYPE_STRING: break; case t_base_type::TYPE_BOOL: result += " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = 0.0"; break; default: throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { result += " = static_cast<" + type_name(type) + ">(0)"; } } if (!reference) { result += ";"; } return result; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_cpp_generator::function_signature(t_function* tfunction, string style, string prefix, bool name_params) { t_type* ttype = tfunction->get_returntype(); t_struct* arglist = tfunction->get_arglist(); bool has_xceptions = !tfunction->get_xceptions()->get_members().empty(); if (style == "") { if (is_complex_type(ttype)) { return "void " + prefix + tfunction->get_name() + "(" + type_name(ttype) + (name_params ? "& _return" : "& /* _return */") + argument_list(arglist, name_params, true) + ")"; } else { return type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(arglist, name_params) + ")"; } } else if (style.substr(0, 3) == "Cob") { string cob_type; string exn_cob; if (style == "CobCl") { cob_type = "(" + service_name_ + "CobClient"; if (gen_templates_) { cob_type += "T"; } cob_type += "* client)"; } else if (style == "CobSv") { cob_type = (ttype->is_void() ? "()" : ("(" + type_name(ttype) + " const& _return)")); if (has_xceptions) { exn_cob = ", ::std::function /* exn_cob */"; } } else { throw "UNKNOWN STYLE"; } return "void " + prefix + tfunction->get_name() + "(::std::function cob" + exn_cob + argument_list(arglist, name_params, true) + ")"; } else { throw "UNKNOWN STYLE"; } } /** * Renders a field list * * @param tstruct The struct definition * @return Comma sepearated list of all field names in that struct */ string t_cpp_generator::argument_list(t_struct* tstruct, bool name_params, bool start_comma) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = !start_comma; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += type_name((*f_iter)->get_type(), false, true) + " " + (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */"); } return result; } /** * Converts the parse type to a C++ enum string for the given type. * * @param type Thrift Type * @return String of C++ code to definition of that type constant */ string t_cpp_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "::apache::thrift::protocol::T_STRING"; case t_base_type::TYPE_BOOL: return "::apache::thrift::protocol::T_BOOL"; case t_base_type::TYPE_I8: return "::apache::thrift::protocol::T_BYTE"; case t_base_type::TYPE_I16: return "::apache::thrift::protocol::T_I16"; case t_base_type::TYPE_I32: return "::apache::thrift::protocol::T_I32"; case t_base_type::TYPE_I64: return "::apache::thrift::protocol::T_I64"; case t_base_type::TYPE_DOUBLE: return "::apache::thrift::protocol::T_DOUBLE"; } } else if (type->is_enum()) { return "::apache::thrift::protocol::T_I32"; } else if (type->is_struct()) { return "::apache::thrift::protocol::T_STRUCT"; } else if (type->is_xception()) { return "::apache::thrift::protocol::T_STRUCT"; } else if (type->is_map()) { return "::apache::thrift::protocol::T_MAP"; } else if (type->is_set()) { return "::apache::thrift::protocol::T_SET"; } else if (type->is_list()) { return "::apache::thrift::protocol::T_LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } bool t_cpp_generator::is_struct_storage_not_throwing(t_struct* tstruct) const { vector members = tstruct->get_members(); for(size_t i=0; i < members.size(); ++i) { t_type* type = get_true_type(members[i]->get_type()); if(type->is_enum()) continue; if(type->is_xception()) return false; if(type->is_base_type()) switch(((t_base_type*)type)->get_base()) { case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: continue; case t_base_type::TYPE_VOID: case t_base_type::TYPE_STRING: default: return false; } if(type->is_struct()) { const vector& more = ((t_struct*)type)->get_members(); for(auto it = more.begin(); it < more.end(); ++it) { if(std::find(members.begin(), members.end(), *it) == members.end()) members.push_back(*it); } continue; } return false; // rest-as-throwing(require-alloc) } return true; } string t_cpp_generator::get_include_prefix(const t_program& program) const { string include_prefix = program.get_include_prefix(); if (!use_include_prefix_ || (include_prefix.size() > 0 && include_prefix[0] == '/')) { // if flag is turned off or this is absolute path, return empty prefix return ""; } string::size_type last_slash = string::npos; if ((last_slash = include_prefix.rfind("/")) != string::npos) { return include_prefix.substr(0, last_slash) + (get_program()->is_out_path_absolute() ? "/" : "/" + out_dir_base_ + "/"); } return ""; } string t_cpp_generator::get_legal_program_name(std::string program_name) { std::size_t found = 0; while(true) { found = program_name.find('.'); if(found != string::npos) { program_name = program_name.replace(found, 1, "_"); } else { break; } } return program_name; } THRIFT_REGISTER_GENERATOR( cpp, "C++", " cob_style: Generate \"Continuation OBject\"-style classes.\n" " no_client_completion:\n" " Omit calls to completion__() in CobClient class.\n" " no_default_operators:\n" " Omits generation of default operators ==, != and <\n" " templates: Generate templatized reader/writer methods.\n" " pure_enums: Generate pure enums instead of wrapper classes.\n" " include_prefix: Use full include paths in generated files.\n" " moveable_types: Generate move constructors and assignment operators.\n" " no_ostream_operators:\n" " Omit generation of ostream definitions.\n" " no_skeleton: Omits generation of skeleton.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_d_generator.cc000066400000000000000000000660511420101504100244720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ofstream; using std::ostream; using std::ostringstream; using std::set; using std::string; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * D code generator. * * generate_*() functions are called by the base class to emit code for the * given entity, print_*() functions write a piece of code to the passed * stream, and render_*() return a string containing the D representation of * the passed entity. */ class t_d_generator : public t_oop_generator { public: t_d_generator(t_program* program, const std::map& parsed_options, const string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option d:" + iter->first; } out_dir_base_ = "gen-d"; } protected: // D reserved words are suffixed with an underscore static string suffix_if_reserved(const string& name) { const bool isIn = std::binary_search(std::begin(d_reserved_words), std::end(d_reserved_words), name); string ret = isIn ? name + "_" : name; return ret; } void init_generator() override { // Make output directory MKDIR(get_out_dir().c_str()); string dir = program_->get_namespace("d"); string subdir = get_out_dir(); string::size_type loc; while ((loc = dir.find(".")) != string::npos) { subdir = subdir + "/" + dir.substr(0, loc); MKDIR(subdir.c_str()); dir = dir.substr(loc + 1); } if (!dir.empty()) { subdir = subdir + "/" + dir; MKDIR(subdir.c_str()); } package_dir_ = subdir + "/"; // Make output file string f_types_name = package_dir_ + program_name_ + "_types.d"; f_types_.open(f_types_name.c_str()); // Print header f_types_ << autogen_comment() << "module " << render_package(*program_) << program_name_ << "_types;" << endl << endl; print_default_imports(f_types_); // Include type modules from other imported programs. const vector& includes = program_->get_includes(); for (auto include : includes) { f_types_ << "public import " << render_package(*include) << include->get_name() << "_types;" << endl; } if (!includes.empty()) f_types_ << endl; } void close_generator() override { // Close output file f_types_.close(); } void generate_consts(std::vector consts) override { if (!consts.empty()) { string f_consts_name = package_dir_ + program_name_ + "_constants.d"; ofstream_with_content_based_conditional_update f_consts; f_consts.open(f_consts_name.c_str()); f_consts << autogen_comment() << "module " << render_package(*program_) << program_name_ << "_constants;" << endl << endl; print_default_imports(f_consts); f_consts << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl << endl; vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { this->emit_doc(*c_iter, f_consts); string name = suffix_if_reserved((*c_iter)->get_name()); t_type* type = (*c_iter)->get_type(); indent(f_consts) << "immutable(" << render_type_name(type) << ") " << name << ";" << endl; } f_consts << endl << "shared static this() {" << endl; indent_up(); bool first = true; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { if (first) { first = false; } else { f_consts << endl; } t_type* type = (*c_iter)->get_type(); indent(f_consts) << suffix_if_reserved((*c_iter)->get_name()) << " = "; if (!is_immutable_type(type)) { f_consts << "cast(immutable(" << render_type_name(type) << ")) "; } f_consts << render_const_value(type, (*c_iter)->get_value()) << ";" << endl; } indent_down(); indent(f_consts) << "}" << endl; } } void generate_typedef(t_typedef* ttypedef) override { this->emit_doc(ttypedef, f_types_); f_types_ << indent() << "alias " << render_type_name(ttypedef->get_type()) << " " << ttypedef->get_symbolic() << ";" << endl << endl; } void generate_enum(t_enum* tenum) override { vector constants = tenum->get_constants(); this->emit_doc(tenum, f_types_); string enum_name = suffix_if_reserved(tenum->get_name()); f_types_ << indent() << "enum " << enum_name << " {" << endl; indent_up(); vector::const_iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { this->emit_doc(*c_iter, f_types_); indent(f_types_) << suffix_if_reserved((*c_iter)->get_name()); f_types_ << " = " << (*c_iter)->get_value() << ","; } f_types_ << endl; indent_down(); indent(f_types_) << "}" << endl; f_types_ << endl; } void generate_struct(t_struct* tstruct) override { print_struct_definition(f_types_, tstruct, false); } void generate_xception(t_struct* txception) override { print_struct_definition(f_types_, txception, true); } void generate_service(t_service* tservice) override { string svc_name = suffix_if_reserved(tservice->get_name()); // Service implementation file includes string f_servicename = package_dir_ + svc_name + ".d"; ofstream_with_content_based_conditional_update f_service; f_service.open(f_servicename.c_str()); f_service << autogen_comment() << "module " << suffix_if_reserved(render_package(*program_)) << svc_name << ";" << endl << endl; print_default_imports(f_service); f_service << "import " << suffix_if_reserved(render_package(*get_program())) << program_name_ << "_types;" << endl; t_service* extends_service = tservice->get_extends(); if (extends_service != nullptr) { f_service << "import " << suffix_if_reserved(render_package(*(extends_service->get_program()))) << suffix_if_reserved(extends_service->get_name()) << ";" << endl; } f_service << endl; string extends = ""; if (tservice->get_extends() != nullptr) { extends = " : " + suffix_if_reserved(render_type_name(tservice->get_extends())); } this->emit_doc(tservice, f_service); f_service << indent() << "interface " << svc_name << extends << " {" << endl; indent_up(); // Collect all the exception types service methods can throw so we can // emit the necessary aliases later. set exception_types; // Print the method signatures. vector functions = tservice->get_functions(); vector::iterator fn_iter; for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { this->emit_doc(*fn_iter, f_service); f_service << indent(); print_function_signature(f_service, *fn_iter); f_service << ";" << endl; const vector& exceptions = (*fn_iter)->get_xceptions()->get_members(); vector::const_iterator ex_iter; for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) { exception_types.insert((*ex_iter)->get_type()); } } // Alias the exception types into the current scope. if (!exception_types.empty()) f_service << endl; set::const_iterator et_iter; for (et_iter = exception_types.begin(); et_iter != exception_types.end(); ++et_iter) { indent(f_service) << "alias " << render_package(*(*et_iter)->get_program()) << (*et_iter)->get_program()->get_name() << "_types" << "." << (*et_iter)->get_name() << " " << (*et_iter)->get_name() << ";" << endl; } // Write the method metadata. ostringstream meta; indent_up(); bool first = true; for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { if ((*fn_iter)->get_arglist()->get_members().empty() && (*fn_iter)->get_xceptions()->get_members().empty() && !(*fn_iter)->is_oneway()) { continue; } if (first) { first = false; } else { meta << ","; } meta << endl << indent() << "TMethodMeta(`" << suffix_if_reserved((*fn_iter)->get_name()) << "`, " << endl; indent_up(); indent(meta) << "["; bool first = true; const vector& params = (*fn_iter)->get_arglist()->get_members(); vector::const_iterator p_iter; for (p_iter = params.begin(); p_iter != params.end(); ++p_iter) { if (first) { first = false; } else { meta << ", "; } meta << "TParamMeta(`" << suffix_if_reserved((*p_iter)->get_name()) << "`, " << (*p_iter)->get_key(); t_const_value* cv = (*p_iter)->get_value(); if (cv != nullptr) { meta << ", q{" << render_const_value((*p_iter)->get_type(), cv) << "}"; } meta << ")"; } meta << "]"; if (!(*fn_iter)->get_xceptions()->get_members().empty() || (*fn_iter)->is_oneway()) { meta << "," << endl << indent() << "["; bool first = true; const vector& exceptions = (*fn_iter)->get_xceptions()->get_members(); vector::const_iterator ex_iter; for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) { if (first) { first = false; } else { meta << ", "; } meta << "TExceptionMeta(`" << suffix_if_reserved((*ex_iter)->get_name()) << "`, " << (*ex_iter)->get_key() << ", `" << (*ex_iter)->get_type()->get_name() << "`)"; } meta << "]"; } if ((*fn_iter)->is_oneway()) { meta << "," << endl << indent() << "TMethodType.ONEWAY"; } indent_down(); meta << endl << indent() << ")"; } indent_down(); string meta_str(meta.str()); if (!meta_str.empty()) { f_service << endl << indent() << "enum methodMeta = [" << meta_str << endl << indent() << "];" << endl; } indent_down(); indent(f_service) << "}" << endl; // Server skeleton generation. string f_skeletonname = package_dir_ + svc_name + "_server.skeleton.d"; ofstream_with_content_based_conditional_update f_skeleton; f_skeleton.open(f_skeletonname.c_str()); print_server_skeleton(f_skeleton, tservice); f_skeleton.close(); } void emit_doc(t_doc *doc, std::ostream& out) { if (!doc->has_doc()) { return; } indent(out) << "/**" << std::endl; indent_up(); // No endl -- comments reliably have a newline at the end. // This is true even for stuff like: // /** method infos */ void foo(/** huh?*/ 1: i64 stuff) indent(out) << doc->get_doc(); indent_down(); indent(out) << "*/" << std::endl; } private: /** * Writes a server skeleton for the passed service to out. */ void print_server_skeleton(ostream& out, t_service* tservice) { string svc_name = suffix_if_reserved(tservice->get_name()); out << "/*" << endl << " * This auto-generated skeleton file illustrates how to build a server. If you" << endl << " * intend to customize it, you should edit a copy with another file name to " << endl << " * avoid overwriting it when running the generator again." << endl << " */" << endl << "module " << render_package(*tservice->get_program()) << svc_name << "_server;" << endl << endl << "import std.stdio;" << endl << "import thrift.codegen.processor;" << endl << "import thrift.protocol.binary;" << endl << "import thrift.server.simple;" << endl << "import thrift.server.transport.socket;" << endl << "import thrift.transport.buffered;" << endl << "import thrift.util.hashset;" << endl << endl << "import " << render_package(*tservice->get_program()) << svc_name << ";" << endl << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl << endl << endl << "class " << svc_name << "Handler : " << svc_name << " {" << endl; indent_up(); out << indent() << "this() {" << endl << indent() << " // Your initialization goes here." << endl << indent() << "}" << endl << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { out << indent(); print_function_signature(out, *f_iter); out << " {" << endl; indent_up(); out << indent() << "// Your implementation goes here." << endl << indent() << "writeln(\"" << suffix_if_reserved((*f_iter)->get_name()) << " called\");" << endl; t_type* rt = (*f_iter)->get_returntype(); if (!rt->is_void()) { indent(out) << "return typeof(return).init;" << endl; } indent_down(); out << indent() << "}" << endl << endl; } indent_down(); out << "}" << endl << endl; out << indent() << "void main() {" << endl; indent_up(); out << indent() << "auto protocolFactory = new TBinaryProtocolFactory!();" << endl << indent() << "auto processor = new TServiceProcessor!" << svc_name << "(new " << svc_name << "Handler);" << endl << indent() << "auto serverTransport = new TServerSocket(9090);" << endl << indent() << "auto transportFactory = new TBufferedTransportFactory;" << endl << indent() << "auto server = new TSimpleServer(" << endl << indent() << " processor, serverTransport, transportFactory, protocolFactory);" << endl << indent() << "server.serve();" << endl; indent_down(); out << "}" << endl; } /** * Writes the definition of a struct or an exception type to out. */ void print_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) { const vector& members = tstruct->get_members(); if (is_exception) { indent(out) << "class " << suffix_if_reserved(tstruct->get_name()) << " : TException {" << endl; } else { indent(out) << "struct " << suffix_if_reserved(tstruct->get_name()) << " {" << endl; } indent_up(); // Declare all fields. vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << render_type_name((*m_iter)->get_type()) << " " << suffix_if_reserved((*m_iter)->get_name()) << ";" << endl; } if (!members.empty()) indent(out) << endl; indent(out) << "mixin TStructHelpers!("; if (!members.empty()) { // If there are any fields, construct the TFieldMeta array to pass to // TStructHelpers. We can't just pass an empty array if not because [] // doesn't pass the TFieldMeta[] constraint. out << "["; indent_up(); bool first = true; vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (first) { first = false; } else { out << ","; } out << endl; indent(out) << "TFieldMeta(`" << suffix_if_reserved((*m_iter)->get_name()) << "`, " << (*m_iter)->get_key(); t_const_value* cv = (*m_iter)->get_value(); t_field::e_req req = (*m_iter)->get_req(); out << ", " << render_req(req); if (cv != nullptr) { out << ", q{" << render_const_value((*m_iter)->get_type(), cv) << "}"; } out << ")"; } indent_down(); out << endl << indent() << "]"; } out << ");" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Prints the D function signature (including return type) for the given * method. */ void print_function_signature(ostream& out, t_function* fn) { out << render_type_name(fn->get_returntype()) << " " << suffix_if_reserved(fn->get_name()) << "("; const vector& fields = fn->get_arglist()->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { out << ", "; } out << render_type_name((*f_iter)->get_type(), true) << " " << suffix_if_reserved((*f_iter)->get_name()); } out << ")"; } /** * Returns the D representation of value. The result is guaranteed to be a * single expression; for complex types, immediately called delegate * literals are used to achieve this. */ string render_const_value(t_type* type, t_const_value* value) { // Resolve any typedefs. type = get_true_type(type); ostringstream out; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: out << "cast(" << render_type_name(type) << ")" << value->get_integer(); break; case t_base_type::TYPE_I32: out << value->get_integer(); break; case t_base_type::TYPE_I64: out << value->get_integer() << "L"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "Compiler error: No const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "cast(" << render_type_name(type) << ")" << value->get_integer(); } else { out << "{" << endl; indent_up(); indent(out) << render_type_name(type) << " v;" << endl; if (type->is_struct() || type->is_xception()) { indent(out) << "v = " << (type->is_xception() ? "new " : "") << render_type_name(type) << "();" << endl; const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "Type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string val = render_const_value(field_type, v_iter->second); indent(out) << "v.set!`" << v_iter->first->get_string() << "`(" << val << ");" << endl; } } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(ktype, v_iter->first); string val = render_const_value(vtype, v_iter->second); indent(out) << "v["; if (!is_immutable_type(ktype)) { out << "cast(immutable(" << render_type_name(ktype) << "))"; } out << key << "] = " << val << ";" << endl; } } else if (type->is_list()) { t_type* etype = ((t_list*)type)->get_elem_type(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(etype, *v_iter); indent(out) << "v ~= " << val << ";" << endl; } } else if (type->is_set()) { t_type* etype = ((t_set*)type)->get_elem_type(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(etype, *v_iter); indent(out) << "v ~= " << val << ";" << endl; } } else { throw "Compiler error: Invalid type in render_const_value: " + type->get_name(); } indent(out) << "return v;" << endl; indent_down(); indent(out) << "}()"; } return out.str(); } /** * Returns the D package to which modules for program are written (with a * trailing dot, if not empty). */ string render_package(const t_program& program) const { string package = program.get_namespace("d"); if (package.size() == 0) return ""; return package + "."; } /** * Returns the name of the D repesentation of ttype. * * If isArg is true, a const reference to the type will be returned for * structs. */ string render_type_name(const t_type* ttype, bool isArg = false) const { if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: return "string"; case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: return "byte"; case t_base_type::TYPE_I16: return "short"; case t_base_type::TYPE_I32: return "int"; case t_base_type::TYPE_I64: return "long"; case t_base_type::TYPE_DOUBLE: return "double"; default: throw "Compiler error: No D type name for base type " + t_base_type::t_base_name(tbase); } } if (ttype->is_container()) { t_container* tcontainer = (t_container*)ttype; if (tcontainer->has_cpp_name()) { return tcontainer->get_cpp_name(); } else if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; t_type* ktype = tmap->get_key_type(); string name = render_type_name(tmap->get_val_type()) + "["; if (!is_immutable_type(ktype)) { name += "immutable("; } name += render_type_name(ktype); if (!is_immutable_type(ktype)) { name += ")"; } name += "]"; return name; } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; return "HashSet!(" + render_type_name(tset->get_elem_type()) + ")"; } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; return render_type_name(tlist->get_elem_type()) + "[]"; } } if (ttype->is_struct() && isArg) { return "ref const(" + ttype->get_name() + ")"; } else { return ttype->get_name(); } } /** * Returns the D TReq enum member corresponding to req. */ string render_req(t_field::e_req req) const { switch (req) { case t_field::T_OPT_IN_REQ_OUT: return "TReq.OPT_IN_REQ_OUT"; case t_field::T_OPTIONAL: return "TReq.OPTIONAL"; case t_field::T_REQUIRED: return "TReq.REQUIRED"; default: { std::stringstream ss; ss << "Compiler error: Invalid requirement level " << req; throw ss.str(); } } } /** * Writes the default list of imports (which are written to every generated * module) to f. */ void print_default_imports(ostream& out) { indent(out) << "import thrift.base;" << endl << "import thrift.codegen.base;" << endl << "import thrift.util.hashset;" << endl << endl; } /** * Returns whether type is »intrinsically immutable«, in the sense that * a value of that type is implicitly castable to immutable(type), and it is * allowed for AA keys without an immutable() qualifier. */ bool is_immutable_type(t_type* type) const { t_type* ttype = get_true_type(type); return ttype->is_base_type() || ttype->is_enum(); } /* * File streams, stored here to avoid passing them as parameters to every * function. */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_header_; string package_dir_; protected: static vector d_reserved_words; }; vector t_d_generator::d_reserved_words = { // The keywords are extracted from https://dlang.org/spec/lex.html // and sorted for use with std::binary_search "__FILE_FULL_PATH__", "__FILE__", "__FUNCTION__", "__LINE__", "__MODULE__", "__PRETTY_FUNCTION__", "__gshared", "__parameters", "__traits", "__vector", "abstract", "alias", "align", "asm", "assert", "auto", "body", "bool", "break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class", "const", "continue", "creal", "dchar", "debug", "default", "delegate", "delete", "deprecated", "do", "double", "else", "enum", "export", "extern", "false", "final", "finally", "float", "for", "foreach", "foreach_reverse", "function", "goto", "idouble", "if", "ifloat", "immutable", "import", "in", "inout", "int", "interface", "invariant", "ireal", "is", "lazy", "long", "macro ", "mixin", "module", "new", "nothrow", "null", "out", "override", "package", "pragma", "private", "protected", "public", "pure", "real", "ref", "return", "scope", "shared", "short", "static", "struct", "super", "switch", "synchronized", "template", "this", "throw", "true", "try", "typeid", "typeof", "ubyte", "ucent", "uint", "ulong", "union", "unittest", "ushort", "version", "void", "wchar", "while", "with" }; THRIFT_REGISTER_GENERATOR(d, "D", "") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_dart_generator.cc000066400000000000000000002364071420101504100252050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes static const string endl2 = "\n\n"; /** * Use the current Thrift version for static libraries. When releasing, update * the version in these files. * - lib/dart/pubspec.yaml * - test/dart/test_client/pubspec.yaml * - tutorial/dart/client/pubspec.yaml * - tutorial/dart/console_client/pubspec.yaml * - tutorial/dart/server/pubspec.yaml * See https://thrift.apache.org/docs/committers/HowToVersion */ static const string dart_thrift_version = THRIFT_VERSION; /* forward declarations */ string initial_caps_to_underscores(string name); /** * Dart code generator * */ class t_dart_generator : public t_oop_generator { public: t_dart_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; library_name_ = ""; library_prefix_ = ""; package_prefix_ = ""; pubspec_lib_ = ""; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("library_name") == 0) { library_name_ = (iter->second); } else if( iter->first.compare("library_prefix") == 0) { library_prefix_ = (iter->second) + "."; package_prefix_ = replace_all(library_prefix_, ".", "/"); } else if( iter->first.compare("pubspec_lib") == 0) { pubspec_lib_ = (iter->second); } else { throw "unknown option dart:" + iter->first; } } out_dir_base_ = "gen-dart"; } void scope_up(std::ostream& out, std::string prefix=" ") { out << prefix << "{" << endl; indent_up(); } void scope_down(std::ostream& out, std::string postfix=endl) { indent_down(); indent(out) << "}" << postfix; } string replace_all(string contents, string search, string repl) { string str(contents); size_t slen = search.length(); size_t rlen = repl.length(); size_t incr = (rlen > 0) ? rlen : 1; if (slen > 0) { size_t found = str.find(search); while ((found != string::npos) && (found < str.length())) { str.replace(found, slen, repl); found = str.find(search, found + incr); } } return str; } /** * Init and close methods */ void init_generator() override; void close_generator() override; void export_class_to_library(string file_name, string class_name); void generate_dart_library(); void generate_dart_pubspec(); void generate_consts(std::vector consts) override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void print_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval = false); std::string render_const_value(ostream& out, std::string name, t_type* type, t_const_value* value); /** * Service-level generation functions */ void generate_dart_struct(t_struct* tstruct, bool is_exception); void generate_dart_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool is_result = false, string export_file_name = ""); void generate_dart_struct_reader(std::ostream& out, t_struct* tstruct); void generate_dart_validator(std::ostream& out, t_struct* tstruct); void generate_dart_struct_result_writer(std::ostream& out, t_struct* tstruct); void generate_dart_struct_writer(std::ostream& out, t_struct* tstruct); void generate_dart_struct_tostring(std::ostream& out, t_struct* tstruct); std::string get_dart_type_string(t_type* type); void generate_generic_field_getters(std::ostream& out, t_struct* tstruct); void generate_generic_field_setters(std::ostream& out, t_struct* tstruct); void generate_generic_isset_method(std::ostream& out, t_struct* tstruct); void generate_dart_bean_boilerplate(std::ostream& out, t_struct* tstruct); void generate_function_helpers(t_function* tfunction); std::string init_value(t_field* tfield); std::string get_cap_name(std::string name); std::string get_member_name(std::string name); std::string get_args_class_name(std::string name); std::string get_result_class_name(std::string name); std::string get_file_name(std::string name); std::string get_constants_class_name(std::string name); std::string generate_isset_check(t_field* field); std::string generate_isset_check(std::string field); void generate_isset_set(ostream& out, t_field* field); void generate_service_interface(t_service* tservice); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string iter, std::string map); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); void generate_dart_doc(std::ostream& out, t_doc* tdoc); void generate_dart_doc(std::ostream& out, t_function* tdoc); /** * Helper rendering functions */ std::string find_library_name(t_program* program); std::string dart_library(string file_name); std::string service_imports(); std::string dart_thrift_imports(); std::string type_name(t_type* ttype); std::string base_type_name(t_base_type* tbase); std::string declare_field(t_field* tfield, bool init = false); std::string function_signature(t_function* tfunction); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string get_ttype_class_name(t_type* ttype); bool type_can_be_null(t_type* ttype) { ttype = get_true_type(ttype); return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string(); } vector split(const string& s, char delim) { vector elems; stringstream ss(s); string item; while (getline(ss, item, delim)) { elems.push_back(item); } return elems; } std::string constant_name(std::string name); private: ofstream_with_content_based_conditional_update f_service_; std::string library_name_; std::string library_prefix_; std::string package_prefix_; std::string pubspec_lib_; std::string base_dir_; std::string src_dir_; std::string library_exports_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_dart_generator::init_generator() { MKDIR(get_out_dir().c_str()); if (library_name_.empty()) { library_name_ = find_library_name(program_); } string subdir = get_out_dir() + "/" + library_name_; MKDIR(subdir.c_str()); base_dir_ = subdir; if (library_prefix_.empty()) { subdir += "/lib"; MKDIR(subdir.c_str()); subdir += "/src"; MKDIR(subdir.c_str()); src_dir_ = subdir; } else { src_dir_ = base_dir_; } } string t_dart_generator::find_library_name(t_program* program) { string name = program->get_namespace("dart"); if (name.empty()) { name = program->get_name(); } name = replace_all(name, ".", "_"); name = replace_all(name, "-", "_"); return name; } /** * The Dart library * * @return String of the library, e.g. "library myservice;" */ string t_dart_generator::dart_library(string file_name) { string out = "library " + library_prefix_ + library_name_; if (!file_name.empty()) { if (library_prefix_.empty()) { out += ".src." + file_name; } else { out += "." + file_name; } } return out + ";\n"; } /** * Prints imports for services * * @return List of imports for services */ string t_dart_generator::service_imports() { return "import 'dart:async';" + endl; } /** * Prints standard dart imports * * @return List of imports necessary for thrift */ string t_dart_generator::dart_thrift_imports() { string imports = "import 'dart:typed_data' show Uint8List;" + endl + "import 'package:thrift/thrift.dart';" + endl; // add import for this library if (package_prefix_.empty()) { imports += "import 'package:" + library_name_ + "/" + library_name_ + ".dart';" + endl; } else { imports += "import 'package:" + package_prefix_ + library_name_ + ".dart';" + endl; } // add imports for included thrift files const vector& includes = program_->get_includes(); for (auto include : includes) { string include_name = find_library_name(include); string named_import = "t_" + include_name; if (package_prefix_.empty()) { imports += "import 'package:" + include_name + "/" + include_name + ".dart' as " + named_import + ";" + endl; } else { imports += "import 'package:" + package_prefix_ + include_name + ".dart' as " + named_import + ";" + endl; } } return imports; } /** * Not used */ void t_dart_generator::close_generator() { generate_dart_library(); if (library_prefix_.empty()) { generate_dart_pubspec(); } } void t_dart_generator::generate_dart_library() { string f_library_name; if (library_prefix_.empty()) { f_library_name = base_dir_ + "/lib/" + library_name_ + ".dart"; } else { f_library_name = get_out_dir() + "/" + library_name_ + ".dart"; } ofstream_with_content_based_conditional_update f_library; f_library.open(f_library_name.c_str()); f_library << autogen_comment() << endl; f_library << "library " << library_prefix_ << library_name_ << ";" << endl2; f_library << library_exports_; f_library.close(); } void t_dart_generator::export_class_to_library(string file_name, string class_name) { string subdir; if (library_prefix_.empty()) { subdir = "src"; } else { subdir = library_name_; } library_exports_ += "export '" + subdir + "/" + file_name + ".dart' show " + class_name + ";" + endl; } void t_dart_generator::generate_dart_pubspec() { string f_pubspec_name = base_dir_ + "/pubspec.yaml"; ofstream_with_content_based_conditional_update f_pubspec; f_pubspec.open(f_pubspec_name.c_str()); indent(f_pubspec) << "name: " << library_name_ << endl; indent(f_pubspec) << "version: 0.0.1" << endl; indent(f_pubspec) << "description: Autogenerated by Thrift Compiler" << endl; f_pubspec << endl; indent(f_pubspec) << "environment:" << endl; indent_up(); indent(f_pubspec) << "sdk: '>=1.24.3 <3.0.0'" << endl; indent_down(); f_pubspec << endl; indent(f_pubspec) << "dependencies:" << endl; indent_up(); if (pubspec_lib_.empty()) { // default to relative path within working directory, which works for tests indent(f_pubspec) << "thrift: # ^" << dart_thrift_version << endl; indent_up(); indent(f_pubspec) << "path: ../../../../lib/dart" << endl; indent_down(); } else { const vector lines = split(pubspec_lib_, '|'); for (const auto & line : lines) { indent(f_pubspec) << line << endl; } } // add included thrift files as dependencies const vector& includes = program_->get_includes(); for (auto include : includes) { string include_name = find_library_name(include); indent(f_pubspec) << include_name << ":" << endl; indent_up(); indent(f_pubspec) << "path: ../" << include_name << endl; indent_down(); } indent_down(); f_pubspec << endl; f_pubspec.close(); } /** * Not used * * @param ttypedef The type definition */ void t_dart_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Enums are a class with a set of static constants. * * @param tenum The enumeration */ void t_dart_generator::generate_enum(t_enum* tenum) { // Make output file string file_name = get_file_name(tenum->get_name()); string f_enum_name = src_dir_ + "/" + file_name + ".dart"; ofstream_with_content_based_conditional_update f_enum; f_enum.open(f_enum_name.c_str()); // Comment and add library f_enum << autogen_comment() << dart_library(file_name) << endl; string class_name = tenum->get_name(); export_class_to_library(file_name, class_name); f_enum << "class " << class_name; scope_up(f_enum); vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); indent(f_enum) << "static const int " << (*c_iter)->get_name() << " = " << value << ";" << endl; } // Create a static Set with all valid values for this enum f_enum << endl; indent(f_enum) << "static final Set VALID_VALUES = new Set.from([" << endl; indent_up(); bool firstValue = true; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { // populate set indent(f_enum) << (firstValue ? "" : ", "); f_enum << (*c_iter)->get_name() << endl; firstValue = false; } indent_down(); indent(f_enum) << "]);" << endl; indent(f_enum) << "static final Map VALUES_TO_NAMES = {" << endl; indent_up(); firstValue = true; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { indent(f_enum) << (firstValue ? "" : ", "); f_enum << (*c_iter)->get_name() << ": '" << (*c_iter)->get_name() << "'" << endl; firstValue = false; } indent_down(); indent(f_enum) << "};" << endl; scope_down(f_enum); // end class f_enum.close(); } /** * Generates a class that holds all the constants. */ void t_dart_generator::generate_consts(std::vector consts) { if (consts.empty()) { return; } string class_name = get_constants_class_name(program_name_); string file_name = get_file_name(class_name); string f_consts_name = src_dir_ + "/" + file_name + ".dart"; ofstream_with_content_based_conditional_update f_consts; f_consts.open(f_consts_name.c_str()); // Print header f_consts << autogen_comment() << dart_library(file_name) << endl; f_consts << dart_thrift_imports() << endl; export_class_to_library(file_name, class_name); indent(f_consts) << "class " << class_name; scope_up(f_consts); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false); f_consts << endl; } scope_down(f_consts); f_consts.close(); } void t_dart_generator::print_const_value(std::ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) { type = get_true_type(type); indent(out); if (!defval) { out << (in_static ? "var " : "static final "); } if (type->is_base_type()) { if (!defval) { out << type_name(type) << " "; } string v2 = render_const_value(out, name, type, value); out << name; out << " = " << v2 << ";" << endl << endl; } else if (type->is_enum()) { if (!defval) { out << type_name(type) << " "; } out << name; out << " = " << value->get_integer() << ";" << endl << endl; } else if (type->is_struct() || type->is_xception()) { const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; out << type_name(type) << " " << name << " = new " << type_name(type) << "()"; indent_up(); for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string val = render_const_value(out, name, field_type, v_iter->second); out << endl; indent(out) << ".." << v_iter->first->get_string() << " = " << val; } indent_down(); out << ";" << endl; } else if (type->is_map()) { if (!defval) { out << type_name(type) << " "; } out << name << " ="; scope_up(out); t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(out, name, ktype, v_iter->first); string val = render_const_value(out, name, vtype, v_iter->second); indent(out) << key << ": " << val << "," << endl; } scope_down(out, ";" + endl); out << endl; } else if (type->is_list() || type->is_set()) { if (!defval) { out << type_name(type) << " "; } out << name << " = "; t_type* etype; if (type->is_list()) { out << "[" << endl; etype = ((t_list*)type)->get_elem_type(); } else { out << "new " << type_name(type) << ".from([" << endl; etype = ((t_set*)type)->get_elem_type(); } const vector& val = value->get_list(); vector::const_iterator v_iter; indent_up(); for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(out, name, etype, *v_iter); indent(out) << val << "," << endl; } indent_down(); if (type->is_list()) { indent(out) << "];" << endl; } else { indent(out) << "]);" << endl; } } else { throw "compiler error: no const of type " + type->get_name(); } } string t_dart_generator::render_const_value(ostream& out, string name, t_type* type, t_const_value* value) { (void)name; type = get_true_type(type); std::ostringstream render; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: render << "'" << get_escaped_string(value) << "'"; break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: render << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << value->get_integer(); } else { render << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { render << value->get_integer(); } else { string t = tmp("tmp"); print_const_value(out, t, type, value, true); out << endl; render << t; } return render.str(); } /** * Generates a struct definition for a thrift data type. This is a class * with data members, read(), write(), and an inner Isset class. * * @param tstruct The struct definition */ void t_dart_generator::generate_struct(t_struct* tstruct) { generate_dart_struct(tstruct, false); } /** * Exceptions are structs, but they inherit from Exception * * @param tstruct The struct definition */ void t_dart_generator::generate_xception(t_struct* txception) { generate_dart_struct(txception, true); } /** * Dart struct definition. * * @param tstruct The struct definition */ void t_dart_generator::generate_dart_struct(t_struct* tstruct, bool is_exception) { string file_name = get_file_name(tstruct->get_name()); string f_struct_name = src_dir_ + "/" + file_name + ".dart"; ofstream_with_content_based_conditional_update f_struct; f_struct.open(f_struct_name.c_str()); f_struct << autogen_comment() << dart_library(file_name) << endl; string imports; f_struct << dart_thrift_imports() << endl; generate_dart_struct_definition(f_struct, tstruct, is_exception, false, file_name); f_struct.close(); } /** * Dart struct definition. This has various parameters, as it could be * generated standalone or inside another class as a helper. If it * is a helper than it is a static class. * * @param tstruct The struct definition * @param is_exception Is this an exception? * @param in_class If inside a class, needs to be static class * @param is_result If this is a result it needs a different writer */ void t_dart_generator::generate_dart_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool is_result, string export_file_name) { generate_dart_doc(out, tstruct); string class_name = tstruct->get_name(); if (!export_file_name.empty()) { export_class_to_library(export_file_name, class_name); } indent(out) << "class " << class_name << " "; out << "implements TBase"; if (is_exception) { out << ", Exception "; } scope_up(out); indent(out) << "static final TStruct _STRUCT_DESC = new TStruct(\"" << class_name << "\");" << endl; // Members are public for -dart, private for -dartbean const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "static final TField _" << constant_name((*m_iter)->get_name()) << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << ");" << endl; } out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_dart_doc(out, *m_iter); indent(out) << type_name((*m_iter)->get_type()) + " _" << get_member_name((*m_iter)->get_name()) << init_value(*m_iter) << ";" << endl; indent(out) << "static const int " << upcase_string((*m_iter)->get_name()) << " = " << (*m_iter)->get_key() << ";" << endl; } out << endl; // Inner Isset class if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!type_can_be_null((*m_iter)->get_type())) { string field_name = get_member_name((*m_iter)->get_name()); indent(out) << "bool __isset_" << field_name << " = false;" << endl; } } } out << endl; // Default constructor indent(out) << tstruct->get_name() << "()"; scope_up(out); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr) { print_const_value(out, "this." + get_member_name((*m_iter)->get_name()), t, (*m_iter)->get_value(), true, true); } } scope_down(out); out << endl; generate_dart_bean_boilerplate(out, tstruct); generate_generic_field_getters(out, tstruct); generate_generic_field_setters(out, tstruct); generate_generic_isset_method(out, tstruct); generate_dart_struct_reader(out, tstruct); if (is_result) { generate_dart_struct_result_writer(out, tstruct); } else { generate_dart_struct_writer(out, tstruct); } generate_dart_struct_tostring(out, tstruct); generate_dart_validator(out, tstruct); scope_down(out); out << endl; } /** * Generates a function to read all the fields of the struct. * * @param tstruct The struct definition */ void t_dart_generator::generate_dart_struct_reader(ostream& out, t_struct* tstruct) { indent(out) << "read(TProtocol iprot)"; scope_up(out); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // Declare stack tmp variables and read struct header indent(out) << "TField field;" << endl; indent(out) << "iprot.readStructBegin();" << endl; // Loop over reading in fields indent(out) << "while (true)"; scope_up(out); // Read beginning field marker indent(out) << "field = iprot.readFieldBegin();" << endl; // Check for field STOP marker and break indent(out) << "if (field.type == TType.STOP)"; scope_up(out); indent(out) << "break;" << endl; scope_down(out); // Switch statement on the field we are reading indent(out) << "switch (field.id)"; scope_up(out); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << upcase_string((*f_iter)->get_name()) << ":" << endl; indent_up(); indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ")"; scope_up(out); generate_deserialize_field(out, *f_iter, "this."); generate_isset_set(out, *f_iter); scope_down(out, " else"); scope_up(out); indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl; scope_down(out); indent(out) << "break;" << endl; indent_down(); } // In the default case we skip the field indent(out) << "default:" << endl; indent_up(); indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl; indent(out) << "break;" << endl; indent_down(); scope_down(out); // Read field end marker indent(out) << "iprot.readFieldEnd();" << endl; scope_down(out); indent(out) << "iprot.readStructEnd();" << endl2; // in non-beans style, check for required fields of primitive type // (which can be checked here but not in the general validate method) indent(out) << "// check for required fields of primitive type, which can't be " "checked in the validate method" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { string field_name = get_member_name((*f_iter)->get_name()); indent(out) << "if (!__isset_" << field_name << ")"; scope_up(out); indent(out) << " throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '" << field_name << "' was not found in serialized data! Struct: \" + toString());" << endl; scope_down(out, endl2); } } // performs various checks (e.g. check that all required fields are set) indent(out) << "validate();" << endl; scope_down(out, endl2); } // generates dart method to perform various checks // (e.g. check that all required fields are set) void t_dart_generator::generate_dart_validator(ostream& out, t_struct* tstruct) { indent(out) << "validate()"; scope_up(out); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; indent(out) << "// check for required fields" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { string field_name = get_member_name((*f_iter)->get_name()); if (type_can_be_null((*f_iter)->get_type())) { indent(out) << "if (" << field_name << " == null)"; scope_up(out); indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '" << field_name << "' was not present! Struct: \" + toString());" << endl; scope_down(out); } else { indent(out) << "// alas, we cannot check '" << field_name << "' because it's a primitive and you chose the non-beans generator." << endl; } } } // check that fields of type enum have valid values indent(out) << "// check that fields of type enum have valid values" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = (*f_iter); t_type* type = field->get_type(); // if field is an enum, check that its value is valid if (type->is_enum()) { string field_name = get_member_name(field->get_name()); indent(out) << "if (" << generate_isset_check(field) << " && !" << get_ttype_class_name(type) << ".VALID_VALUES.contains(" << field_name << "))"; scope_up(out); indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"The field '" << field_name << "' has been assigned the invalid value " << "$" << field_name << "\");" << endl; scope_down(out); } } scope_down(out, endl2); } /** * Generates a function to write all the fields of the struct * * @param tstruct The struct definition */ void t_dart_generator::generate_dart_struct_writer(ostream& out, t_struct* tstruct) { out << indent() << "write(TProtocol oprot)"; scope_up(out); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; // performs various checks (e.g. check that all required fields are set) indent(out) << "validate();" << endl2; indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { string field_name = get_member_name((*f_iter)->get_name()); bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; if (could_be_unset) { indent(out) << "if (" << generate_isset_check(*f_iter) << ")"; scope_up(out); } bool null_allowed = type_can_be_null((*f_iter)->get_type()); if (null_allowed) { indent(out) << "if (this." << field_name << " != null)"; scope_up(out); } indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this."); // Write field closer indent(out) << "oprot.writeFieldEnd();" << endl; if (null_allowed) { scope_down(out); } if (could_be_unset) { scope_down(out); } } // Write the struct map indent(out) << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" << endl; scope_down(out, endl2); } /** * Generates a function to write all the fields of the struct, * which is a function result. These fields are only written * if they are set in the Isset array, and only one of them * can be set at a time. * * @param tstruct The struct definition */ void t_dart_generator::generate_dart_struct_result_writer(ostream& out, t_struct* tstruct) { indent(out) << "write(TProtocol oprot)"; scope_up(out); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl2; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; indent(out) << "if "; } else { out << " else if "; } out << "(this." << generate_isset_check(*f_iter) << ")"; scope_up(out); indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this."); // Write field closer indent(out) << "oprot.writeFieldEnd();" << endl; scope_down(out, ""); } out << endl; // Write the struct map indent(out) << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" << endl; scope_down(out, endl2); } void t_dart_generator::generate_generic_field_getters(std::ostream& out, t_struct* tstruct) { // create the getter indent(out) << "getFieldValue(int fieldID)"; scope_up(out); indent(out) << "switch (fieldID)"; scope_up(out); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; std::string field_name = get_member_name(field->get_name()); indent(out) << "case " << upcase_string(field_name) << ":" << endl; indent_up(); indent(out) << "return this." << field_name << ";" << endl; indent_down(); } indent(out) << "default:" << endl; indent_up(); indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl; indent_down(); scope_down(out); // switch scope_down(out, endl2); // method } void t_dart_generator::generate_generic_field_setters(std::ostream& out, t_struct* tstruct) { // create the setter indent(out) << "setFieldValue(int fieldID, Object value)"; scope_up(out); indent(out) << "switch (fieldID)"; scope_up(out); // build up the bodies of both the getter and setter at once const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; std::string field_name = get_member_name(field->get_name()); indent(out) << "case " << upcase_string(field_name) << ":" << endl; indent_up(); indent(out) << "if (value == null)"; scope_up(out); indent(out) << "unset" << get_cap_name(field_name) << "();" << endl; scope_down(out, " else"); scope_up(out); indent(out) << "this." << field_name << " = value;" << endl; scope_down(out); indent(out) << "break;" << endl; indent_down(); out << endl; } indent(out) << "default:" << endl; indent_up(); indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl; indent_down(); scope_down(out); // switch scope_down(out, endl2); // method } // Creates a generic isSet method that takes the field number as argument void t_dart_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // create the isSet method indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a " "value) and false otherwise" << endl; indent(out) << "bool isSet(int fieldID)"; scope_up(out); indent(out) << "switch (fieldID)"; scope_up(out); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl; indent_up(); indent(out) << "return " << generate_isset_check(field) << ";" << endl; indent_down(); } indent(out) << "default:" << endl; indent_up(); indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl; indent_down(); scope_down(out); // switch scope_down(out, endl2); // method } /** * Generates a set of Dart Bean boilerplate functions (setters, getters, etc.) * for the given struct. * * @param tstruct The struct definition */ void t_dart_generator::generate_dart_bean_boilerplate(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; t_type* type = get_true_type(field->get_type()); std::string field_name = get_member_name(field->get_name()); std::string cap_name = get_cap_name(field_name); indent(out) << "// " << field_name << endl; // Simple getter generate_dart_doc(out, field); indent(out) << type_name(type) << " get " << field_name << " => this._" << field_name << ";" << endl2; // Simple setter generate_dart_doc(out, field); indent(out) << "set " << field_name << "(" << type_name(type) << " " << field_name << ")"; scope_up(out); indent(out) << "this._" << field_name << " = " << field_name << ";" << endl; generate_isset_set(out, field); scope_down(out, endl2); // isSet method indent(out) << "bool is" << get_cap_name("set") << cap_name << "()"; if (type_can_be_null(type)) { out << " => this." << field_name << " != null;" << endl2; } else { out << " => this.__isset_" << field_name << ";" << endl2; } // Unsetter indent(out) << "unset" << cap_name << "()"; scope_up(out); if (type_can_be_null(type)) { indent(out) << "this." << field_name << " = null;" << endl; } else { indent(out) << "this.__isset_" << field_name << " = false;" << endl; } scope_down(out, endl2); } } /** * Generates a toString() method for the given struct * * @param tstruct The struct definition */ void t_dart_generator::generate_dart_struct_tostring(ostream& out, t_struct* tstruct) { indent(out) << "String toString()"; scope_up(out); indent(out) << "StringBuffer ret = new StringBuffer(\"" << tstruct->get_name() << "(\");" << endl2; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; if (could_be_unset) { indent(out) << "if (" << generate_isset_check(*f_iter) << ")"; scope_up(out); } t_field* field = (*f_iter); std::string field_name = get_member_name(field->get_name()); if (!first) { indent(out) << "ret.write(\", \");" << endl; } indent(out) << "ret.write(\"" << field_name << ":\");" << endl; bool can_be_null = type_can_be_null(field->get_type()); if (can_be_null) { indent(out) << "if (this." << field_name << " == null)"; scope_up(out); indent(out) << "ret.write(\"null\");" << endl; scope_down(out, " else"); scope_up(out); } if (field->get_type()->is_binary()) { indent(out) << "ret.write(\"BINARY\");" << endl; } else if (field->get_type()->is_enum()) { indent(out) << "String " << field_name << "_name = " << get_ttype_class_name(field->get_type()) << ".VALUES_TO_NAMES[this." << field_name << "];" << endl; indent(out) << "if (" << field_name << "_name != null)"; scope_up(out); indent(out) << "ret.write(" << field_name << "_name);" << endl; indent(out) << "ret.write(\" (\");" << endl; scope_down(out); indent(out) << "ret.write(this." << field_name << ");" << endl; indent(out) << "if (" << field_name << "_name != null)"; scope_up(out); indent(out) << "ret.write(\")\");" << endl; scope_down(out); } else { indent(out) << "ret.write(this." << field_name << ");" << endl; } if (can_be_null) { scope_down(out); } if (could_be_unset) { scope_down(out); } out << endl; first = false; } indent(out) << "ret.write(\")\");" << endl2; indent(out) << "return ret.toString();" << endl; scope_down(out, endl2); } /** * Returns a string with the dart representation of the given thrift type * (e.g. for the type struct it returns "TType.STRUCT") */ std::string t_dart_generator::get_dart_type_string(t_type* type) { if (type->is_list()) { return "TType.LIST"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_typedef()) { return get_dart_type_string(((t_typedef*)type)->get_type()); } else if (type->is_base_type()) { switch (((t_base_type*)type)->get_base()) { case t_base_type::TYPE_VOID: return "TType.VOID"; break; case t_base_type::TYPE_STRING: return "TType.STRING"; break; case t_base_type::TYPE_BOOL: return "TType.BOOL"; break; case t_base_type::TYPE_I8: return "TType.BYTE"; break; case t_base_type::TYPE_I16: return "TType.I16"; break; case t_base_type::TYPE_I32: return "TType.I32"; break; case t_base_type::TYPE_I64: return "TType.I64"; break; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; break; default: throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_dart_generator::get_dart_type_string!"); break; // This should never happen! } } else { throw std::runtime_error( "Unknown thrift type \"" + type->get_name() + "\" passed to t_dart_generator::get_dart_type_string!"); // This should never happen! } } void t_dart_generator::generate_service(t_service* tservice) { string file_name = get_file_name(service_name_); string f_service_name = src_dir_ + "/" + file_name + ".dart"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << dart_library(file_name) << endl; f_service_ << service_imports() << dart_thrift_imports() << endl; f_service_ << endl; generate_service_interface(tservice); generate_service_client(tservice); generate_service_server(tservice); generate_service_helpers(tservice); f_service_.close(); } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_dart_generator::generate_service_interface(t_service* tservice) { string extends_iface = ""; if (tservice->get_extends() != nullptr) { extends_iface = " extends " + get_ttype_class_name(tservice->get_extends()); } generate_dart_doc(f_service_, tservice); string class_name = service_name_; export_class_to_library(get_file_name(service_name_), class_name); indent(f_service_) << "abstract class " << class_name << extends_iface; scope_up(f_service_); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << endl; generate_dart_doc(f_service_, *f_iter); indent(f_service_) << function_signature(*f_iter) << ";" << endl; } scope_down(f_service_, endl2); } /** * Generates structs for all the service args and return types * * @param tservice The service */ void t_dart_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_dart_struct_definition(f_service_, ts, false, false); generate_function_helpers(*f_iter); } } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_dart_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = get_ttype_class_name(tservice->get_extends()); extends_client = " extends " + extends + "Client"; } string class_name = service_name_ + "Client"; export_class_to_library(get_file_name(service_name_), class_name); indent(f_service_) << "class " << class_name << extends_client << " implements " << service_name_; scope_up(f_service_); f_service_ << endl; indent(f_service_) << class_name << "(TProtocol iprot, [TProtocol oprot = null])"; if (!extends.empty()) { indent_up(); f_service_ << endl; indent(f_service_) << ": super(iprot, oprot);" << endl; indent_down(); } else { scope_up(f_service_); indent(f_service_) << "_iprot = iprot;" << endl; indent(f_service_) << "_oprot = (oprot == null) ? iprot : oprot;" << endl; scope_down(f_service_); } f_service_ << endl; if (extends.empty()) { indent(f_service_) << "TProtocol _iprot;" << endl2; indent(f_service_) << "TProtocol get iprot => _iprot;" << endl2; indent(f_service_) << "TProtocol _oprot;" << endl2; indent(f_service_) << "TProtocol get oprot => _oprot;" << endl2; indent(f_service_) << "int _seqid = 0;" << endl2; indent(f_service_) << "int get seqid => _seqid;" << endl2; indent(f_service_) << "int nextSeqid() => ++_seqid;" << endl2; } // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { // Open function indent(f_service_) << function_signature(*f_iter) << " async"; scope_up(f_service_); // Get the struct of function call params t_struct* arg_struct = (*f_iter)->get_arglist(); string argsname = get_args_class_name((*f_iter)->get_name()); vector::const_iterator fld_iter; const vector& fields = arg_struct->get_members(); // Serialize the request indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << (*f_iter)->get_name() << "\", " << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") << ", nextSeqid()));" << endl; indent(f_service_) << argsname << " args = new " << argsname << "();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { string arg_field_name = get_member_name((*fld_iter)->get_name()); indent(f_service_) << "args." << arg_field_name << " = " << arg_field_name << ";" << endl; } indent(f_service_) << "args.write(oprot);" << endl; indent(f_service_) << "oprot.writeMessageEnd();" << endl2; indent(f_service_) << "await oprot.transport.flush();" << endl2; if (!(*f_iter)->is_oneway()) { indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl; indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION)"; scope_up(f_service_); indent(f_service_) << "TApplicationError error = TApplicationError.read(iprot);" << endl; indent(f_service_) << "iprot.readMessageEnd();" << endl; indent(f_service_) << "throw error;" << endl; scope_down(f_service_, endl2); string result_class = get_result_class_name((*f_iter)->get_name()); indent(f_service_) << result_class << " result = new " << result_class << "();" << endl; indent(f_service_) << "result.read(iprot);" << endl; indent(f_service_) << "iprot.readMessageEnd();" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "if (result." << generate_isset_check("success") << ")"; scope_up(f_service_); indent(f_service_) << "return result.success;" << endl; scope_down(f_service_, endl2); } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { string result_field_name = get_member_name((*x_iter)->get_name()); indent(f_service_) << "if (result." << result_field_name << " != null)"; scope_up(f_service_); indent(f_service_) << "throw result." << result_field_name << ";" << endl; scope_down(f_service_); } // If you get here it's an exception, unless a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "return;" << endl; } else { indent(f_service_) << "throw new TApplicationError(TApplicationErrorType.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; } } scope_down(f_service_, endl2); } scope_down(f_service_, endl2); } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_dart_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; // typedef indent(f_service_) << "typedef void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" << endl2; // Extends stuff string extends = ""; string extends_processor = ""; if (tservice->get_extends() != nullptr) { extends = get_ttype_class_name(tservice->get_extends()); extends_processor = " extends " + extends + "Processor"; } // Generate the header portion string class_name = service_name_ + "Processor"; export_class_to_library(get_file_name(service_name_), class_name); indent(f_service_) << "class " << class_name << extends_processor << " implements TProcessor"; scope_up(f_service_); indent(f_service_) << class_name << "(" << service_name_ << " iface)"; if (!extends.empty()) { indent_up(); f_service_ << endl; indent(f_service_) << ": super(iface)"; indent_down(); } scope_up(f_service_); if (extends.empty()) { indent(f_service_) << "iface_ = iface;" << endl; } for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_service_) << "PROCESS_MAP[\"" << (*f_iter)->get_name() << "\"] = " << get_member_name((*f_iter)->get_name()) << ";" << endl; } scope_down(f_service_, endl2); indent(f_service_) << service_name_ << " iface_;" << endl; if (extends.empty()) { indent(f_service_) << "final Map PROCESS_MAP = {};" << endl; } f_service_ << endl; // Generate the server implementation indent(f_service_) << "bool process(TProtocol iprot, TProtocol oprot)"; scope_up(f_service_); indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl; indent(f_service_) << "ProcessFunction fn = PROCESS_MAP[msg.name];" << endl; indent(f_service_) << "if (fn == null)"; scope_up(f_service_); indent(f_service_) << "TProtocolUtil.skip(iprot, TType.STRUCT);" << endl; indent(f_service_) << "iprot.readMessageEnd();" << endl; indent(f_service_) << "TApplicationError x = new TApplicationError(TApplicationErrorType.UNKNOWN_METHOD, " "\"Invalid method name: '\"+msg.name+\"'\");" << endl; indent(f_service_) << "oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl; indent(f_service_) << "x.write(oprot);" << endl; indent(f_service_) << "oprot.writeMessageEnd();" << endl; indent(f_service_) << "oprot.transport.flush();" << endl; indent(f_service_) << "return true;" << endl; scope_down(f_service_); indent(f_service_) << "fn(msg.seqid, iprot, oprot);" << endl; indent(f_service_) << "return true;" << endl; scope_down(f_service_, endl2); // process function // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } scope_down(f_service_, endl2); // class } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_dart_generator::generate_function_helpers(t_function* tfunction) { if (tfunction->is_oneway()) { return; } t_struct result(program_, get_result_class_name(tfunction->get_name())); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_dart_struct_definition(f_service_, &result, false, true); } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_dart_generator::generate_process_function(t_service* tservice, t_function* tfunction) { (void)tservice; bool await_result = (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()); indent(f_service_) << get_member_name(tfunction->get_name()) << "(int seqid, TProtocol iprot, TProtocol oprot)"; if (await_result) { f_service_ << " async"; } scope_up(f_service_); string argsname = get_args_class_name(tfunction->get_name()); string resultname = get_result_class_name(tfunction->get_name()); indent(f_service_) << argsname << " args = new " << argsname << "();" << endl; indent(f_service_) << "args.read(iprot);" << endl; indent(f_service_) << "iprot.readMessageEnd();" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; if (!tfunction->is_oneway()) { indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; } if (!tfunction->is_oneway() && xceptions.size() > 0) { indent(f_service_) << "try"; scope_up(f_service_); } // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent(); if (await_result) { f_service_ << "result.success = await "; } f_service_ << "iface_." << get_member_name(tfunction->get_name()) << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << get_member_name((*f_iter)->get_name()); } f_service_ << ");" << endl; if (!tfunction->is_oneway() && xceptions.size() > 0) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { string result_field_name = get_member_name((*x_iter)->get_name()); scope_down(f_service_, ""); f_service_ << " on " << type_name((*x_iter)->get_type()) << " catch(" << result_field_name << ")"; scope_up(f_service_); if (!tfunction->is_oneway()) { indent(f_service_) << "result." << result_field_name << " = " << result_field_name << ";" << endl; } } scope_down(f_service_, " "); f_service_ << "catch (th)"; scope_up(f_service_); indent(f_service_) << "// Internal error" << endl; indent(f_service_) << "TApplicationError x = new " "TApplicationError(TApplicationErrorType.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl; indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl; indent(f_service_) << "x.write(oprot);" << endl; indent(f_service_) << "oprot.writeMessageEnd();" << endl; indent(f_service_) << "oprot.transport.flush();" << endl; indent(f_service_) << "return;" << endl; scope_down(f_service_); } if (tfunction->is_oneway()) { indent(f_service_) << "return;" << endl; } else { indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl; indent(f_service_) << "result.write(oprot);" << endl; indent(f_service_) << "oprot.writeMessageEnd();" << endl; indent(f_service_) << "oprot.transport.flush();" << endl; } scope_down(f_service_, endl2); } /** * Deserializes a field of any type. * * @param tfield The field * @param prefix The variable name or container for this field */ void t_dart_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); string field_name = get_member_name(tfield->get_name()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + field_name; } string name = prefix + field_name; if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << name << " = iprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "readBinary();"; } else { out << "readString();"; } break; case t_base_type::TYPE_BOOL: out << "readBool();"; break; case t_base_type::TYPE_I8: out << "readByte();"; break; case t_base_type::TYPE_I16: out << "readI16();"; break; case t_base_type::TYPE_I32: out << "readI32();"; break; case t_base_type::TYPE_I64: out << "readI64();"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble();"; break; default: throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "readI32();"; } out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", field_name.c_str(), type_name(type).c_str()); } } /** * Generates an unserializer for a struct, invokes read() */ void t_dart_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl; indent(out) << prefix << ".read(iprot);" << endl; } /** * Deserializes a container by reading its size and then iterating */ void t_dart_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { indent(out); scope_up(out, ""); string obj; if (ttype->is_map()) { obj = tmp("_map"); } else if (ttype->is_set()) { obj = tmp("_set"); } else if (ttype->is_list()) { obj = tmp("_list"); } // Declare variables, read header if (ttype->is_map()) { indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl; } else if (ttype->is_set()) { indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl; } else if (ttype->is_list()) { indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl; } indent(out) << prefix << " = new " << type_name(ttype) << "();" << endl; // For loop iterates over elements string i = tmp("_i"); indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".length" << "; " << "++" << i << ")"; scope_up(out); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } scope_down(out); // Read container end if (ttype->is_map()) { indent(out) << "iprot.readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "iprot.readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "iprot.readListEnd();" << endl; } scope_down(out); } /** * Generates code to deserialize a map */ void t_dart_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); indent(out) << declare_field(&fkey) << endl; indent(out) << declare_field(&fval) << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); indent(out) << prefix << "[" << key << "] = " << val << ";" << endl; } /** * Deserializes a set element */ void t_dart_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".add(" << elem << ");" << endl; } /** * Deserializes a list element */ void t_dart_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".add(" << elem << ");" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_dart_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); string field_name = get_member_name(tfield->get_name()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + field_name; } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + field_name); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + field_name); } else if (type->is_base_type() || type->is_enum()) { string name = prefix + field_name; indent(out) << "oprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "writeBinary(" << name << ");"; } else { out << "writeString(" << name << ");"; } break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ");"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ");"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ");"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ");"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ");"; break; default: throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32(" << name << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), field_name.c_str(), type_name(type).c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_dart_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; indent(out) << prefix << ".write(oprot);" << endl; } /** * Serializes a container by writing its size then the elements. * * @param ttype The type of container * @param prefix String prefix for fields */ void t_dart_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { indent(out); scope_up(out, ""); if (ttype->is_map()) { string iter = tmp("_key"); indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".length));" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix << ".length));" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListBegin(new TList(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));" << endl; } string iter = tmp("elem"); if (ttype->is_map()) { indent(out) << "for (var " << iter << " in " << prefix << ".keys)"; } else if (ttype->is_set() || ttype->is_list()) { indent(out) << "for (var " << iter << " in " << prefix << ")"; } scope_up(out); if (ttype->is_map()) { generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); } else if (ttype->is_set()) { generate_serialize_set_element(out, (t_set*)ttype, iter); } else if (ttype->is_list()) { generate_serialize_list_element(out, (t_list*)ttype, iter); } scope_down(out); if (ttype->is_map()) { indent(out) << "oprot.writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListEnd();" << endl; } scope_down(out); } /** * Serializes the members of a map. */ void t_dart_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map) { t_field kfield(tmap->get_key_type(), iter); generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); generate_serialize_field(out, &vfield, ""); } /** * Serializes the members of a set. */ void t_dart_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Serializes the members of a list. */ void t_dart_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Returns a Dart type name * * @param ttype The type * @return Dart type name, i.e. Map */ string t_dart_generator::type_name(t_type* ttype) { ttype = get_true_type(ttype); if (ttype->is_base_type()) { return base_type_name((t_base_type*)ttype); } else if (ttype->is_enum()) { return "int"; } else if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; return "Map<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type()) + ">"; } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; return "Set<" + type_name(tset->get_elem_type()) + ">"; } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; return "List<" + type_name(tlist->get_elem_type()) + ">"; } return get_ttype_class_name(ttype); } /** * Returns the Dart type that corresponds to the thrift type. * * @param tbase The base type */ string t_dart_generator::base_type_name(t_base_type* type) { t_base_type::t_base tbase = type->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: if (type->is_binary()) { return "Uint8List"; } else { return "String"; } case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: return "int"; case t_base_type::TYPE_DOUBLE: return "double"; default: throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase); } } /** * Declares a field, which may include initialization as necessary. * * @param ttype The type */ string t_dart_generator::declare_field(t_field* tfield, bool init) { string field_name = get_member_name(tfield->get_name()); string result = type_name(tfield->get_type()) + " " + field_name; if (init) { t_type* ttype = get_true_type(tfield->get_type()); if (ttype->is_base_type() && tfield->get_value() != nullptr) { std:: ofstream dummy; result += " = " + render_const_value(dummy, field_name, ttype, tfield->get_value()); } else if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: result += " = null"; break; case t_base_type::TYPE_BOOL: result += " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = 0.0"; break; } } else if (ttype->is_enum()) { result += " = 0"; } else if (ttype->is_container()) { result += " = new " + type_name(ttype) + "()"; } else { result += " = new " + type_name(ttype) + "()"; ; } } return result + ";"; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_dart_generator::function_signature(t_function* tfunction) { std::string arguments = argument_list(tfunction->get_arglist()); std::string returntype; if (tfunction->get_returntype()->is_void()) { returntype = "Future"; } else { returntype = "Future<" + type_name(tfunction->get_returntype()) + ">"; } std::string result = returntype + " " + get_member_name(tfunction->get_name()) + "(" + arguments + ")"; return result; } /** * Renders a comma separated field list, with type names */ string t_dart_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } string field_name = get_member_name((*f_iter)->get_name()); result += type_name((*f_iter)->get_type()) + " " + field_name; } return result; } /** * Converts the parse type to a C++ enum string for the given type. */ string t_dart_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.STRING"; case t_base_type::TYPE_BOOL: return "TType.BOOL"; case t_base_type::TYPE_I8: return "TType.BYTE"; case t_base_type::TYPE_I16: return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; } } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_list()) { return "TType.LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } std::string t_dart_generator::init_value(t_field* field) { // Do not initialize optional fields if (field->get_req() == t_field::T_OPTIONAL) { return ""; } t_type* ttype = field->get_type(); // Get the actual type for a typedef if (ttype->is_typedef()) { ttype = ((t_typedef*)ttype)->get_type(); } // Only consider base types for default initialization if (!ttype->is_base_type()) { return ""; } t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); // Initialize bools, ints, and doubles with sane defaults string result; switch (tbase) { case t_base_type::TYPE_BOOL: result = " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result = " = 0"; break; case t_base_type::TYPE_DOUBLE: result = " = 0.0"; break; case t_base_type::TYPE_VOID: case t_base_type::TYPE_STRING: result = ""; break; } return result; } std::string t_dart_generator::get_cap_name(std::string name) { name[0] = toupper(name[0]); return name; } std::string t_dart_generator::get_member_name(std::string name) { name[0] = tolower(name[0]); return name; } std::string t_dart_generator::get_args_class_name(std::string name) { return name + "_args"; } std::string t_dart_generator::get_result_class_name(std::string name) { return name + "_result"; } std::string t_dart_generator::get_file_name(std::string name) { // e.g. change APIForFileIO to api_for_file_io string ret; const char* tmp = name.c_str(); bool is_prev_lc = true; bool is_current_lc = tmp[0] == tolower(tmp[0]); bool is_next_lc = false; for (unsigned int i = 0; i < name.length(); i++) { char lc = tolower(tmp[i]); if (i == name.length() - 1) { is_next_lc = false; } else { is_next_lc = (tmp[i+1] == tolower(tmp[i+1])); } if (i != 0 && !is_current_lc && (is_prev_lc || is_next_lc)) { ret += "_"; } ret += lc; is_prev_lc = is_current_lc; is_current_lc = is_next_lc; } return ret; } std::string t_dart_generator::get_constants_class_name(std::string name) { // e.g. change my_great_model to MyGreatModelConstants string ret; const char* tmp = name.c_str(); bool is_prev_underscore = true; for (unsigned int i = 0; i < name.length(); i++) { if (tmp[i] == '_') { is_prev_underscore = true; } else { if (is_prev_underscore) { ret += toupper(tmp[i]); } else { ret += tmp[i]; } is_prev_underscore = false; } } return ret + "Constants"; } string t_dart_generator::constant_name(string name) { string constant_name; bool is_first = true; bool was_previous_char_upper = false; for (char character : name) { bool is_upper = isupper(character); if (is_upper && !is_first && !was_previous_char_upper) { constant_name += '_'; } constant_name += toupper(character); is_first = false; was_previous_char_upper = is_upper; } return constant_name; } /** * Emits a doc comment if the provided object has a doc in Thrift */ void t_dart_generator::generate_dart_doc(ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_docstring_comment(out, "", "/// ", tdoc->get_doc(), ""); } } /** * Emits a doc comment if the provided function object has a doc in Thrift */ void t_dart_generator::generate_dart_doc(ostream& out, t_function* tfunction) { if (tfunction->has_doc()) { stringstream ss; ss << tfunction->get_doc(); const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; string field_name = get_member_name(p->get_name()); ss << "\n@param " << field_name; if (p->has_doc()) { ss << " " << p->get_doc(); } } generate_docstring_comment(out, "", "/// ", ss.str(), ""); } } std::string t_dart_generator::generate_isset_check(t_field* field) { string field_name = get_member_name(field->get_name()); return generate_isset_check(field_name); } std::string t_dart_generator::generate_isset_check(std::string field_name) { return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; } void t_dart_generator::generate_isset_set(ostream& out, t_field* field) { if (!type_can_be_null(field->get_type())) { string field_name = get_member_name(field->get_name()); indent(out) << "this.__isset_" << field_name << " = true;" << endl; } } std::string t_dart_generator::get_ttype_class_name(t_type* ttype) { if (program_ == ttype->get_program()) { return ttype->get_name(); } else { string named_import = "t_" + find_library_name(ttype->get_program()); return named_import + "." + ttype->get_name(); } } THRIFT_REGISTER_GENERATOR( dart, "Dart", " library_name: Optional override for library name.\n" " library_prefix: Generate code that can be used within an existing library.\n" " Use a dot-separated string, e.g. \"my_parent_lib.src.gen\"\n" " pubspec_lib: Optional override for thrift lib dependency in pubspec.yaml,\n" " e.g. \"thrift: 0.x.x\". Use a pipe delimiter to separate lines,\n" " e.g. \"thrift:| git:| url: git@foo.com\"\n" ) thrift-0.16.0/compiler/cpp/src/thrift/generate/t_delphi_generator.cc000066400000000000000000004563241420101504100255220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" #ifdef _WIN32 #include #include #include #include #endif using std::map; using std::ofstream; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes class t_delphi_generator : public t_oop_generator { public: t_delphi_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; indent_impl_ = 0; has_forward = false; has_enum = false; has_const = false; std::map::const_iterator iter; ansistr_binary_ = false; register_types_ = false; constprefix_ = false; events_ = false; xmldoc_ = false; async_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("ansistr_binary") == 0) { ansistr_binary_ = true; } else if( iter->first.compare("register_types") == 0) { register_types_ = true; } else if( iter->first.compare("constprefix") == 0) { constprefix_ = true; } else if( iter->first.compare("events") == 0) { events_ = true; } else if( iter->first.compare("xmldoc") == 0) { xmldoc_ = true; } else if( iter->first.compare("async") == 0) { async_ = true; } else { throw "unknown option delphi:" + iter->first; } } out_dir_base_ = "gen-delphi"; escape_.clear(); escape_['\''] = "''"; } void init_generator() override; void close_generator() override; void generate_consts(std::vector consts) override; void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_forward_declaration(t_struct* tstruct) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void generate_property(ostream& out, t_field* tfield, bool isPublic, bool is_xception); void generate_property_writer_(ostream& out, t_field* tfield, bool isPublic); void generate_delphi_property(ostream& out, bool struct_is_exception, t_field* tfield, bool isPublic, std::string fieldPrefix = ""); void generate_delphi_isset_reader_writer_definition(ostream& out, t_field* tfield, bool is_xception); void generate_delphi_property_reader_definition(ostream& out, t_field* tfield, bool is_xception_class); void generate_delphi_property_writer_definition(ostream& out, t_field* tfield, bool is_xception_class); void generate_delphi_property_reader_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class); void generate_delphi_property_writer_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factory_name); void generate_delphi_clear_union_value(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factory_name); void generate_delphi_isset_reader_writer_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception); void generate_delphi_struct_writer_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory); void generate_delphi_struct_result_writer_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory); void generate_delphi_struct_tostring_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory); void add_delphi_uses_list(string unitname); void generate_delphi_struct_reader_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory); void generate_delphi_create_exception_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception); bool const_needs_var(t_type* type); void print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value); void print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value); void print_const_value(std::ostream& vars, std::ostream& out, std::string name, t_type* type, t_const_value* value); void initialize_field(std::ostream& vars, std::ostream& out, std::string name, t_type* type, t_const_value* value); void finalize_field(std::ostream& out, std::string name, t_type* type, t_const_value* value, std::string cls_nm = ""); std::string render_const_value(std::ostream& local_vars, std::ostream& out, std::string name, t_type* type, t_const_value* value); void print_const_def_value(std::ostream& vars, std::ostream& out, std::string name, t_type* type, t_const_value* value, std::string cls_nm = ""); std::string make_constants_classname(); void generate_delphi_struct(t_struct* tstruct, bool is_exception); void generate_delphi_struct_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false); void print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct); void generate_delphi_struct_type_factory(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false); void generate_delphi_struct_type_factory_registration(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false); void generate_delphi_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool in_class = false, bool is_result = false, bool is_x_factory = false); void generate_delphi_struct_reader(std::ostream& out, t_struct* tstruct); void generate_delphi_struct_result_writer(std::ostream& out, t_struct* tstruct); void generate_delphi_struct_writer(std::ostream& out, t_struct* tstruct); void generate_delphi_struct_tostring(std::ostream& out, t_struct* tstruct); void generate_function_helpers(t_function* tfunction); void generate_service_interface(t_service* tservice); void generate_service_interface(t_service* tservice, bool for_async); void generate_guid(std::ostream& out); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* function); void generate_deserialize_field(std::ostream& out, bool is_xception, t_field* tfield, std::string prefix, std::ostream& local_vars); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string name, std::string prefix); void generate_deserialize_container(ostream& out, bool is_xception, t_type* ttype, string name, std::ostream& local_vars); void generate_deserialize_set_element(std::ostream& out, bool is_xception, t_set* tset, std::string prefix, std::ostream& local_vars); void generate_deserialize_map_element(std::ostream& out, bool is_xception, t_map* tmap, std::string prefix, std::ostream& local_vars); void generate_deserialize_list_element(std::ostream& out, bool is_xception, t_list* list, std::string prefix, std::ostream& local_vars); void generate_serialize_field(std::ostream& out, bool is_xception, t_field* tfield, std::string prefix, std::ostream& local_vars); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix, std::ostream& local_vars); void generate_serialize_container(std::ostream& out, bool is_xception, t_type* ttype, std::string prefix, std::ostream& local_vars); void generate_serialize_map_element(std::ostream& out, bool is_xception, t_map* tmap, std::string iter, std::string map, std::ostream& local_vars); void generate_serialize_set_element(std::ostream& out, bool is_xception, t_set* tmap, std::string iter, std::ostream& local_vars); void generate_serialize_list_element(std::ostream& out, bool is_xception, t_list* tlist, std::string iter, std::ostream& local_vars); void delphi_type_usings(std::ostream& out); std::string delphi_thrift_usings(); std::string type_name(t_type* ttype, bool b_cls = false, bool b_no_postfix = false, bool b_exception_factory = false, bool b_full_exception_factory = false); std::string normalize_clsnm(std::string name, std::string prefix, bool b_no_check_keyword = false); std::string make_valid_delphi_identifier(std::string const& fromName); std::string make_pascal_string_literal( std::string value); std::string input_arg_prefix(t_type* ttype); std::string base_type_name(t_base_type* tbase); std::string declare_field(t_field* tfield, bool init = false, std::string prefix = "", bool is_xception_class = false); std::string function_signature(t_function* tfunction, bool for_async, std::string full_cls = "", bool is_xception = false); std::string argument_list(t_struct* tstruct); std::string constructor_argument_list(t_struct* tstruct, std::string current_indent); std::string type_to_enum(t_type* ttype); std::string prop_name(t_field* tfield, bool is_xception = false); std::string prop_name(std::string name, bool is_xception = false); std::string constructor_param_name(string name); void write_enum(std::string line); void write_forward_decr(std::string line); void write_const(std::string line); void write_struct(std::string line); void write_service(std::string line); std::string autogen_comment() override { return std::string("(**\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + " *)\n"; } string replace_all(string contents, string search, string replace); string xml_encode(string contents); string xmldoc_encode(string contents); string xmlattrib_encode(string contents); void generate_delphi_doc(std::ostream& out, t_field* field); void generate_delphi_doc(std::ostream& out, t_doc* tdoc); void generate_delphi_doc(std::ostream& out, t_function* tdoc); void generate_delphi_docstring_comment(std::ostream& out, string contents); bool type_can_be_null(t_type* ttype) { while (ttype->is_typedef()) { ttype = ((t_typedef*)ttype)->get_type(); } return ttype->is_container() || ttype->is_struct() || ttype->is_xception(); } private: std::string namespace_name_; std::ostringstream s_forward_decr; std::ostringstream s_enum; std::ostringstream s_const; std::ostringstream s_struct; std::ostringstream s_service; std::ostringstream s_const_impl; std::ostringstream s_struct_impl; std::ostringstream s_service_impl; std::ostringstream s_type_factory_registration; std::ostringstream s_type_factory_funcs; bool has_forward; bool has_enum; bool has_const; std::string namespace_dir_; std::map delphi_keywords; std::map delphi_reserved_method; std::map delphi_reserved_method_exception; std::map types_known; std::list typedefs_pending; std::vector uses_list; void create_keywords(); bool find_keyword(std::map& keyword_map, std::string name); std::string normalize_name(std::string name, bool b_method = false, bool b_exception_method = false); std::string empty_value(t_type* type); bool is_fully_defined_type(t_type* ttype); void add_defined_type(t_type* ttype); void init_known_types_list(); bool is_void(t_type* type); int indent_impl_; bool ansistr_binary_; bool register_types_; bool constprefix_; bool events_; bool xmldoc_; bool async_; void indent_up_impl() { ++indent_impl_; }; void indent_down_impl() { --indent_impl_; }; std::string indent_impl() { std::string ind = ""; int i; for (i = 0; i < indent_impl_; ++i) { ind += " "; } return ind; }; std::ostream& indent_impl(std::ostream& os) { return os << indent_impl(); }; }; string t_delphi_generator::replace_all(string contents, string search, string repl) { string str(contents); size_t slen = search.length(); size_t rlen = repl.length(); size_t incr = (rlen > 0) ? rlen : 1; if (slen > 0) { size_t found = str.find(search); while ((found != string::npos) && (found < str.length())) { str.replace(found, slen, repl); found = str.find(search, found + incr); } } return str; } // XML encoding string t_delphi_generator::xml_encode(string contents) { string str(contents); // escape the escape str = replace_all(str, "&", "&"); // other standard XML entities str = replace_all(str, "<", "<"); str = replace_all(str, ">", ">"); return str; } // XML attribute encoding string t_delphi_generator::xmlattrib_encode(string contents) { string str(xml_encode(contents)); // our attribs are enclosed in " str = replace_all(str, "\"", "\\\""); return str; } // XML encoding for doc comments string t_delphi_generator::xmldoc_encode(string contents) { string str(xml_encode(contents)); // XMLDoc specific: convert linebreaks into graphs str = replace_all(str, "\r\n", "\r"); str = replace_all(str, "\n", "\r"); str = replace_all(str, "\r", "\n"); return str; } void t_delphi_generator::generate_delphi_docstring_comment(ostream& out, string contents) { if (xmldoc_) { generate_docstring_comment(out, "{$REGION 'XMLDoc'}/// \n", "/// ", "" + contents + "", "/// \n{$ENDREGION}\n"); } } void t_delphi_generator::generate_delphi_doc(ostream& out, t_field* field) { if (xmldoc_) { if (field->get_type()->is_enum()) { string combined_message = xmldoc_encode(field->get_doc()) + "\nget_type())) + "\"/>"; generate_delphi_docstring_comment(out, combined_message); } else { generate_delphi_doc(out, (t_doc*)field); } } } void t_delphi_generator::generate_delphi_doc(ostream& out, t_doc* tdoc) { if (tdoc->has_doc() && xmldoc_) { generate_delphi_docstring_comment(out, xmldoc_encode(tdoc->get_doc())); } } void t_delphi_generator::generate_delphi_doc(ostream& out, t_function* tfunction) { if (tfunction->has_doc() && xmldoc_) { stringstream ps; const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; ps << "\nget_name()) << "\">"; if (p->has_doc()) { std::string str = p->get_doc(); str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); // remove the newlines that appear from the parser ps << xmldoc_encode(str); } ps << ""; } generate_docstring_comment(out, "{$REGION 'XMLDoc'}", "/// ", "" + xmldoc_encode(tfunction->get_doc()) + "" + ps.str(), "{$ENDREGION}\n"); } } bool t_delphi_generator::find_keyword(std::map& keyword_map, std::string name) { std::string::size_type len = name.length(); if (len <= 0) { return false; } std::string::size_type nlast = name.find_last_of('_'); if (nlast >= 1) { if (nlast == (len - 1)) { string new_name(name, 0, nlast); return find_keyword(keyword_map, new_name); } } return (keyword_map[name] == 1); } std::string t_delphi_generator::normalize_name(std::string name, bool b_method, bool b_exception_method) { string tmp(name); std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast(std::tolower)); bool b_found = false; if (find_keyword(delphi_keywords, tmp)) { b_found = true; } else if (b_method && find_keyword(delphi_reserved_method, tmp)) { b_found = true; } else if (b_exception_method && find_keyword(delphi_reserved_method_exception, tmp)) { b_found = true; } if (b_found) { return name + "_"; } else { return name; } } void t_delphi_generator::create_keywords() { delphi_keywords["and"] = 1; delphi_keywords["end"] = 1; delphi_keywords["interface"] = 1; delphi_keywords["raise"] = 1; delphi_keywords["uses"] = 1; delphi_keywords["array"] = 1; delphi_keywords["except"] = 1; delphi_keywords["is"] = 1; delphi_keywords["record"] = 1; delphi_keywords["var"] = 1; delphi_keywords["as"] = 1; delphi_keywords["exports"] = 1; delphi_keywords["label"] = 1; delphi_keywords["repeat"] = 1; delphi_keywords["while"] = 1; delphi_keywords["asm"] = 1; delphi_keywords["file"] = 1; delphi_keywords["library"] = 1; delphi_keywords["resourcestring"] = 1; delphi_keywords["with"] = 1; delphi_keywords["begin"] = 1; delphi_keywords["finalization"] = 1; delphi_keywords["mod"] = 1; delphi_keywords["set"] = 1; delphi_keywords["xor"] = 1; delphi_keywords["case"] = 1; delphi_keywords["finally"] = 1; delphi_keywords["nil"] = 1; delphi_keywords["shl"] = 1; delphi_keywords["class"] = 1; delphi_keywords["for"] = 1; delphi_keywords["not"] = 1; delphi_keywords["shr"] = 1; delphi_keywords["const"] = 1; delphi_keywords["function"] = 1; delphi_keywords["object"] = 1; delphi_keywords["string"] = 1; delphi_keywords["constructor"] = 1; delphi_keywords["goto"] = 1; delphi_keywords["of"] = 1; delphi_keywords["then"] = 1; delphi_keywords["destructor"] = 1; delphi_keywords["if"] = 1; delphi_keywords["or"] = 1; delphi_keywords["threadvar"] = 1; delphi_keywords["dispinterface"] = 1; delphi_keywords["implementation"] = 1; delphi_keywords["out"] = 1; delphi_keywords["to"] = 1; delphi_keywords["div"] = 1; delphi_keywords["in"] = 1; delphi_keywords["packed"] = 1; delphi_keywords["try"] = 1; delphi_keywords["do"] = 1; delphi_keywords["inherited"] = 1; delphi_keywords["procedure"] = 1; delphi_keywords["type"] = 1; delphi_keywords["downto"] = 1; delphi_keywords["initialization"] = 1; delphi_keywords["program"] = 1; delphi_keywords["unit"] = 1; delphi_keywords["else"] = 1; delphi_keywords["inline"] = 1; delphi_keywords["property"] = 1; delphi_keywords["until"] = 1; delphi_keywords["private"] = 1; delphi_keywords["protected"] = 1; delphi_keywords["public"] = 1; delphi_keywords["published"] = 1; delphi_keywords["automated"] = 1; delphi_keywords["at"] = 1; delphi_keywords["on"] = 1; // reserved/predefined variables and types (lowercase!) delphi_keywords["result"] = 1; delphi_keywords["system"] = 1; delphi_keywords["sysutils"] = 1; delphi_keywords["thrift"] = 1; delphi_keywords["tbytes"] = 1; delphi_keywords["tobject"] = 1; delphi_keywords["tclass"] = 1; delphi_keywords["tinterfacedobject"] = 1; delphi_keywords["ansistring"] = 1; delphi_keywords["string"] = 1; delphi_keywords["boolean"] = 1; delphi_keywords["shortint"] = 1; delphi_keywords["smallint"] = 1; delphi_keywords["integer"] = 1; delphi_keywords["int64"] = 1; delphi_keywords["double"] = 1; delphi_reserved_method["create"] = 1; delphi_reserved_method["free"] = 1; delphi_reserved_method["initinstance"] = 1; delphi_reserved_method["cleanupinstance"] = 1; delphi_reserved_method["classtype"] = 1; delphi_reserved_method["classname"] = 1; delphi_reserved_method["classnameis"] = 1; delphi_reserved_method["classparent"] = 1; delphi_reserved_method["classinfo"] = 1; delphi_reserved_method["instancesize"] = 1; delphi_reserved_method["inheritsfrom"] = 1; delphi_reserved_method["methodaddress"] = 1; delphi_reserved_method["methodname"] = 1; delphi_reserved_method["fieldaddress"] = 1; delphi_reserved_method["getinterface"] = 1; delphi_reserved_method["getinterfaceentry"] = 1; delphi_reserved_method["getinterfacetable"] = 1; delphi_reserved_method["unitname"] = 1; delphi_reserved_method["equals"] = 1; delphi_reserved_method["gethashcode"] = 1; delphi_reserved_method["tostring"] = 1; delphi_reserved_method["safecallexception"] = 1; delphi_reserved_method["afterconstruction"] = 1; delphi_reserved_method["beforedestruction"] = 1; delphi_reserved_method["dispatch"] = 1; delphi_reserved_method["defaulthandler"] = 1; delphi_reserved_method["newinstance"] = 1; delphi_reserved_method["freeinstance"] = 1; delphi_reserved_method["destroy"] = 1; delphi_reserved_method["read"] = 1; delphi_reserved_method["write"] = 1; delphi_reserved_method_exception["setinnerexception"] = 1; delphi_reserved_method_exception["setstackinfo"] = 1; delphi_reserved_method_exception["getstacktrace"] = 1; delphi_reserved_method_exception["raisingexception"] = 1; delphi_reserved_method_exception["createfmt"] = 1; delphi_reserved_method_exception["createres"] = 1; delphi_reserved_method_exception["createresfmt"] = 1; delphi_reserved_method_exception["createhelp"] = 1; delphi_reserved_method_exception["createfmthelp"] = 1; delphi_reserved_method_exception["createreshelp"] = 1; delphi_reserved_method_exception["createresfmthelp"] = 1; delphi_reserved_method_exception["getbaseexception"] = 1; delphi_reserved_method_exception["baseexception"] = 1; delphi_reserved_method_exception["helpcontext"] = 1; delphi_reserved_method_exception["innerexception"] = 1; delphi_reserved_method_exception["message"] = 1; delphi_reserved_method_exception["stacktrace"] = 1; delphi_reserved_method_exception["stackinfo"] = 1; delphi_reserved_method_exception["getexceptionstackinfoproc"] = 1; delphi_reserved_method_exception["getstackinfostringproc"] = 1; delphi_reserved_method_exception["cleanupstackinfoproc"] = 1; delphi_reserved_method_exception["raiseouterexception"] = 1; delphi_reserved_method_exception["throwouterexception"] = 1; } void t_delphi_generator::add_delphi_uses_list(string unitname) { vector::const_iterator s_iter; bool found = false; for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) { if ((*s_iter) == unitname) { found = true; break; } } if (!found) { uses_list.push_back(unitname); } } void t_delphi_generator::init_generator() { indent_impl_ = 0; namespace_name_ = program_->get_namespace("delphi"); has_forward = false; has_enum = false; has_const = false; create_keywords(); add_delphi_uses_list("Classes"); add_delphi_uses_list("SysUtils"); add_delphi_uses_list("Generics.Collections"); if(async_) { add_delphi_uses_list("System.Threading"); } add_delphi_uses_list("Thrift"); add_delphi_uses_list("Thrift.Utils"); add_delphi_uses_list("Thrift.Collections"); add_delphi_uses_list("Thrift.Protocol"); add_delphi_uses_list("Thrift.Transport"); if (register_types_) { add_delphi_uses_list("Thrift.TypeRegistry"); } init_known_types_list(); string unitname, nsname; const vector& includes = program_->get_includes(); for (auto include : includes) { unitname = include->get_name(); nsname = include->get_namespace("delphi"); if ("" != nsname) { unitname = normalize_name(nsname); } add_delphi_uses_list(unitname); } MKDIR(get_out_dir().c_str()); } void t_delphi_generator::close_generator() { std::string unitname = program_name_; if ("" != namespace_name_) { unitname = namespace_name_; } for (int i = 0; i < (int)unitname.size(); i++) { if (unitname[i] == ' ') { unitname.replace(i, 1, "_"); } } unitname = normalize_name(unitname); std::string f_name = get_out_dir() + "/" + unitname + ".pas"; ofstream_with_content_based_conditional_update f_all; f_all.open(f_name); f_all << autogen_comment() << endl; generate_delphi_doc(f_all, program_); f_all << "unit " << unitname << ";" << endl << endl; f_all << "{$WARN SYMBOL_DEPRECATED OFF}" << endl << endl; f_all << "interface" << endl << endl; f_all << "uses" << endl; indent_up(); vector::const_iterator s_iter; for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) { if (s_iter != uses_list.begin()) { f_all << ","; f_all << endl; } indent(f_all) << *s_iter; } f_all << ";" << endl << endl; indent_down(); string tmp_unit(unitname); for (int i = 0; i < (int)tmp_unit.size(); i++) { if (tmp_unit[i] == '.') { tmp_unit.replace(i, 1, "_"); } } f_all << "const" << endl; indent_up(); indent(f_all) << "c" << tmp_unit << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";" << endl; indent(f_all) << "c" << tmp_unit << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";" << endl; indent(f_all) << "c" << tmp_unit << "_Option_ConstPrefix = " << (constprefix_ ? "True" : "False") << ";" << endl; indent(f_all) << "c" << tmp_unit << "_Option_Events = " << (events_ ? "True" : "False") << ";" << endl; indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc = " << (xmldoc_ ? "True" : "False") << ";" << endl; indent_down(); f_all << endl; f_all << "type" << endl; if (has_forward) { f_all << s_forward_decr.str() << endl; } if (has_enum) { indent(f_all) << endl; indent(f_all) << "{$SCOPEDENUMS ON}" << endl << endl; f_all << s_enum.str(); indent(f_all) << "{$SCOPEDENUMS OFF}" << endl << endl; } f_all << s_struct.str(); f_all << s_service.str(); f_all << s_const.str(); f_all << "implementation" << endl << endl; f_all << s_struct_impl.str(); f_all << s_service_impl.str(); f_all << s_const_impl.str(); if (register_types_) { f_all << endl; f_all << "// Type factory methods and registration" << endl; f_all << s_type_factory_funcs.str(); f_all << "procedure RegisterTypeFactories;" << endl; f_all << "begin" << endl; f_all << s_type_factory_registration.str(); f_all << "end;" << endl; } f_all << endl; string constants_class = make_constants_classname(); f_all << "initialization" << endl; if (has_const) { f_all << "{$IF CompilerVersion < 21.0} // D2010" << endl; f_all << " " << constants_class.c_str() << "_Initialize;" << endl; f_all << "{$IFEND}" << endl; } if (register_types_) { f_all << " RegisterTypeFactories;" << endl; } f_all << endl; f_all << "finalization" << endl; if (has_const) { f_all << "{$IF CompilerVersion < 21.0} // D2010" << endl; f_all << " " << constants_class.c_str() << "_Finalize;" << endl; f_all << "{$IFEND}" << endl; } f_all << endl << endl; f_all << "end." << endl; f_all.close(); if (!typedefs_pending.empty()) { pwarning(0, "%d typedefs with unresolved type references left:\n", typedefs_pending.size()); for (std::list::iterator iter = typedefs_pending.begin(); typedefs_pending.end() != iter; ++iter) { pwarning(0, "- %s\n", (*iter)->get_symbolic().c_str()); } } } void t_delphi_generator::delphi_type_usings(ostream& out) { indent_up(); indent(out) << "Classes, SysUtils, Generics.Collections, Thrift.Collections, Thrift.Protocol," << endl; indent(out) << "Thrift.Transport;" << endl << endl; indent_down(); } void t_delphi_generator::generate_forward_declaration(t_struct* tstruct) { // Forward declare struct def has_forward = true; pverbose("forward declaration of %s\n", type_name(tstruct).c_str()); string what = tstruct->is_xception() ? "class" : "interface"; indent_up(); indent(s_forward_decr) << type_name(tstruct, tstruct->is_xception(), true) << " = " << what << ";" << endl; indent_down(); add_defined_type(tstruct); } void t_delphi_generator::generate_typedef(t_typedef* ttypedef) { t_type* type = ttypedef->get_type(); // write now or save for later? if (!is_fully_defined_type(type)) { pverbose("typedef %s: unresolved dependencies found\n", type_name(ttypedef).c_str()); typedefs_pending.push_back(ttypedef); return; } indent_up(); generate_delphi_doc(s_struct, ttypedef); indent(s_struct) << type_name(ttypedef) << " = "; // commented out: the benefit is not big enough to risk breaking existing code // bool container = type->is_list() || type->is_map() || type->is_set(); // if( ! container) // s_struct << "type "; //the "type A = type B" syntax leads to E2574 with generics s_struct << type_name(ttypedef->get_type()) << ";" << endl << endl; indent_down(); add_defined_type(ttypedef); } bool t_delphi_generator::is_fully_defined_type(t_type* ttype) { if ((nullptr != ttype->get_program()) && (ttype->get_program() != program_)) { t_scope* scope = ttype->get_program()->scope(); if (nullptr != scope->get_type(ttype->get_name())) { // printf("type %s found in included scope %s\n", ttype->get_name().c_str(), // ttype->get_program()->get_name().c_str()); return true; } } if (ttype->is_typedef()) { return (1 == types_known[type_name(ttype)]); } if (ttype->is_base_type()) { return (1 == types_known[base_type_name((t_base_type*)ttype)]); } else if (ttype->is_enum()) { return true; // enums are written first, before all other types } else if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; return is_fully_defined_type(tmap->get_key_type()) && is_fully_defined_type(tmap->get_val_type()); } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; return is_fully_defined_type(tset->get_elem_type()); } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; return is_fully_defined_type(tlist->get_elem_type()); } return (1 == types_known[type_name(ttype)]); } void t_delphi_generator::add_defined_type(t_type* ttype) { // mark as known type types_known[type_name(ttype)] = 1; // check all pending typedefs std::list::iterator iter; bool more = true; while (more && (!typedefs_pending.empty())) { more = false; for (iter = typedefs_pending.begin(); typedefs_pending.end() != iter; ++iter) { t_typedef* ttypedef = (*iter); if (is_fully_defined_type(ttypedef->get_type())) { pverbose("typedef %s: all pending references are now resolved\n", type_name(ttypedef).c_str()); typedefs_pending.erase(iter); generate_typedef(ttypedef); more = true; break; } } } } void t_delphi_generator::init_known_types_list() { // known base types types_known[type_name(g_type_string)] = 1; types_known[type_name(g_type_binary)] = 1; types_known[type_name(g_type_bool)] = 1; types_known[type_name(g_type_i8)] = 1; types_known[type_name(g_type_i16)] = 1; types_known[type_name(g_type_i32)] = 1; types_known[type_name(g_type_i64)] = 1; types_known[type_name(g_type_double)] = 1; } void t_delphi_generator::generate_enum(t_enum* tenum) { has_enum = true; indent_up(); generate_delphi_doc(s_enum, tenum); indent(s_enum) << type_name(tenum, true, true) << " = " << "(" << endl; indent_up(); vector constants = tenum->get_constants(); if (constants.empty()) { indent(s_enum) << "dummy = 0 // empty enums are not allowed"; } else { vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); if (c_iter != constants.begin()) { s_enum << ","; s_enum << endl; } generate_delphi_doc(s_enum, *c_iter); indent(s_enum) << normalize_name((*c_iter)->get_name()) << " = " << value; } } s_enum << endl; indent_down(); indent(s_enum) << ");" << endl << endl; indent_down(); } std::string t_delphi_generator::make_pascal_string_literal(std::string value) { std::stringstream result; if (value.length() == 0) { return ""; } result << "'"; for (signed char const c: value) { if( (c >= 0) && (c < 32)) { // convert ctrl chars, but leave UTF-8 alone result << "#" << (int)c; } else if (c == '\'') { result << "''"; // duplicate any single quotes we find } else { result << c; // anything else "as is" } } result << "'"; return result.str(); } std::string t_delphi_generator::make_valid_delphi_identifier(std::string const& fromName) { std::string str = fromName; if (str.empty()) { return str; } // tests rely on this assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); // if the first letter is a number, we add an additional underscore in front of it char c = str.at(0); if (('0' <= c) && (c <= '9')) { str = "_" + str; } // following chars: letter, number or underscore for (size_t i = 0; i < str.size(); ++i) { c = str.at(i); if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) && ('_' != c)) { str.replace(i, 1, "_"); } } return str; } std::string t_delphi_generator::make_constants_classname() { if (constprefix_) { return make_valid_delphi_identifier("T" + program_name_ + "Constants"); } else { return "TConstants"; // compatibility } } void t_delphi_generator::generate_consts(std::vector consts) { if (consts.empty()) { return; } has_const = true; string constants_class = make_constants_classname(); indent_up(); indent(s_const) << constants_class.c_str() << " = class" << endl; indent(s_const) << "private" << endl; indent_up(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { if (const_needs_var((*c_iter)->get_type())) { print_private_field(s_const, normalize_name((*c_iter)->get_name()), (*c_iter)->get_type(), (*c_iter)->get_value()); } } indent_down(); indent(s_const) << "public" << endl; indent_up(); for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { generate_delphi_doc(s_const, *c_iter); print_const_prop(s_const, normalize_name((*c_iter)->get_name()), (*c_iter)->get_type(), (*c_iter)->get_value()); } indent(s_const) << "{$IF CompilerVersion >= 21.0}" << endl; indent(s_const) << "class constructor Create;" << endl; indent(s_const) << "class destructor Destroy;" << endl; indent(s_const) << "{$IFEND}" << endl; indent_down(); indent(s_const) << "end;" << endl << endl; indent_down(); std::ostringstream vars, code; indent_up_impl(); for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { initialize_field(vars, code, "F" + prop_name((*c_iter)->get_name()), (*c_iter)->get_type(), (*c_iter)->get_value()); } indent_down_impl(); indent_impl(s_const_impl) << "{$IF CompilerVersion >= 21.0}" << endl; indent_impl(s_const_impl) << "class constructor " << constants_class.c_str() << ".Create;" << endl; if (!vars.str().empty()) { indent_impl(s_const_impl) << "var" << endl; s_const_impl << vars.str(); } indent_impl(s_const_impl) << "begin" << endl; if (!code.str().empty()) { s_const_impl << code.str(); } indent_impl(s_const_impl) << "end;" << endl << endl; indent_impl(s_const_impl) << "class destructor " << constants_class.c_str() << ".Destroy;" << endl; indent_impl(s_const_impl) << "begin" << endl; indent_up_impl(); for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { if (const_needs_var((*c_iter)->get_type())) { finalize_field(s_const_impl, normalize_name((*c_iter)->get_name()), (*c_iter)->get_type(), (*c_iter)->get_value()); } } indent_impl(s_const_impl) << "inherited;" << endl; indent_down_impl(); indent_impl(s_const_impl) << "end;" << endl; indent_impl(s_const_impl) << "{$ELSE}" << endl; vars.str(""); code.str(""); indent_up_impl(); for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { if (const_needs_var((*c_iter)->get_type())) { initialize_field(vars, code, constants_class + ".F" + prop_name((*c_iter)->get_name()), (*c_iter)->get_type(), (*c_iter)->get_value()); } } indent_down_impl(); indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Initialize;" << endl; if (!vars.str().empty()) { indent_impl(s_const_impl) << "var" << endl; s_const_impl << vars.str(); } indent_impl(s_const_impl) << "begin" << endl; if (!code.str().empty()) { s_const_impl << code.str(); } indent_impl(s_const_impl) << "end;" << endl << endl; indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Finalize;" << endl; indent_impl(s_const_impl) << "begin" << endl; indent_up_impl(); for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { finalize_field(s_const_impl, normalize_name((*c_iter)->get_name()), (*c_iter)->get_type(), (*c_iter)->get_value(), constants_class); } indent_down_impl(); indent_impl(s_const_impl) << "end;" << endl; indent_impl(s_const_impl) << "{$IFEND}" << endl << endl; } void t_delphi_generator::print_const_def_value(std::ostream& vars, std::ostream& out, string name, t_type* type, t_const_value* value, string cls_nm) { string cls_prefix; if (cls_nm == "") { cls_prefix = ""; } else { cls_prefix = cls_nm + "."; } if (type->is_struct() || type->is_xception()) { const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string val = render_const_value(vars, out, name, field_type, v_iter->second); indent_impl(out) << cls_prefix << normalize_name(name) << "." << prop_name(v_iter->first->get_string(), type->is_xception()) << " := " << val << ";" << endl; } } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(vars, out, name, ktype, v_iter->first); string val = render_const_value(vars, out, name, vtype, v_iter->second); indent_impl(out) << cls_prefix << normalize_name(name) << "[" << key << "]" << " := " << val << ";" << endl; } } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(vars, out, name, etype, *v_iter); indent_impl(out) << cls_prefix << normalize_name(name) << ".Add(" << val << ");" << endl; } } } void t_delphi_generator::print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value) { (void)value; indent(out) << "class var F" << name << ": " << type_name(type) << ";" << endl; } bool t_delphi_generator::const_needs_var(t_type* type) { t_type* truetype = type; while (truetype->is_typedef()) { truetype = ((t_typedef*)truetype)->get_type(); } return (!truetype->is_base_type()); } void t_delphi_generator::print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value) { (void)value; if (const_needs_var(type)) { indent(out) << "class property " << name << ": " << type_name(type) << " read F" << name << ";" << endl; } else { std::ostringstream vars; // dummy string v2 = render_const_value(vars, out, name, type, value); indent(out) << "const " << name << " = " << v2 << ";" << endl; } } void t_delphi_generator::print_const_value(std::ostream& vars, std::ostream& out, string name, t_type* type, t_const_value* value) { t_type* truetype = type; while (truetype->is_typedef()) { truetype = ((t_typedef*)truetype)->get_type(); } if (truetype->is_base_type()) { // already done // string v2 = render_const_value( vars, out, name, type, value); // indent_impl(out) << name << " := " << v2 << ";" << endl; } else if (truetype->is_enum()) { indent_impl(out) << name << " := " << type_name(type) << "." << value->get_identifier_name() << ";" << endl; } else { string typname; typname = type_name(truetype, true, false, type->is_xception(), type->is_xception()); indent_impl(out) << name << " := " << typname << ".Create;" << endl; print_const_def_value(vars, out, name, truetype, value); } } void t_delphi_generator::initialize_field(std::ostream& vars, std::ostream& out, string name, t_type* type, t_const_value* value) { print_const_value(vars, out, name, type, value); } void t_delphi_generator::finalize_field(std::ostream& out, string name, t_type* type, t_const_value* value, string cls_nm) { (void)out; (void)name; (void)type; (void)value; (void)cls_nm; } string t_delphi_generator::render_const_value(ostream& vars, ostream& out, string name, t_type* type, t_const_value* value) { (void)name; t_type* truetype = type; while (truetype->is_typedef()) { truetype = ((t_typedef*)truetype)->get_type(); } std::ostringstream render; if (truetype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: render << "'" << get_escaped_string(value) << "'"; break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "True" : "False"); break; case t_base_type::TYPE_I8: render << "ShortInt( " << value->get_integer() << ")"; break; case t_base_type::TYPE_I16: render << "SmallInt( " << value->get_integer() << ")"; break; case t_base_type::TYPE_I32: render << "LongInt( " << value->get_integer() << ")"; break; case t_base_type::TYPE_I64: render << "Int64( " << value->get_integer() << ")"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << value->get_integer() << ".0"; // make it a double constant by adding ".0" } else { render << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (truetype->is_enum()) { render << type_name(type, false) << "." << value->get_identifier_name(); } else { string t = tmp("tmp"); vars << " " << t << " : " << type_name(type) << ";" << endl; print_const_value(vars, out, t, type, value); render << t; } return render.str(); } void t_delphi_generator::generate_struct(t_struct* tstruct) { generate_delphi_struct(tstruct, false); } void t_delphi_generator::generate_xception(t_struct* txception) { generate_delphi_struct(txception, true); } void t_delphi_generator::generate_delphi_struct(t_struct* tstruct, bool is_exception) { indent_up(); generate_delphi_struct_definition(s_struct, tstruct, is_exception); indent_down(); add_defined_type(tstruct); generate_delphi_struct_impl(s_struct_impl, "", tstruct, is_exception); if (register_types_) { generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception); generate_delphi_struct_type_factory_registration(s_type_factory_registration, "", tstruct, is_exception); } } void t_delphi_generator::generate_delphi_struct_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) { if (is_exception && (!is_x_factory)) { generate_delphi_struct_impl(out, cls_prefix, tstruct, is_exception, is_result, true); } string cls_nm; string exception_factory_name; if (is_exception) { exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; } if (is_exception) { cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true); } else { cls_nm = type_name(tstruct, true, false); } std::ostringstream vars, code; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; indent_up_impl(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = (*m_iter)->get_type(); while (t->is_typedef()) { t = ((t_typedef*)t)->get_type(); } if ((*m_iter)->get_value() != nullptr) { initialize_field(vars, code, "F" + prop_name((*m_iter)->get_name(), is_exception), t, (*m_iter)->get_value()); if ((*m_iter)->get_req() != t_field::T_REQUIRED) { indent_impl(code) << "F__isset_" << prop_name((*m_iter), is_exception) << " := True;" << endl; } } } indent_down_impl(); indent_impl(out) << "constructor " << cls_prefix << cls_nm << "." << "Create;" << endl; if (!vars.str().empty()) { out << "var" << endl; out << vars.str(); } indent_impl(out) << "begin" << endl; indent_up_impl(); if (is_exception && (!is_x_factory)) { indent_impl(out) << "inherited Create('');" << endl; } else { indent_impl(out) << "inherited;" << endl; } if (!code.str().empty()) { out << code.str(); } indent_down_impl(); indent_impl(out) << "end;" << endl << endl; if ((members.size() > 0) && is_exception && (!is_x_factory)) { indent_impl(out) << "constructor " << cls_prefix << cls_nm << "." << "Create(" << constructor_argument_list(tstruct, indent_impl()) << ");" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "Create;" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { string propname = prop_name((*m_iter)->get_name(), is_exception); string param_name = constructor_param_name((*m_iter)->get_name()); indent_impl(out) << propname << " := " << param_name << ";" << endl; } indent_impl(out) << "UpdateMessageProperty;" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } indent_impl(out) << "destructor " << cls_prefix << cls_nm << "." << "Destroy;" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = (*m_iter)->get_type(); while (t->is_typedef()) { t = ((t_typedef*)t)->get_type(); } finalize_field(out, prop_name(*m_iter, is_exception), t, (*m_iter)->get_value()); } indent_impl(out) << "inherited;" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; if (is_exception && (!is_x_factory)) { indent_impl(out) << "function " << cls_prefix << cls_nm << "." << exception_factory_name << ": I" << exception_factory_name << ";" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "if F" << exception_factory_name << " = nil" << endl; indent_impl(out) << "then F" << exception_factory_name << " := T" << exception_factory_name << "Impl.Create;" << endl << endl; indent_impl(out) << "result := F" << exception_factory_name << ";" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; indent_impl(out) << "function " << cls_prefix << cls_nm << ".QueryInterface(const IID: TGUID; out Obj): HRESULT;" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "if GetInterface(IID, Obj)" << endl; indent_impl(out) << "then result := S_OK" << endl; indent_impl(out) << "else result := E_NOINTERFACE;" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; indent_impl(out) << "function " << cls_prefix << cls_nm << "._AddRef: Integer;" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "result := -1; // not refcounted" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; indent_impl(out) << "function " << cls_prefix << cls_nm << "._Release: Integer;" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "result := -1; // not refcounted" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } if (tstruct->is_union()) { indent_impl(out) << "procedure " << cls_prefix << cls_nm << "." << "ClearUnionValues;" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = (*m_iter)->get_type(); while (t->is_typedef()) { t = ((t_typedef*)t)->get_type(); } generate_delphi_clear_union_value(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception, tstruct->is_union(), is_x_factory, exception_factory_name); } indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = (*m_iter)->get_type(); while (t->is_typedef()) { t = ((t_typedef*)t)->get_type(); } generate_delphi_property_reader_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception); generate_delphi_property_writer_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception, tstruct->is_union(), is_x_factory, exception_factory_name); if ((*m_iter)->get_req() != t_field::T_REQUIRED) { generate_delphi_isset_reader_writer_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception); } } generate_delphi_struct_reader_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); if (is_result) { generate_delphi_struct_result_writer_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); } else { generate_delphi_struct_writer_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); } generate_delphi_struct_tostring_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); if (is_exception && is_x_factory) { generate_delphi_create_exception_impl(out, cls_prefix, tstruct, is_exception); } } void t_delphi_generator::print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct) { string struct_intf_name = type_name(tstruct); out << "Create_"; out << struct_intf_name; out << "_Impl"; } void t_delphi_generator::generate_delphi_struct_type_factory(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) { (void)cls_prefix; if (is_exception) return; if (is_result) return; if (is_x_factory) return; string struct_intf_name = type_name(tstruct); string cls_nm = type_name(tstruct, true, false); out << "function "; print_delphi_struct_type_factory_func(out, tstruct); out << ": "; out << struct_intf_name; out << ";" << endl; out << "begin" << endl; indent_up(); indent(out) << "Result := " << cls_nm << ".Create;" << endl; indent_down(); out << "end;" << endl << endl; } void t_delphi_generator::generate_delphi_struct_type_factory_registration(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) { (void)cls_prefix; if (is_exception) return; if (is_result) return; if (is_x_factory) return; string struct_intf_name = type_name(tstruct); indent(out) << " TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">("; print_delphi_struct_type_factory_func(out, tstruct); out << ");"; out << endl; } void t_delphi_generator::generate_delphi_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result, bool is_x_factory) { bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); string struct_intf_name; string struct_name; string isset_name; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; string exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; if (is_exception) { struct_intf_name = type_name(tstruct, false, false, true); } else { struct_intf_name = type_name(tstruct); } if (is_exception) { struct_name = type_name(tstruct, true, (!is_x_factory), is_x_factory); } else { struct_name = type_name(tstruct, true); } if ((!is_exception) || is_x_factory) { generate_delphi_doc(out, tstruct); indent(out) << struct_intf_name << " = interface(IBase)" << endl; indent_up(); generate_guid(out); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_delphi_property_reader_definition(out, *m_iter, is_exception); generate_delphi_property_writer_definition(out, *m_iter, is_exception); } if (is_x_factory) { out << endl; indent(out) << "// Create Exception Object" << endl; indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl; } if (members.size() > 0) { out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_property(out, *m_iter, true, is_exception); } } if (members.size() > 0) { out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_REQUIRED) { generate_delphi_isset_reader_writer_definition(out, *m_iter, is_exception); } } } if (members.size() > 0) { out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_REQUIRED) { isset_name = "__isset_" + prop_name(*m_iter, is_exception); indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";" << endl; } } } indent_down(); indent(out) << "end;" << endl << endl; } generate_delphi_doc(out, tstruct); indent(out) << struct_name << " = "; if (is_final) { out << "sealed "; } out << "class("; if (is_exception && (!is_x_factory)) { out << "TException, IInterface, IBase, ISupportsToString"; } else { out << "TInterfacedObject, IBase, ISupportsToString, " << struct_intf_name; } out << ")" << endl; if (is_exception && (!is_x_factory)) { indent(out) << "public" << endl; indent_up(); indent(out) << "type" << endl; indent_up(); generate_delphi_struct_definition(out, tstruct, is_exception, in_class, is_result, true); indent_down(); indent_down(); } indent(out) << "private" << endl; indent_up(); if (is_exception && (!is_x_factory)) { indent(out) << "F" << exception_factory_name << " :" << struct_intf_name << ";" << endl << endl; } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << declare_field(*m_iter, false, "F", is_exception) << endl; } if (members.size() > 0) { indent(out) << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_REQUIRED) { isset_name = "F__isset_" + prop_name(*m_iter, is_exception); indent(out) << isset_name << ": System.Boolean;" << endl; } } } indent(out) << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_delphi_property_reader_definition(out, *m_iter, is_exception); generate_delphi_property_writer_definition(out, *m_iter, is_exception); } if (tstruct->is_union()) { out << endl; indent(out) << "// Clear values(for union's property setter)" << endl; indent(out) << "procedure ClearUnionValues;" << endl; } if (members.size() > 0) { out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_REQUIRED) { isset_name = "__isset_" + prop_name(*m_iter, is_exception); indent(out) << "function Get" << isset_name << ": System.Boolean;" << endl; indent(out) << "procedure Set" << isset_name << "( const value : System.Boolean);" << endl; } } } if (is_exception && (!is_x_factory)) { out << endl; indent_down(); indent(out) << "strict protected" << endl; indent_up(); indent(out) << "function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;" << endl; indent(out) << "function _AddRef: Integer; stdcall;" << endl; indent(out) << "function _Release: Integer; stdcall;" << endl; out << endl; } indent_down(); indent(out) << "public" << endl; indent_up(); if ((members.size() > 0) && is_exception && (!is_x_factory)) { indent(out) << "constructor Create; overload;" << endl; indent(out) << "constructor Create(" << constructor_argument_list(tstruct, indent()) << "); overload;" << endl; } else { indent(out) << "constructor Create;" << endl; } indent(out) << "destructor Destroy; override;" << endl; out << endl; indent(out) << "function ToString: string; override;" << endl; if (is_exception && (!is_x_factory)) { out << endl; indent(out) << "// Exception Factory" << endl; indent(out) << "function " << exception_factory_name << ": " << struct_intf_name << ";" << endl; } out << endl; indent(out) << "// IBase" << endl; indent(out) << "procedure Read( const iprot: IProtocol);" << endl; indent(out) << "procedure Write( const oprot: IProtocol);" << endl; if (is_exception && is_x_factory) { out << endl; indent(out) << "// Create Exception Object" << endl; indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl; } if (members.size() > 0) { out << endl; indent(out) << "// Properties" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_property(out, *m_iter, true, is_exception); } } if (members.size() > 0) { out << endl; indent(out) << "// isset" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_REQUIRED) { isset_name = "__isset_" + prop_name(*m_iter, is_exception); indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";" << endl; } } } indent_down(); indent(out) << "end;" << endl << endl; } void t_delphi_generator::generate_service(t_service* tservice) { indent_up(); generate_delphi_doc(s_service, tservice); indent(s_service) << normalize_clsnm(service_name_, "T") << " = class" << endl; indent(s_service) << "public" << endl; indent_up(); indent(s_service) << "type" << endl; generate_service_interface(tservice); generate_service_client(tservice); generate_service_server(tservice); generate_service_helpers(tservice); indent_down(); indent_down(); indent(s_service) << "end;" << endl; indent(s_service) << endl; indent_down(); } void t_delphi_generator::generate_service_interface(t_service* tservice) { generate_service_interface(tservice,false); if(async_) { generate_service_interface(tservice,true); } } void t_delphi_generator::generate_service_interface(t_service* tservice, bool for_async) { string extends = ""; string extends_iface = ""; string iface_name = for_async ? "IAsync" : "Iface"; indent_up(); generate_delphi_doc(s_service, tservice); if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends(), true, true); extends_iface = extends + "." + iface_name; generate_delphi_doc(s_service, tservice); indent(s_service) << iface_name << " = interface(" << extends_iface << ")" << endl; } else { indent(s_service) << iface_name << " = interface" << endl; } indent_up(); generate_guid(s_service); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_delphi_doc(s_service, *f_iter); indent(s_service) << function_signature(*f_iter, for_async) << endl; } indent_down(); indent(s_service) << "end;" << endl << endl; indent_down(); } void t_delphi_generator::generate_guid(std::ostream& out) { #ifdef _WIN32 // TODO: add support for non-windows platforms if needed GUID guid; if (SUCCEEDED(CoCreateGuid(&guid))) { OLECHAR guid_chars[40]; if (StringFromGUID2(guid, &guid_chars[0], sizeof(guid_chars) / sizeof(guid_chars[0])) > 0) { std::wstring guid_wstr(guid_chars); std::wstring_convert> convert; std::string guid_str = convert.to_bytes(guid_wstr); indent(out) << "['" << guid_str << "']" << endl; } } #else (void)out; // prevent unused warning on other platforms #endif } void t_delphi_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_delphi_struct_definition(s_service, ts, false, true); generate_delphi_struct_impl(s_service_impl, normalize_clsnm(service_name_, "T") + ".", ts, false); generate_function_helpers(*f_iter); } } void t_delphi_generator::generate_service_client(t_service* tservice) { indent_up(); string extends = ""; string extends_client = "TInterfacedObject"; string implements = async_ ? "Iface, IAsync" : "Iface"; generate_delphi_doc(s_service, tservice); if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends(), true, true); extends_client = extends + ".TClient"; } indent(s_service) << "TClient = class( " << extends_client << ", " << implements << ")" << endl; indent(s_service) << "public" << endl; indent_up(); indent(s_service) << "constructor Create( prot: IProtocol); overload;" << endl; indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T") << ".TClient.Create( prot: IProtocol);" << endl; indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "Create( prot, prot );" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; indent(s_service) << "constructor Create( const iprot: IProtocol; const oprot: IProtocol); overload;" << endl; indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T") << ".TClient.Create( const iprot: IProtocol; const oprot: IProtocol);" << endl; indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "inherited Create;" << endl; indent_impl(s_service_impl) << "iprot_ := iprot;" << endl; indent_impl(s_service_impl) << "oprot_ := oprot;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; indent_down(); if (extends.empty()) { indent(s_service) << "protected" << endl; indent_up(); indent(s_service) << "iprot_: IProtocol;" << endl; indent(s_service) << "oprot_: IProtocol;" << endl; indent(s_service) << "seqid_: System.Integer;" << endl; indent_down(); indent(s_service) << "public" << endl; indent_up(); indent(s_service) << "property InputProtocol: IProtocol read iprot_;" << endl; indent(s_service) << "property OutputProtocol: IProtocol read oprot_;" << endl; indent_down(); } vector functions = tservice->get_functions(); vector::const_iterator f_iter; indent(s_service) << "protected" << endl; indent_up(); indent(s_service) << "// Iface" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); generate_delphi_doc(s_service, *f_iter); indent(s_service) << function_signature(*f_iter, false) << endl; } if( async_) { indent(s_service) << endl; indent(s_service) << "// IAsync" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); generate_delphi_doc(s_service, *f_iter); indent(s_service) << function_signature(*f_iter, true) << endl; } } indent_down(); indent(s_service) << "public" << endl; indent_up(); string full_cls = normalize_clsnm(service_name_, "T") + ".TClient"; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); vector::const_iterator fld_iter; t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); // one for sync only, two for async+sync int mode = async_ ? 1 : 0; while( mode >= 0) { bool for_async = (mode != 0); mode--; indent_impl(s_service_impl) << function_signature(*f_iter, for_async, full_cls) << endl; indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); t_type* ttype = (*f_iter)->get_returntype(); if( for_async) { if (is_void(ttype)) { // Delphi forces us to specify a type with IFuture, so we use Integer=0 for void methods indent_impl(s_service_impl) << "result := TTask.Future(function: System.Integer" << endl; } else { string rettype = type_name(ttype, false, true, false, true); indent_impl(s_service_impl) << "result := TTask.Future<" << rettype << ">(function: " << rettype << endl; } indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); } indent_impl(s_service_impl) << "send_" << funname << "("; bool first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { s_service_impl << ", "; } s_service_impl << normalize_name((*fld_iter)->get_name()); } s_service_impl << ");" << endl; if (!(*f_iter)->is_oneway()) { s_service_impl << indent_impl(); if (!(*f_iter)->get_returntype()->is_void()) { s_service_impl << "Result := "; } s_service_impl << "recv_" << funname << "();" << endl; } if( for_async) { if (is_void(ttype)) { indent_impl(s_service_impl) << "Result := 0;" << endl; // no IFuture in Delphi } indent_down_impl(); indent_impl(s_service_impl) << "end);" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; } t_function send_function(g_type_void, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); string argsname = (*f_iter)->get_name() + "_args"; string args_clsnm = normalize_clsnm(argsname, "T"); string args_intfnm = normalize_clsnm(argsname, "I"); string argsvar = tmp("_args"); string msgvar = tmp("_msg"); indent(s_service) << function_signature(&send_function, false) << endl; indent_impl(s_service_impl) << function_signature(&send_function, false, full_cls) << endl; indent_impl(s_service_impl) << "var" << endl; indent_up_impl(); indent_impl(s_service_impl) << argsvar << " : " << args_intfnm << ";" << endl; indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "seqid_ := seqid_ + 1;" << endl; indent_impl(s_service_impl) << "Thrift.Protocol.Init( " << msgvar << ", '" << funname << "', " << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call") << ", seqid_);" << endl; indent_impl(s_service_impl) << "oprot_.WriteMessageBegin( " << msgvar << " );" << endl; indent_impl(s_service_impl) << argsvar << " := " << args_clsnm << "Impl.Create();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter) << " := " << normalize_name((*fld_iter)->get_name()) << ";" << endl; } indent_impl(s_service_impl) << argsvar << ".Write(oprot_);" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter) << " := " << empty_value((*fld_iter)->get_type()) << ";" << endl; } indent_impl(s_service_impl) << "oprot_.WriteMessageEnd();" << endl; indent_impl(s_service_impl) << "oprot_.Transport.Flush();" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; if (!(*f_iter)->is_oneway()) { string org_resultname = (*f_iter)->get_name() + "_result"; string result_clsnm = normalize_clsnm(org_resultname, "T"); string result_intfnm = normalize_clsnm(org_resultname, "I"); t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs, (*f_iter)->get_xceptions()); t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); string exceptvar = tmp("_ex"); string appexvar = tmp("_ax"); string retvar = tmp("_ret"); indent(s_service) << function_signature(&recv_function, false) << endl; indent_impl(s_service_impl) << function_signature(&recv_function, false, full_cls) << endl; indent_impl(s_service_impl) << "var" << endl; indent_up_impl(); indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl; if (xceptions.size() > 0) { indent_impl(s_service_impl) << exceptvar << " : Exception;" << endl; } indent_impl(s_service_impl) << appexvar << " : TApplicationException;" << endl; indent_impl(s_service_impl) << retvar << " : " << result_intfnm << ";" << endl; indent_down_impl(); indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << msgvar << " := iprot_.ReadMessageBegin();" << endl; indent_impl(s_service_impl) << "if (" << msgvar << ".Type_ = TMessageType.Exception) then begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << appexvar << " := TApplicationException.Read(iprot_);" << endl; indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl; indent_impl(s_service_impl) << "raise " << appexvar << ";" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; indent_impl(s_service_impl) << retvar << " := " << result_clsnm << "Impl.Create();" << endl; indent_impl(s_service_impl) << retvar << ".Read(iprot_);" << endl; indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl; if (!(*f_iter)->get_returntype()->is_void()) { indent_impl(s_service_impl) << "if (" << retvar << ".__isset_success) then begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "Result := " << retvar << ".Success;" << endl; t_type* type = (*f_iter)->get_returntype(); if (type->is_struct() || type->is_xception() || type->is_map() || type->is_list() || type->is_set()) { indent_impl(s_service_impl) << retvar << ".Success := nil;" << endl; } indent_impl(s_service_impl) << "Exit;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; } vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { indent_impl(s_service_impl) << "if (" << retvar << ".__isset_" << prop_name(*x_iter) << ") then begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter) << ".CreateException;" << endl; indent_impl(s_service_impl) << "raise " << exceptvar << ";" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; } if (!(*f_iter)->get_returntype()->is_void()) { indent_impl(s_service_impl) << "raise TApplicationExceptionMissingResult.Create('" << (*f_iter)->get_name() << " failed: unknown result');" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; } } indent_down(); indent(s_service) << "end;" << endl << endl; } void t_delphi_generator::generate_service_server(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_processor = ""; string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl"; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends(), true, true); extends_processor = extends + ".TProcessorImpl"; indent(s_service) << "TProcessorImpl = class(" << extends_processor << ", IProcessor)" << endl; } else { indent(s_service) << "TProcessorImpl = class( TInterfacedObject, IProcessor)" << endl; } indent(s_service) << "public" << endl; indent_up(); indent(s_service) << "constructor Create( iface_: Iface );" << endl; indent(s_service) << "destructor Destroy; override;" << endl; indent_down(); indent_impl(s_service_impl) << "constructor " << full_cls << ".Create( iface_: Iface );" << endl; indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); if (tservice->get_extends() != nullptr) { indent_impl(s_service_impl) << "inherited Create( iface_);" << endl; } else { indent_impl(s_service_impl) << "inherited Create;" << endl; } indent_impl(s_service_impl) << "Self.iface_ := iface_;" << endl; if (tservice->get_extends() != nullptr) { indent_impl(s_service_impl) << "ASSERT( processMap_ <> nil); // inherited" << endl; } else { indent_impl(s_service_impl) << "processMap_ := TThriftDictionaryImpl.Create;" << endl; } for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent_impl(s_service_impl) << "processMap_.AddOrSetValue( '" << (*f_iter)->get_name() << "', " << (*f_iter)->get_name() << "_Process);" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; indent_impl(s_service_impl) << "destructor " << full_cls << ".Destroy;" << endl; indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "inherited;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; indent(s_service) << "private" << endl; indent_up(); indent(s_service) << "iface_: Iface;" << endl; indent_down(); if (tservice->get_extends() == nullptr) { indent(s_service) << "protected" << endl; indent_up(); indent(s_service) << "type" << endl; indent_up(); indent(s_service) << "TProcessFunction = reference to procedure( seqid: System.Integer; const iprot: " "IProtocol; const oprot: IProtocol" << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; indent_down(); indent_down(); indent(s_service) << "protected" << endl; indent_up(); indent(s_service) << "processMap_: IThriftDictionary;" << endl; indent_down(); } indent(s_service) << "public" << endl; indent_up(); if (extends.empty()) { indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const " "events : IProcessorEvents): System.Boolean;" << endl; } else { indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const " "events : IProcessorEvents): System.Boolean; reintroduce;" << endl; } indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; " "const oprot: IProtocol; const events " ": IProcessorEvents): System.Boolean;" << endl; ; indent_impl(s_service_impl) << "var" << endl; indent_up_impl(); indent_impl(s_service_impl) << "msg : Thrift.Protocol.TThriftMessage;" << endl; indent_impl(s_service_impl) << "fn : TProcessFunction;" << endl; indent_impl(s_service_impl) << "x : TApplicationException;" << endl; if (events_) { indent_impl(s_service_impl) << "context : IRequestEvents;" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "try" << endl; indent_up_impl(); indent_impl(s_service_impl) << "msg := iprot.ReadMessageBegin();" << endl; indent_impl(s_service_impl) << "fn := nil;" << endl; indent_impl(s_service_impl) << "if not processMap_.TryGetValue(msg.Name, fn)" << endl; indent_impl(s_service_impl) << "or not Assigned(fn) then begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "TProtocolUtil.Skip(iprot, TType.Struct);" << endl; indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl; indent_impl(s_service_impl) << "x := " "TApplicationExceptionUnknownMethod.Create(" "'Invalid method name: ''' + msg.Name + '''');" << endl; indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, msg.Name, TMessageType.Exception, msg.SeqID);" << endl; indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl; indent_impl(s_service_impl) << "x.Write(oprot);" << endl; indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; indent_impl(s_service_impl) << "Result := True;" << endl; indent_impl(s_service_impl) << "Exit;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; if (events_) { indent_impl(s_service_impl) << "if events <> nil" << endl; indent_impl(s_service_impl) << "then context := events.CreateRequestContext(msg.Name)" << endl; indent_impl(s_service_impl) << "else context := nil;" << endl; indent_impl(s_service_impl) << "try" << endl; indent_up_impl(); indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot, context);" << endl; indent_down_impl(); indent_impl(s_service_impl) << "finally" << endl; indent_up_impl(); indent_impl(s_service_impl) << "if context <> nil then begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "context.CleanupContext;" << endl; indent_impl(s_service_impl) << "context := nil;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; } else { indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "except" << endl; indent_up_impl(); indent_impl(s_service_impl) << "on TTransportExceptionTimedOut do begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "Result := True;" << endl; indent_impl(s_service_impl) << "Exit;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; indent_impl(s_service_impl) << "else begin" << endl; indent_up_impl(); indent_impl(s_service_impl) << "Result := False;" << endl; indent_impl(s_service_impl) << "Exit;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; indent_impl(s_service_impl) << "Result := True;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } indent_down(); indent(s_service) << "end;" << endl << endl; } void t_delphi_generator::generate_function_helpers(t_function* tfunction) { if (tfunction->is_oneway()) { return; } t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "Success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_delphi_struct_definition(s_service, &result, false, true, true); generate_delphi_struct_impl(s_service_impl, normalize_clsnm(service_name_, "T") + ".", &result, false); } void t_delphi_generator::generate_process_function(t_service* tservice, t_function* tfunction) { (void)tservice; string funcname = tfunction->get_name(); string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl"; string org_argsname = funcname + "_args"; string args_clsnm = normalize_clsnm(org_argsname, "T"); string args_intfnm = normalize_clsnm(org_argsname, "I"); string org_resultname = funcname + "_result"; string result_clsnm = normalize_clsnm(org_resultname, "T"); string result_intfnm = normalize_clsnm(org_resultname, "I"); indent(s_service) << "procedure " << funcname << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol" << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; if (tfunction->is_oneway()) { indent_impl(s_service_impl) << "// one way processor" << endl; } else { indent_impl(s_service_impl) << "// both way processor" << endl; } indent_impl(s_service_impl) << "procedure " << full_cls << "." << funcname << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol" << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; indent_impl(s_service_impl) << "var" << endl; indent_up_impl(); indent_impl(s_service_impl) << "args: " << args_intfnm << ";" << endl; if (!tfunction->is_oneway()) { indent_impl(s_service_impl) << "msg: Thrift.Protocol.TThriftMessage;" << endl; indent_impl(s_service_impl) << "ret: " << result_intfnm << ";" << endl; indent_impl(s_service_impl) << "appx : TApplicationException;" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "begin" << endl; indent_up_impl(); if (!tfunction->is_oneway()) { indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create;" << endl; } indent_impl(s_service_impl) << "try" << endl; indent_up_impl(); if (events_) { indent_impl(s_service_impl) << "if events <> nil then events.PreRead;" << endl; } indent_impl(s_service_impl) << "args := " << args_clsnm << "Impl.Create;" << endl; indent_impl(s_service_impl) << "args.Read(iprot);" << endl; indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl; if (events_) { indent_impl(s_service_impl) << "if events <> nil then events.PostRead;" << endl; } t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; s_service_impl << indent_impl(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { s_service_impl << "ret.Success := "; } s_service_impl << "iface_." << normalize_name(tfunction->get_name(), true) << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { s_service_impl << ", "; } s_service_impl << "args." << prop_name(*f_iter); } s_service_impl << ");" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent_impl(s_service_impl) << "args." << prop_name(*f_iter) << " := " << empty_value((*f_iter)->get_type()) << ";" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "except" << endl; indent_up_impl(); for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { indent_impl(s_service_impl) << "on E: " << type_name((*x_iter)->get_type(), true, true) << " do begin" << endl; indent_up_impl(); if (!tfunction->is_oneway()) { string factory_name = normalize_clsnm((*x_iter)->get_type()->get_name(), "", true) + "Factory"; indent_impl(s_service_impl) << "ret." << prop_name(*x_iter) << " := E." << factory_name << ";" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; } indent_impl(s_service_impl) << "on E: Exception do begin" << endl; indent_up_impl(); if(events_) { indent_impl(s_service_impl) << "if events <> nil then events.UnhandledError(E);" << endl; } if (!tfunction->is_oneway()) { indent_impl(s_service_impl) << "appx := TApplicationExceptionInternalError.Create(E.Message);" << endl; indent_impl(s_service_impl) << "try" << endl; indent_up_impl(); if(events_) { indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl; } indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '" << tfunction->get_name() << "', TMessageType.Exception, seqid);" << endl; indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl; indent_impl(s_service_impl) << "appx.Write(oprot);" << endl; indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; if(events_) { indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl; } indent_impl(s_service_impl) << "Exit;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "finally" << endl; indent_up_impl(); indent_impl(s_service_impl) << "appx.Free;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl; if (!tfunction->is_oneway()) { if (events_) { indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl; } indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '" << tfunction->get_name() << "', TMessageType.Reply, seqid); " << endl; indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg); " << endl; indent_impl(s_service_impl) << "ret.Write(oprot);" << endl; indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; if (events_) { indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl; } } else if (events_) { indent_impl(s_service_impl) << "if events <> nil then events.OnewayComplete;" << endl; } indent_down_impl(); indent_impl(s_service_impl) << "end;" << endl << endl; } void t_delphi_generator::generate_deserialize_field(ostream& out, bool is_xception, t_field* tfield, string prefix, ostream& local_vars) { t_type* type = tfield->get_type(); while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); } if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + prop_name(tfield, is_xception); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name, ""); } else if (type->is_container()) { generate_deserialize_container(out, is_xception, type, name, local_vars); } else if (type->is_base_type() || type->is_enum()) { indent_impl(out) << name << " := "; if (type->is_enum()) { out << type_name(type, false) << "("; } out << "iprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { if (ansistr_binary_) { out << "ReadAnsiString();"; } else { out << "ReadBinary();"; } } else { out << "ReadString();"; } break; case t_base_type::TYPE_BOOL: out << "ReadBool();"; break; case t_base_type::TYPE_I8: out << "ReadByte();"; break; case t_base_type::TYPE_I16: out << "ReadI16();"; break; case t_base_type::TYPE_I32: out << "ReadI32();"; break; case t_base_type::TYPE_I64: out << "ReadI64();"; break; case t_base_type::TYPE_DOUBLE: out << "ReadDouble();"; break; default: throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "ReadI32()"; out << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str()); } } void t_delphi_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string name, string prefix) { string typ_name; if (tstruct->is_xception()) { typ_name = type_name(tstruct, true, false, true, true); } else { typ_name = type_name(tstruct, true, false); } indent_impl(out) << prefix << name << " := " << typ_name << ".Create;" << endl; indent_impl(out) << prefix << name << ".Read(iprot);" << endl; } void t_delphi_generator::generate_deserialize_container(ostream& out, bool is_xception, t_type* ttype, string name, std::ostream& local_vars) { string obj; string counter; string local_var; if (ttype->is_map()) { obj = tmp("_map"); } else if (ttype->is_set()) { obj = tmp("_set"); } else if (ttype->is_list()) { obj = tmp("_list"); } if (ttype->is_map()) { local_var = obj + ": TThriftMap;"; } else if (ttype->is_set()) { local_var = obj + ": TThriftSet;"; } else if (ttype->is_list()) { local_var = obj + ": TThriftList;"; } local_vars << " " << local_var << endl; counter = tmp("_i"); local_var = counter + ": System.Integer;"; local_vars << " " << local_var << endl; indent_impl(out) << name << " := " << type_name(ttype, true) << ".Create;" << endl; if (ttype->is_map()) { indent_impl(out) << obj << " := iprot.ReadMapBegin();" << endl; } else if (ttype->is_set()) { indent_impl(out) << obj << " := iprot.ReadSetBegin();" << endl; } else if (ttype->is_list()) { indent_impl(out) << obj << " := iprot.ReadListBegin();" << endl; } indent_impl(out) << "for " << counter << " := 0 to " << obj << ".Count - 1 do begin" << endl; indent_up_impl(); if (ttype->is_map()) { generate_deserialize_map_element(out, is_xception, (t_map*)ttype, name, local_vars); } else if (ttype->is_set()) { generate_deserialize_set_element(out, is_xception, (t_set*)ttype, name, local_vars); } else if (ttype->is_list()) { generate_deserialize_list_element(out, is_xception, (t_list*)ttype, name, local_vars); } indent_down_impl(); indent_impl(out) << "end;" << endl; if (ttype->is_map()) { indent_impl(out) << "iprot.ReadMapEnd();" << endl; } else if (ttype->is_set()) { indent_impl(out) << "iprot.ReadSetEnd();" << endl; } else if (ttype->is_list()) { indent_impl(out) << "iprot.ReadListEnd();" << endl; } } void t_delphi_generator::generate_deserialize_map_element(ostream& out, bool is_xception, t_map* tmap, string prefix, ostream& local_vars) { string key = tmp("_key"); string val = tmp("_val"); string local_var; t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); local_vars << " " << declare_field(&fkey) << endl; local_vars << " " << declare_field(&fval) << endl; generate_deserialize_field(out, is_xception, &fkey, "", local_vars); generate_deserialize_field(out, is_xception, &fval, "", local_vars); indent_impl(out) << prefix << ".AddOrSetValue( " << key << ", " << val << ");" << endl; } void t_delphi_generator::generate_deserialize_set_element(ostream& out, bool is_xception, t_set* tset, string prefix, ostream& local_vars) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); local_vars << " " << declare_field(&felem) << endl; generate_deserialize_field(out, is_xception, &felem, "", local_vars); indent_impl(out) << prefix << ".Add(" << elem << ");" << endl; } void t_delphi_generator::generate_deserialize_list_element(ostream& out, bool is_xception, t_list* tlist, string prefix, ostream& local_vars) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); local_vars << " " << declare_field(&felem) << endl; generate_deserialize_field(out, is_xception, &felem, "", local_vars); indent_impl(out) << prefix << ".Add(" << elem << ");" << endl; } void t_delphi_generator::generate_serialize_field(ostream& out, bool is_xception, t_field* tfield, string prefix, ostream& local_vars) { (void)local_vars; t_type* type = tfield->get_type(); while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); } string name = prefix + prop_name(tfield, is_xception); if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, name, local_vars); } else if (type->is_container()) { generate_serialize_container(out, is_xception, type, name, local_vars); } else if (type->is_base_type() || type->is_enum()) { indent_impl(out) << "oprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { if (ansistr_binary_) { out << "WriteAnsiString("; } else { out << "WriteBinary("; } } else { out << "WriteString("; } out << name << ");"; break; case t_base_type::TYPE_BOOL: out << "WriteBool(" << name << ");"; break; case t_base_type::TYPE_I8: out << "WriteByte(" << name << ");"; break; case t_base_type::TYPE_I16: out << "WriteI16(" << name << ");"; break; case t_base_type::TYPE_I32: out << "WriteI32(" << name << ");"; break; case t_base_type::TYPE_I64: out << "WriteI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "WriteDouble(" << name << ");"; break; default: throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "WriteI32(System.Integer(" << name << "));"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str()); } } void t_delphi_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix, ostream& local_vars) { (void)local_vars; (void)tstruct; out << indent_impl() << prefix << ".Write(oprot);" << endl; } void t_delphi_generator::generate_serialize_container(ostream& out, bool is_xception, t_type* ttype, string prefix, ostream& local_vars) { string obj; if (ttype->is_map()) { obj = tmp("map"); local_vars << " " << obj << " : TThriftMap;" << endl; indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".Count);" << endl; indent_impl(out) << "oprot.WriteMapBegin( " << obj << ");" << endl; } else if (ttype->is_set()) { obj = tmp("set_"); local_vars << " " << obj << " : TThriftSet;" << endl; indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix << ".Count);" << endl; indent_impl(out) << "oprot.WriteSetBegin( " << obj << ");" << endl; } else if (ttype->is_list()) { obj = tmp("list_"); local_vars << " " << obj << " : TThriftList;" << endl; indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".Count);" << endl; indent_impl(out) << "oprot.WriteListBegin( " << obj << ");" << endl; } string iter = tmp("_iter"); if (ttype->is_map()) { local_vars << " " << iter << ": " << type_name(((t_map*)ttype)->get_key_type()) << ";" << endl; indent_impl(out) << "for " << iter << " in " << prefix << ".Keys do begin" << endl; indent_up_impl(); } else if (ttype->is_set()) { local_vars << " " << iter << ": " << type_name(((t_set*)ttype)->get_elem_type()) << ";" << endl; indent_impl(out) << "for " << iter << " in " << prefix << " do begin" << endl; indent_up_impl(); } else if (ttype->is_list()) { local_vars << " " << iter << ": " << type_name(((t_list*)ttype)->get_elem_type()) << ";" << endl; indent_impl(out) << "for " << iter << " in " << prefix << " do begin" << endl; indent_up_impl(); } if (ttype->is_map()) { generate_serialize_map_element(out, is_xception, (t_map*)ttype, iter, prefix, local_vars); } else if (ttype->is_set()) { generate_serialize_set_element(out, is_xception, (t_set*)ttype, iter, local_vars); } else if (ttype->is_list()) { generate_serialize_list_element(out, is_xception, (t_list*)ttype, iter, local_vars); } indent_down_impl(); indent_impl(out) << "end;" << endl; if (ttype->is_map()) { indent_impl(out) << "oprot.WriteMapEnd();" << endl; } else if (ttype->is_set()) { indent_impl(out) << "oprot.WriteSetEnd();" << endl; } else if (ttype->is_list()) { indent_impl(out) << "oprot.WriteListEnd();" << endl; } } void t_delphi_generator::generate_serialize_map_element(ostream& out, bool is_xception, t_map* tmap, string iter, string map, ostream& local_vars) { t_field kfield(tmap->get_key_type(), iter); generate_serialize_field(out, is_xception, &kfield, "", local_vars); t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); generate_serialize_field(out, is_xception, &vfield, "", local_vars); } void t_delphi_generator::generate_serialize_set_element(ostream& out, bool is_xception, t_set* tset, string iter, ostream& local_vars) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, is_xception, &efield, "", local_vars); } void t_delphi_generator::generate_serialize_list_element(ostream& out, bool is_xception, t_list* tlist, string iter, ostream& local_vars) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, is_xception, &efield, "", local_vars); } void t_delphi_generator::generate_property(ostream& out, t_field* tfield, bool isPublic, bool is_xception) { generate_delphi_property(out, is_xception, tfield, isPublic, "Get"); } void t_delphi_generator::generate_delphi_property(ostream& out, bool struct_is_xception, t_field* tfield, bool isPublic, std::string fieldPrefix) { (void)isPublic; t_type* ftype = tfield->get_type(); bool is_xception = ftype->is_xception(); generate_delphi_doc(out, tfield); indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": " << type_name(ftype, false, true, is_xception, true) << " read " << fieldPrefix + prop_name(tfield, struct_is_xception) << " write Set" << prop_name(tfield, struct_is_xception) << ";" << endl; } std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception) { return prop_name(tfield->get_name(), is_xception); } std::string t_delphi_generator::prop_name(string name, bool is_xception) { string ret = name; ret[0] = toupper(ret[0]); return normalize_name(ret, true, is_xception); } std::string t_delphi_generator::constructor_param_name(string name) { string ret = name; ret[0] = toupper(ret[0]); ret = "A" + ret; return normalize_name(ret, false, false); } string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) { if (clsnm.size() > 0) { clsnm[0] = toupper(clsnm[0]); } if (b_no_check_keyword) { return prefix + clsnm; } else { return normalize_name(prefix + clsnm); } } string t_delphi_generator::type_name(t_type* ttype, bool b_cls, bool b_no_postfix, bool b_exception_factory, bool b_full_exception_factory) { if (ttype->is_typedef()) { t_typedef* tdef = (t_typedef*)ttype; if (tdef->is_forward_typedef()) { // forward types according to THRIFT-2421 if (tdef->get_type() != nullptr) { return type_name(tdef->get_type(), b_cls, b_no_postfix, b_exception_factory, b_full_exception_factory); } else { throw "unresolved forward declaration: " + tdef->get_symbolic(); } } else { return normalize_name("T" + tdef->get_symbolic()); } } string typ_nm; string s_factory; if (ttype->is_base_type()) { return base_type_name((t_base_type*)ttype); } else if (ttype->is_enum()) { b_cls = true; b_no_postfix = true; } else if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; if (b_cls) { typ_nm = "TThriftDictionaryImpl"; } else { typ_nm = "IThriftDictionary"; } return typ_nm + "<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type()) + ">"; } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; if (b_cls) { typ_nm = "THashSetImpl"; } else { typ_nm = "IHashSet"; } return typ_nm + "<" + type_name(tset->get_elem_type()) + ">"; } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; if (b_cls) { typ_nm = "TThriftListImpl"; } else { typ_nm = "IThriftList"; } return typ_nm + "<" + type_name(tlist->get_elem_type()) + ">"; } string type_prefix; if (b_cls) { type_prefix = "T"; } else { type_prefix = "I"; } string nm = normalize_clsnm(ttype->get_name(), type_prefix); if (b_exception_factory) { nm = nm + "Factory"; } if (b_cls) { if (!b_no_postfix) { nm = nm + "Impl"; } } if (b_exception_factory && b_full_exception_factory) { return type_name(ttype, true, true, false, false) + "." + nm; } return nm; } // returns "const " for some argument types string t_delphi_generator::input_arg_prefix(t_type* ttype) { // base types if (ttype->is_base_type()) { switch (((t_base_type*)ttype)->get_base()) { // these should be const'ed for optimal performamce case t_base_type::TYPE_STRING: // refcounted pointer case t_base_type::TYPE_I64: // larger than 32 bit case t_base_type::TYPE_DOUBLE: // larger than 32 bit return "const "; // all others don't need to be case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_BOOL: case t_base_type::TYPE_VOID: return ""; // we better always report any unknown types default: throw "compiler error: no input_arg_prefix() for base type " + t_base_type::t_base_name(((t_base_type*)ttype)->get_base()); } // enums } else if (ttype->is_enum()) { return ""; // usually <= 32 bit // containers } else if (ttype->is_map()) { return "const "; // refcounted pointer } else if (ttype->is_set()) { return "const "; // refcounted pointer } else if (ttype->is_list()) { return "const "; // refcounted pointer } // any other type, either TSomething or ISomething return "const "; // possibly refcounted pointer } string t_delphi_generator::base_type_name(t_base_type* tbase) { switch (tbase->get_base()) { case t_base_type::TYPE_VOID: // no "void" in Delphi language return ""; case t_base_type::TYPE_STRING: if (tbase->is_binary()) { if (ansistr_binary_) { return "System.AnsiString"; } else { return "SysUtils.TBytes"; } } else { return "System.string"; } case t_base_type::TYPE_BOOL: return "System.Boolean"; case t_base_type::TYPE_I8: return "System.ShortInt"; case t_base_type::TYPE_I16: return "System.SmallInt"; case t_base_type::TYPE_I32: return "System.Integer"; case t_base_type::TYPE_I64: return "System.Int64"; case t_base_type::TYPE_DOUBLE: return "System.Double"; default: throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase->get_base()); } } string t_delphi_generator::declare_field(t_field* tfield, bool init, std::string prefix, bool is_xception_class) { (void)init; t_type* ftype = tfield->get_type(); bool is_xception = ftype->is_xception(); string result = prefix + prop_name(tfield, is_xception_class) + ": " + type_name(ftype, false, true, is_xception, true) + ";"; return result; } string t_delphi_generator::function_signature(t_function* tfunction, bool for_async, std::string full_cls, bool is_xception) { t_type* ttype = tfunction->get_returntype(); string prefix; if (full_cls == "") { prefix = ""; } else { prefix = full_cls + "."; } string signature = ""; if( for_async) { if (is_void(ttype)) { signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async(" + argument_list(tfunction->get_arglist()) + "): IFuture;"; // no IFuture in Delphi } else { signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async(" + argument_list(tfunction->get_arglist()) + "): IFuture<" + type_name(ttype, false, true, is_xception, true) + ">;"; } } else { if (is_void(ttype)) { signature = "procedure " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "(" + argument_list(tfunction->get_arglist()) + ");"; } else { signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "(" + argument_list(tfunction->get_arglist()) + "): " + type_name(ttype, false, true, is_xception, true) + ";"; } } // deprecated method? only at intf decl! if( full_cls == "") { auto iter = tfunction->annotations_.find("deprecated"); if( tfunction->annotations_.end() != iter) { signature += " deprecated"; // empty annotation values end up with "1" somewhere, ignore these as well if ((iter->second.length() > 0) && (iter->second != "1")) { signature += " " + make_pascal_string_literal(iter->second); } signature += ";"; } } return signature; } string t_delphi_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; t_type* tt; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += "; "; } tt = (*f_iter)->get_type(); result += input_arg_prefix(tt); // const? result += normalize_name((*f_iter)->get_name()) + ": " + type_name(tt, false, true, tt->is_xception(), true); } return result; } string t_delphi_generator::constructor_argument_list(t_struct* tstruct, string current_indent) { ostringstream result; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; t_type* tt; string line = ""; string newline_indent = current_indent + " "; bool firstline = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { line += ";"; } if (line.size() > 80) { if (firstline) { result << endl << newline_indent; firstline = false; } result << line << endl; line = newline_indent; } else if (line.size() > 0) { line += " "; } tt = (*f_iter)->get_type(); line += input_arg_prefix(tt); // const? line += constructor_param_name((*f_iter)->get_name()) + ": " + type_name(tt, false, true, tt->is_xception(), true); } if (line.size() > 0) { result << line; } string result_str; if (firstline) { result_str = " " + result.str(); } else { result_str = result.str(); } return result_str; } string t_delphi_generator::type_to_enum(t_type* type) { while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); } if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.String_"; case t_base_type::TYPE_BOOL: return "TType.Bool_"; case t_base_type::TYPE_I8: return "TType.Byte_"; case t_base_type::TYPE_I16: return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.Double_"; } } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "TType.Struct"; } else if (type->is_map()) { return "TType.Map"; } else if (type->is_set()) { return "TType.Set_"; } else if (type->is_list()) { return "TType.List"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } string t_delphi_generator::empty_value(t_type* type) { while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); } if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "0"; case t_base_type::TYPE_STRING: if (type->is_binary()) { if (ansistr_binary_) { return "''"; } else { return "nil"; } } else { return "''"; } case t_base_type::TYPE_BOOL: return "False"; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: return "0"; case t_base_type::TYPE_DOUBLE: return "0.0"; } } else if (type->is_enum()) { return "T" + type->get_name() + "(0)"; } else if (type->is_struct() || type->is_xception()) { return "nil"; } else if (type->is_map()) { return "nil"; } else if (type->is_set()) { return "nil"; } else if (type->is_list()) { return "nil"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } void t_delphi_generator::generate_delphi_property_writer_definition(ostream& out, t_field* tfield, bool is_xception_class) { t_type* ftype = tfield->get_type(); bool is_xception = ftype->is_xception(); indent(out) << "procedure Set" << prop_name(tfield, is_xception_class) << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");" << endl; } void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out, t_field* tfield, bool is_xception_class) { t_type* ftype = tfield->get_type(); bool is_xception = ftype->is_xception(); indent(out) << "function Get" << prop_name(tfield, is_xception_class) << ": " << type_name(ftype, false, true, is_xception, true) << ";" << endl; } void t_delphi_generator::generate_delphi_isset_reader_writer_definition(ostream& out, t_field* tfield, bool is_xception) { indent(out) << "function Get__isset_" << prop_name(tfield, is_xception) << ": System.Boolean;" << endl; indent(out) << "procedure Set__isset_" << prop_name(tfield, is_xception) << "( const value : System.Boolean);" << endl; } void t_delphi_generator::generate_delphi_clear_union_value(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factory_name) { (void)cls_prefix; (void)name; (void)type; (void)is_union; (void)is_xception_factory; (void)xception_factory_name; t_type* ftype = tfield->get_type(); bool is_xception = ftype->is_xception(); indent_impl(out) << "if F__isset_" << prop_name(tfield, is_xception_class) << " then begin" << endl; indent_up_impl(); indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl; indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := " << "Default( " << type_name(ftype, false, true, is_xception, true) << ");" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl; } void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factory_name) { (void)type; t_type* ftype = tfield->get_type(); bool is_xception = ftype->is_xception(); indent_impl(out) << "procedure " << cls_prefix << name << "." << "Set" << prop_name(tfield, is_xception_class) << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); if (is_union) { indent_impl(out) << "ClearUnionValues;" << endl; } if (tfield->get_req() != t_field::T_REQUIRED) { indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := True;" << endl; } indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := Value;" << endl; if (is_xception_class && (!is_xception_factory)) { indent_impl(out) << xception_factory_name << "." << prop_name(tfield, is_xception_class) << " := Value;" << endl; } indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } void t_delphi_generator::generate_delphi_property_reader_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class) { (void)type; t_type* ftype = tfield->get_type(); bool is_xception = ftype->is_xception(); indent_impl(out) << "function " << cls_prefix << name << "." << "Get" << prop_name(tfield, is_xception_class) << ": " << type_name(ftype, false, true, is_xception, true) << ";" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "Result := " << fieldPrefix << prop_name(tfield, is_xception_class) << ";" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } void t_delphi_generator::generate_delphi_isset_reader_writer_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception) { (void)type; string isset_name = "__isset_" + prop_name(tfield, is_xception); indent_impl(out) << "function " << cls_prefix << name << "." << "Get" << isset_name << ": System.Boolean;" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "Result := " << fieldPrefix << isset_name << ";" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; indent_impl(out) << "procedure " << cls_prefix << name << "." << "Set" << isset_name << "( const value: System.Boolean);" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << fieldPrefix << isset_name << " := value;" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } void t_delphi_generator::generate_delphi_create_exception_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception) { (void)cls_prefix; string exception_cls_nm = type_name(tstruct, true, true); string cls_nm = type_name(tstruct, true, false, is_exception, is_exception); indent_impl(out) << "function " << cls_nm << ".CreateException: " << exception_cls_nm << ";" << endl; indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << "Result := " << exception_cls_nm << ".Create;" << endl; string factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; indent_impl(out) << "Result.F" << factory_name << " := Self;" << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; string propname; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { propname = prop_name(*f_iter, is_exception); if ((*f_iter)->get_req() != t_field::T_REQUIRED) { indent_impl(out) << "if __isset_" << propname << " then begin" << endl; indent_up_impl(); } indent_impl(out) << "Result." << propname << " := " << propname << ";" << endl; if ((*f_iter)->get_req() != t_field::T_REQUIRED) { indent_down_impl(); indent_impl(out) << "end;" << endl; } } indent_impl(out) << "Result.UpdateMessageProperty;" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory) { ostringstream local_vars; ostringstream code_block; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; indent_impl(code_block) << "begin" << endl; indent_up_impl(); indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; indent_impl(code_block) << "tracker := iprot.NextRecursionLevel;" << endl; // local bools for required fields for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { indent_impl(local_vars) << "_req_isset_" << prop_name(*f_iter, is_exception) << " : System.Boolean;" << endl; indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := FALSE;" << endl; } } indent_impl(code_block) << "struc := iprot.ReadStructBegin;" << endl; indent_impl(code_block) << "try" << endl; indent_up_impl(); indent_impl(code_block) << "while (true) do begin" << endl; indent_up_impl(); indent_impl(code_block) << "field_ := iprot.ReadFieldBegin();" << endl; indent_impl(code_block) << "if (field_.Type_ = TType.Stop) then Break;" << endl; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { code_block << endl; indent_impl(code_block) << "case field_.ID of" << endl; indent_up_impl(); } first = false; if (f_iter != fields.begin()) { code_block << endl; } indent_impl(code_block) << (*f_iter)->get_key() << ": begin" << endl; indent_up_impl(); indent_impl(code_block) << "if (field_.Type_ = " << type_to_enum((*f_iter)->get_type()) << ") then begin" << endl; indent_up_impl(); generate_deserialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); // required field? if ((*f_iter)->get_req() == t_field::T_REQUIRED) { indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := TRUE;" << endl; } indent_down_impl(); indent_impl(code_block) << "end else begin" << endl; indent_up_impl(); indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl; indent_down_impl(); indent_impl(code_block) << "end;" << endl; indent_down_impl(); indent_impl(code_block) << "end;"; } if (!first) { code_block << endl; indent_down_impl(); indent_impl(code_block) << "else" << endl; indent_up_impl(); } indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl; if (!first) { indent_down_impl(); indent_impl(code_block) << "end;" << endl; } indent_impl(code_block) << "iprot.ReadFieldEnd;" << endl; indent_down_impl(); indent_impl(code_block) << "end;" << endl; indent_down_impl(); indent_impl(code_block) << "finally" << endl; indent_up_impl(); indent_impl(code_block) << "iprot.ReadStructEnd;" << endl; indent_down_impl(); indent_impl(code_block) << "end;" << endl; // all required fields have been read? first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { if(first) { code_block << endl; first = false; } indent_impl(code_block) << "if not _req_isset_" << prop_name(*f_iter, is_exception) << endl; indent_impl(code_block) << "then raise TProtocolExceptionInvalidData.Create(" << "'required field " << prop_name(*f_iter, is_exception) << " not set');" << endl; } } if( is_exception && (!is_x_factory)) { code_block << endl; indent_impl(code_block) << "UpdateMessageProperty;" << endl; } indent_down_impl(); indent_impl(code_block) << "end;" << endl << endl; string cls_nm; cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory); indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Read( const iprot: IProtocol);" << endl; indent_impl(out) << "var" << endl; indent_up_impl(); indent_impl(out) << "field_ : TThriftField;" << endl; indent_impl(out) << "struc : TThriftStruct;" << endl; indent_down_impl(); out << local_vars.str() << endl; out << code_block.str(); } void t_delphi_generator::generate_delphi_struct_result_writer_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory) { ostringstream local_vars; ostringstream code_block; string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent_impl(code_block) << "begin" << endl; indent_up_impl(); indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl; indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl; indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl; if (fields.size() > 0) { indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then" << endl; indent_impl(code_block) << "begin" << endl; indent_up_impl(); indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl; indent_impl(code_block) << "field_.Type_ := " << type_to_enum((*f_iter)->get_type()) << ";" << endl; indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl; indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl; generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl; indent_down_impl(); } } indent_impl(code_block) << "oprot.WriteFieldStop();" << endl; indent_impl(code_block) << "oprot.WriteStructEnd();" << endl; indent_down_impl(); indent_impl(code_block) << "end;" << endl << endl; string cls_nm; cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory); indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" << endl; indent_impl(out) << "var" << endl; indent_up_impl(); indent_impl(out) << "struc : TThriftStruct;" << endl; if (fields.size() > 0) { indent_impl(out) << "field_ : TThriftField;" << endl; } out << local_vars.str(); indent_down_impl(); out << code_block.str(); } void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory) { ostringstream local_vars; ostringstream code_block; string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent_impl(code_block) << "begin" << endl; indent_up_impl(); indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl; indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl; indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl; if (fields.size() > 0) { indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl; } for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { string fieldname = prop_name((*f_iter), is_exception); bool null_allowed = type_can_be_null((*f_iter)->get_type()); bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED); bool has_isset = (!is_required); if (is_required && null_allowed) { null_allowed = false; indent_impl(code_block) << "if (Self." << fieldname << " = nil)" << endl; indent_impl(code_block) << "then raise TProtocolExceptionInvalidData.Create(" << "'required field " << fieldname << " not set');" << endl; } if (null_allowed) { indent_impl(code_block) << "if (Self." << fieldname << " <> nil)"; if (has_isset) { code_block << " and __isset_" << fieldname; } code_block << " then begin" << endl; indent_up_impl(); } else { if (has_isset) { indent_impl(code_block) << "if (__isset_" << fieldname << ") then begin" << endl; indent_up_impl(); } } indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl; indent_impl(code_block) << "field_.Type_ := " << type_to_enum((*f_iter)->get_type()) << ";" << endl; indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl; indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl; generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl; if (null_allowed || has_isset) { indent_down_impl(); indent_impl(code_block) << "end;" << endl; } } indent_impl(code_block) << "oprot.WriteFieldStop();" << endl; indent_impl(code_block) << "oprot.WriteStructEnd();" << endl; indent_down_impl(); indent_impl(code_block) << "end;" << endl << endl; string cls_nm; cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory); indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" << endl; indent_impl(out) << "var" << endl; indent_up_impl(); indent_impl(out) << "struc : TThriftStruct;" << endl; if (fields.size() > 0) { indent_impl(out) << "field_ : TThriftField;" << endl; } out << local_vars.str(); indent_down_impl(); out << code_block.str(); } void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; string cls_nm; if (is_exception) { cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true); } else { cls_nm = type_name(tstruct, true, false); } string tmp_sb = tmp("_sb"); string tmp_first = tmp("_first"); bool useFirstFlag = false; indent_impl(out) << "function " << cls_prefix << cls_nm << ".ToString: string;" << endl; indent_impl(out) << "var" << endl; indent_up_impl(); indent_impl(out) << tmp_sb << " : TThriftStringBuilder;" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED); if (is_optional) { indent_impl(out) << tmp_first << " : System.Boolean;" << endl; useFirstFlag = true; } break; } indent_down_impl(); indent_impl(out) << "begin" << endl; indent_up_impl(); indent_impl(out) << tmp_sb << " := TThriftStringBuilder.Create('(');" << endl; indent_impl(out) << "try" << endl; indent_up_impl(); if (useFirstFlag) { indent_impl(out) << tmp_first << " := TRUE;" << endl; } bool had_required = false; // set to true after first required field has been processed for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool null_allowed = type_can_be_null((*f_iter)->get_type()); bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED); if (null_allowed) { indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)"; if (is_optional) { out << " and __isset_" << prop_name(*f_iter, is_exception); } out << " then begin" << endl; indent_up_impl(); } else { if (is_optional) { indent_impl(out) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then begin" << endl; indent_up_impl(); } } if (useFirstFlag && (!had_required)) { indent_impl(out) << "if not " << tmp_first << " then " << tmp_sb << ".Append(',');" << endl; if (is_optional) { indent_impl(out) << tmp_first << " := FALSE;" << endl; } indent_impl(out) << tmp_sb << ".Append('" << prop_name((*f_iter), is_exception) << ": ');" << endl; } else { indent_impl(out) << tmp_sb << ".Append(', " << prop_name((*f_iter), is_exception) << ": ');" << endl; } t_type* ttype = (*f_iter)->get_type(); while (ttype->is_typedef()) { ttype = ((t_typedef*)ttype)->get_type(); } if (ttype->is_xception() || ttype->is_struct()) { indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " = nil) then " << tmp_sb << ".Append('') else " << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ".ToString());" << endl; } else if (ttype->is_enum()) { indent_impl(out) << tmp_sb << ".Append(EnumUtils<" << type_name(ttype, false, true, false, false) << ">.ToString( System.Ord( Self." << prop_name((*f_iter), is_exception) << ")));" << endl; } else { indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");" << endl; } if (null_allowed || is_optional) { indent_down_impl(); indent_impl(out) << "end;" << endl; } if (!is_optional) { had_required = true; // now __first must be false, so we don't need to check it anymore } } indent_impl(out) << tmp_sb << ".Append(')');" << endl; indent_impl(out) << "Result := " << tmp_sb << ".ToString;" << endl; if (useFirstFlag) { indent_impl(out) << "if " << tmp_first << " then {prevent warning};" << endl; } indent_down_impl(); indent_impl(out) << "finally" << endl; indent_up_impl(); indent_impl(out) << tmp_sb << ".Free;" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl; indent_down_impl(); indent_impl(out) << "end;" << endl << endl; } bool t_delphi_generator::is_void(t_type* type) { while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); } if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); if (tbase == t_base_type::TYPE_VOID) { return true; } } return false; } THRIFT_REGISTER_GENERATOR( delphi, "delphi", " ansistr_binary: Use AnsiString for binary datatype (default is TBytes).\n" " register_types: Enable TypeRegistry, allows for creation of struct, union\n" " and container instances by interface or TypeInfo()\n" " constprefix: Name TConstants classes after IDL to reduce ambiguities\n" " events: Enable and use processing events in the generated code.\n" " xmldoc: Enable XMLDoc comments for Help Insight etc.\n" " async: Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_erl_generator.cc000066400000000000000000001173261420101504100250330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const std::string endl = "\n"; // avoid ostream << std::endl flushes /** * Erlang code generator. * */ class t_erl_generator : public t_generator { public: t_erl_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; legacy_names_ = false; delimiter_ = "."; app_prefix_ = ""; maps_ = false; export_lines_first_ = true; export_types_lines_first_ = true; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("legacynames") == 0) { legacy_names_ = true; } else if( iter->first.compare("maps") == 0) { maps_ = true; } else if( iter->first.compare("delimiter") == 0) { delimiter_ = iter->second; } else if( iter->first.compare("app_prefix") == 0) { app_prefix_ = iter->second; } else { throw "unknown option erl:" + iter->first; } } out_dir_base_ = "gen-erl"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void generate_member_type(std::ostream& out, t_type* type); void generate_member_value(std::ostream& out, t_type* type, t_const_value* value); std::string render_member_type(t_field* field); std::string render_member_value(t_field* field); std::string render_member_requiredness(t_field* field); // std::string render_default_value(t_type* type); std::string render_default_value(t_field* field); std::string render_const_value(t_type* type, t_const_value* value); std::string render_type_term(t_type* ttype, bool expand_structs, bool extended_info = false); /** * Struct generation code */ void generate_erl_struct(t_struct* tstruct, bool is_exception); void generate_erl_struct_definition(std::ostream& out, t_struct* tstruct); void generate_erl_struct_member(std::ostream& out, t_field* tmember); void generate_erl_struct_info(std::ostream& out, t_struct* tstruct); void generate_erl_extended_struct_info(std::ostream& out, t_struct* tstruct); void generate_erl_function_helpers(t_function* tfunction); void generate_type_metadata(std::string function_name, vector names); void generate_enum_info(t_enum* tenum); void generate_enum_metadata(); void generate_const_function(t_const* tconst, ostringstream& exports, ostringstream& functions); void generate_const_functions(); /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_metadata(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_function_info(t_service* tservice, t_function* tfunction); /** * Helper rendering functions */ std::string erl_autogen_comment(); std::string erl_imports(); std::string render_includes(); std::string type_name(t_type* ttype); std::string render_const_list_values(t_type* type, t_const_value* value); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string type_module(t_type* ttype); std::string make_safe_for_module_name(std::string in) { if (legacy_names_) { return decapitalize(app_prefix_ + in); } else { return underscore(app_prefix_) + underscore(in); } } std::string atomify(std::string in) { if (legacy_names_) { return "'" + decapitalize(in) + "'"; } else { return "'" + in + "'"; } } std::string constify(std::string in) { if (legacy_names_) { return capitalize(in); } else { return uppercase(in); } } static std::string comment(string in); private: bool has_default_value(t_field*); /* if true retain pre 0.9.2 naming scheme for functions, atoms and consts */ bool legacy_names_; /* if true use maps instead of dicts in generated code */ bool maps_; /* delimiter between namespace and record name */ std::string delimiter_; /* used to avoid module name clashes for different applications */ std::string app_prefix_; /** * add function to export list */ void export_function(t_function* tfunction, std::string prefix = ""); void export_string(std::string name, int num); void export_types_string(std::string name, int num); /** * write out headers and footers for hrl files */ void hrl_header(std::ostream& out, std::string name); void hrl_footer(std::ostream& out, std::string name); /** * stuff to spit out at the top of generated files */ bool export_lines_first_; std::ostringstream export_lines_; bool export_types_lines_first_; std::ostringstream export_types_lines_; /** * File streams */ std::ostringstream f_info_; std::ostringstream f_info_ext_; ofstream_with_content_based_conditional_update f_types_file_; ofstream_with_content_based_conditional_update f_types_hrl_file_; ofstream_with_content_based_conditional_update f_consts_file_; ofstream_with_content_based_conditional_update f_consts_hrl_file_; std::ostringstream f_service_; ofstream_with_content_based_conditional_update f_service_file_; ofstream_with_content_based_conditional_update f_service_hrl_; /** * Metadata containers */ std::vector v_struct_names_; std::vector v_enum_names_; std::vector v_exception_names_; std::vector v_enums_; std::vector v_consts_; }; /** * UI for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_erl_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); // setup export lines export_lines_first_ = true; export_types_lines_first_ = true; string program_module_name = make_safe_for_module_name(program_name_); // types files string f_types_name = get_out_dir() + program_module_name + "_types.erl"; string f_types_hrl_name = get_out_dir() + program_module_name + "_types.hrl"; f_types_file_.open(f_types_name.c_str()); f_types_hrl_file_.open(f_types_hrl_name.c_str()); hrl_header(f_types_hrl_file_, program_module_name + "_types"); f_types_file_ << erl_autogen_comment() << endl << "-module(" << program_module_name << "_types)." << endl << erl_imports() << endl; f_types_file_ << "-include(\"" << program_module_name << "_types.hrl\")." << endl << endl; f_types_hrl_file_ << render_includes() << endl; // consts files string f_consts_name = get_out_dir() + program_module_name + "_constants.erl"; string f_consts_hrl_name = get_out_dir() + program_module_name + "_constants.hrl"; f_consts_file_.open(f_consts_name.c_str()); f_consts_hrl_file_.open(f_consts_hrl_name.c_str()); f_consts_file_ << erl_autogen_comment() << endl << "-module(" << program_module_name << "_constants)." << endl << erl_imports() << endl << "-include(\"" << program_module_name << "_types.hrl\")." << endl << endl; f_consts_hrl_file_ << erl_autogen_comment() << endl << erl_imports() << endl << "-include(\"" << program_module_name << "_types.hrl\")." << endl << endl; } /** * Boilerplate at beginning and end of header files */ void t_erl_generator::hrl_header(ostream& out, string name) { out << erl_autogen_comment() << endl << "-ifndef(_" << name << "_included)." << endl << "-define(_" << name << "_included, yeah)." << endl; } void t_erl_generator::hrl_footer(ostream& out, string name) { (void)name; out << "-endif." << endl; } /** * Renders all the imports necessary for including another Thrift program */ string t_erl_generator::render_includes() { const vector& includes = program_->get_includes(); string result = ""; for (auto include : includes) { result += "-include(\"" + make_safe_for_module_name(include->get_name()) + "_types.hrl\").\n"; } if (includes.size() > 0) { result += "\n"; } return result; } /** * Autogen'd comment */ string t_erl_generator::erl_autogen_comment() { return std::string("%%\n") + "%% Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "%%\n" + "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "%%\n"; } /** * Comment out text */ string t_erl_generator::comment(string in) { size_t pos = 0; in.insert(pos, "%% "); while ((pos = in.find_first_of('\n', pos)) != string::npos) { in.insert(++pos, "%% "); } return in; } /** * Prints standard thrift imports */ string t_erl_generator::erl_imports() { return ""; } /** * Closes the type files */ void t_erl_generator::close_generator() { export_types_string("struct_info", 1); export_types_string("struct_info_ext", 1); export_types_string("enum_info", 1); export_types_string("enum_names", 0); export_types_string("struct_names", 0); export_types_string("exception_names", 0); f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl << endl; f_types_file_ << f_info_.str(); f_types_file_ << "struct_info(_) -> erlang:error(function_clause)." << endl << endl; f_types_file_ << f_info_ext_.str(); f_types_file_ << "struct_info_ext(_) -> erlang:error(function_clause)." << endl << endl; generate_const_functions(); generate_type_metadata("struct_names", v_struct_names_); generate_enum_metadata(); generate_type_metadata("enum_names", v_enum_names_); generate_type_metadata("exception_names", v_exception_names_); hrl_footer(f_types_hrl_file_, string("BOGUS")); f_types_file_.close(); f_types_hrl_file_.close(); f_consts_file_.close(); f_consts_hrl_file_.close(); } const std::string emit_double_as_string(const double value) { std::stringstream double_output_stream; // sets the maximum precision: http://en.cppreference.com/w/cpp/io/manip/setprecision // sets the output format to fixed: http://en.cppreference.com/w/cpp/io/manip/fixed (not in scientific notation) double_output_stream << std::setprecision(std::numeric_limits::digits10 + 1); #ifdef _MSC_VER // strtod is broken in MSVC compilers older than 2015, so std::fixed fails to format a double literal. // more details: https://blogs.msdn.microsoft.com/vcblog/2014/06/18/ // c-runtime-crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1/ // and // http://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/ #if _MSC_VER >= MSC_2015_VER double_output_stream << std::fixed; #else // note that if this function is called from the erlang generator and the MSVC compiler is older than 2015, // the double literal must be output in the scientific format. There can be some cases where the // mantissa of the output does not have fractionals, which is illegal in Erlang. // example => 10000000000000000.0 being output as 1e+16 double_output_stream << std::scientific; #endif #else double_output_stream << std::fixed; #endif double_output_stream << value; return double_output_stream.str(); } void t_erl_generator::generate_type_metadata(std::string function_name, vector names) { size_t num_structs = names.size(); indent(f_types_file_) << function_name << "() ->\n"; indent_up(); indent(f_types_file_) << "["; for(size_t i=0; i < num_structs; i++) { f_types_file_ << names.at(i); if (i < num_structs - 1) { f_types_file_ << ", "; } } f_types_file_ << "].\n\n"; indent_down(); } /** * Generates a typedef. no op * * @param ttypedef The type definition */ void t_erl_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } void t_erl_generator::generate_const_function(t_const* tconst, ostringstream& exports, ostringstream& functions) { t_type* type = get_true_type(tconst->get_type()); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); string const_fun_name = lowercase(name); // Emit const function export. if (exports.tellp() > 0) { exports << ", "; } exports << const_fun_name << "/1, " << const_fun_name << "/2"; // Emit const function definition. map::const_iterator i, end = value->get_map().end(); // The one-argument form throws an error if the key does not exist in the map. for (i = value->get_map().begin(); i != end;) { functions << const_fun_name << "(" << render_const_value(ktype, i->first) << ") -> " << render_const_value(vtype, i->second); ++i; functions << (i != end ? ";\n" : ".\n\n"); } // The two-argument form returns a default value if the key does not exist in the map. for (i = value->get_map().begin(); i != end; ++i) { functions << const_fun_name << "(" << render_const_value(ktype, i->first) << ", _) -> " << render_const_value(vtype, i->second) << ";\n"; } functions << const_fun_name << "(_, Default) -> Default.\n\n"; } else if (type->is_list()) { string const_fun_name = lowercase(name); if (exports.tellp() > 0) { exports << ", "; } exports << const_fun_name << "/1, " << const_fun_name << "/2"; size_t list_size = value->get_list().size(); string rendered_list = render_const_list_values(type, value); functions << const_fun_name << "(N) when N >= 1, N =< " << list_size << " ->\n" << indent_str() << "element(N, {" << rendered_list << "}).\n"; functions << const_fun_name << "(N, _) when N >= 1, N =< " << list_size << " ->\n" << indent_str() << "element(N, {" << rendered_list << "});\n" << const_fun_name << "(_, Default) -> Default.\n\n"; indent_down(); } } void t_erl_generator::generate_const_functions() { ostringstream exports; ostringstream functions; vector::iterator c_iter; for (c_iter = v_consts_.begin(); c_iter != v_consts_.end(); ++c_iter) { generate_const_function(*c_iter, exports, functions); } if (exports.tellp() > 0) { f_consts_file_ << "-export([" << exports.str() << "]).\n\n" << functions.str(); } } /** * Generates code for an enumerated type. Done using a class to scope * the values. * * @param tenum The enumeration */ void t_erl_generator::generate_enum(t_enum* tenum) { vector constants = tenum->get_constants(); vector::iterator c_iter; v_enums_.push_back(tenum); v_enum_names_.push_back(atomify(tenum->get_name())); for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); string name = (*c_iter)->get_name(); indent(f_types_hrl_file_) << "-define(" << constify(make_safe_for_module_name(program_name_)) << "_" << constify(tenum->get_name()) << "_" << constify(name) << ", " << value << ")." << endl; } f_types_hrl_file_ << endl; } void t_erl_generator::generate_enum_info(t_enum* tenum){ vector constants = tenum->get_constants(); size_t num_constants = constants.size(); indent(f_types_file_) << "enum_info(" << atomify(tenum->get_name()) << ") ->\n"; indent_up(); indent(f_types_file_) << "[\n"; for(size_t i=0; i < num_constants; i++) { indent_up(); t_enum_value* value = constants.at(i); indent(f_types_file_) << "{" << atomify(value->get_name()) << ", " << value->get_value() << "}"; if (i < num_constants - 1) { f_types_file_ << ",\n"; } indent_down(); } f_types_file_ << "\n"; indent(f_types_file_) << "];\n\n"; indent_down(); } void t_erl_generator::generate_enum_metadata() { size_t enum_count = v_enums_.size(); for(size_t i=0; i < enum_count; i++) { t_enum* tenum = v_enums_.at(i); generate_enum_info(tenum); } indent(f_types_file_) << "enum_info(_) -> erlang:error(function_clause).\n\n"; } /** * Generate a constant value */ void t_erl_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); // Save the tconst so that function can be emitted in generate_const_functions(). v_consts_.push_back(tconst); f_consts_hrl_file_ << "-define(" << constify(make_safe_for_module_name(program_name_)) << "_" << constify(name) << ", " << render_const_value(type, value) << ")." << endl << endl; } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_erl_generator::render_const_value(t_type* type, t_const_value* value) { type = get_true_type(type); std::ostringstream out; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << "float(" << value->get_integer() << ")"; } else { out << emit_double_as_string(value->get_double()); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { indent(out) << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << "#" << type_name(type) << "{"; const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; bool first = true; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } if (first) { first = false; } else { out << ","; } out << v_iter->first->get_string(); out << " = "; out << render_const_value(field_type, v_iter->second); } indent_down(); indent(out) << "}"; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); if (maps_) { out << "maps:from_list(["; } else { out << "dict:from_list(["; } map::const_iterator i, end = value->get_map().end(); for (i = value->get_map().begin(); i != end;) { out << "{" << render_const_value(ktype, i->first) << "," << render_const_value(vtype, i->second) << "}"; if (++i != end) { out << ","; } } out << "])"; } else if (type->is_set()) { t_type* etype = ((t_set*)type)->get_elem_type(); out << "sets:from_list(["; vector::const_iterator i, end = value->get_list().end(); for (i = value->get_list().begin(); i != end;) { out << render_const_value(etype, *i); if (++i != end) { out << ","; } } out << "])"; } else if (type->is_list()) { out << "[" << render_const_list_values(type, value) << "]"; } else { throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); } return out.str(); } string t_erl_generator::render_const_list_values(t_type* type, t_const_value* value) { std::ostringstream out; t_type* etype = ((t_list*)type)->get_elem_type(); bool first = true; const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { if (first) { first = false; } else { out << ","; } out << render_const_value(etype, *v_iter); } return out.str(); } string t_erl_generator::render_default_value(t_field* field) { t_type* type = field->get_type(); if (type->is_struct() || type->is_xception()) { return "#" + type_name(type) + "{}"; } else if (type->is_map()) { if (maps_) { return "#{}"; } else { return "dict:new()"; } } else if (type->is_set()) { return "sets:new()"; } else if (type->is_list()) { return "[]"; } else { return "undefined"; } } string t_erl_generator::render_member_type(t_field* field) { t_type* type = get_true_type(field->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: return "string() | binary()"; case t_base_type::TYPE_BOOL: return "boolean()"; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: return "integer()"; case t_base_type::TYPE_DOUBLE: return "float()"; default: throw "compiler error: unsupported base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { return "integer()"; } else if (type->is_struct() || type->is_xception()) { return type_name(type) + "()"; } else if (type->is_map()) { if (maps_) { return "map()"; } else { return "dict:dict()"; } } else if (type->is_set()) { return "sets:set()"; } else if (type->is_list()) { return "list()"; } else { throw "compiler error: unsupported type " + type->get_name(); } } string t_erl_generator::render_member_requiredness(t_field* field) { switch (field->get_req()) { case t_field::T_REQUIRED: return "required"; case t_field::T_OPTIONAL: return "optional"; default: return "undefined"; } } /** * Generates a struct */ void t_erl_generator::generate_struct(t_struct* tstruct) { v_struct_names_.push_back(type_name(tstruct)); generate_erl_struct(tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_erl_generator::generate_xception(t_struct* txception) { v_exception_names_.push_back(type_name(txception)); generate_erl_struct(txception, true); } /** * Generates a struct */ void t_erl_generator::generate_erl_struct(t_struct* tstruct, bool is_exception) { (void)is_exception; generate_erl_struct_definition(f_types_hrl_file_, tstruct); generate_erl_struct_info(f_info_, tstruct); generate_erl_extended_struct_info(f_info_ext_, tstruct); } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_erl_generator::generate_erl_struct_definition(ostream& out, t_struct* tstruct) { indent(out) << "%% struct " << type_name(tstruct) << endl << endl; std::stringstream buf; buf << indent() << "-record(" << type_name(tstruct) << ", {"; string field_indent(buf.str().size(), ' '); const vector& members = tstruct->get_members(); for (vector::const_iterator m_iter = members.begin(); m_iter != members.end();) { generate_erl_struct_member(buf, *m_iter); if (++m_iter != members.end()) { buf << "," << endl << field_indent; } } buf << "})."; out << buf.str() << endl; out << "-type " + type_name(tstruct) << "() :: #" + type_name(tstruct) + "{}." << endl << endl; } /** * Generates the record field definition */ void t_erl_generator::generate_erl_struct_member(ostream& out, t_field* tmember) { out << atomify(tmember->get_name()); if (has_default_value(tmember)) out << " = " << render_member_value(tmember); out << " :: " << render_member_type(tmember); if (tmember->get_req() != t_field::T_REQUIRED) out << " | 'undefined'"; } bool t_erl_generator::has_default_value(t_field* field) { t_type* type = field->get_type(); if (!field->get_value()) { if (field->get_req() == t_field::T_REQUIRED) { if (type->is_struct() || type->is_xception() || type->is_map() || type->is_set() || type->is_list()) { return true; } else { return false; } } else { return false; } } else { return true; } } string t_erl_generator::render_member_value(t_field* field) { if (!field->get_value()) { return render_default_value(field); } else { return render_const_value(field->get_type(), field->get_value()); } } /** * Generates the read method for a struct */ void t_erl_generator::generate_erl_struct_info(ostream& out, t_struct* tstruct) { indent(out) << "struct_info(" << type_name(tstruct) << ") ->" << endl; indent_up(); out << indent() << render_type_term(tstruct, true) << ";" << endl; indent_down(); out << endl; } void t_erl_generator::generate_erl_extended_struct_info(ostream& out, t_struct* tstruct) { indent(out) << "struct_info_ext(" << type_name(tstruct) << ") ->" << endl; indent_up(); out << indent() << render_type_term(tstruct, true, true) << ";" << endl; indent_down(); out << endl; } /** * Generates a thrift service. * * @param tservice The service definition */ void t_erl_generator::generate_service(t_service* tservice) { service_name_ = make_safe_for_module_name(service_name_); string f_service_hrl_name = get_out_dir() + service_name_ + "_thrift.hrl"; string f_service_name = get_out_dir() + service_name_ + "_thrift.erl"; f_service_file_.open(f_service_name.c_str()); f_service_hrl_.open(f_service_hrl_name.c_str()); // Reset service text aggregating stream streams f_service_.str(""); export_lines_.str(""); export_lines_first_ = true; hrl_header(f_service_hrl_, service_name_); if (tservice->get_extends() != nullptr) { f_service_hrl_ << "-include(\"" << make_safe_for_module_name(tservice->get_extends()->get_name()) << "_thrift.hrl\"). % inherit " << endl; } f_service_hrl_ << "-include(\"" << make_safe_for_module_name(program_name_) << "_types.hrl\")." << endl << endl; // Generate the three main parts of the service (well, two for now in PHP) generate_service_helpers(tservice); // cpiro: New Erlang Order generate_service_interface(tservice); generate_service_metadata(tservice); // indent_down(); f_service_file_ << erl_autogen_comment() << endl << "-module(" << service_name_ << "_thrift)." << endl << "-behaviour(thrift_service)." << endl << endl << erl_imports() << endl; f_service_file_ << "-include(\"" << make_safe_for_module_name(tservice->get_name()) << "_thrift.hrl\")." << endl << endl; f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl; f_service_file_ << f_service_.str(); hrl_footer(f_service_hrl_, f_service_name); // Close service file f_service_file_.close(); f_service_hrl_.close(); } void t_erl_generator::generate_service_metadata(t_service* tservice) { export_string("function_names", 0); vector functions = tservice->get_functions(); size_t num_functions = functions.size(); indent(f_service_) << "function_names() -> " << endl; indent_up(); indent(f_service_) << "["; for (size_t i=0; i < num_functions; i++) { t_function* current = functions.at(i); f_service_ << atomify(current->get_name()); if (i < num_functions - 1) { f_service_ << ", "; } } f_service_ << "].\n\n"; indent_down(); } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_erl_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; // indent(f_service_) << // "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl; export_string("struct_info", 1); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_erl_function_helpers(*f_iter); } f_service_ << "struct_info(_) -> erlang:error(function_clause)." << endl; } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_erl_generator::generate_erl_function_helpers(t_function* tfunction) { (void)tfunction; } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_erl_generator::generate_service_interface(t_service* tservice) { export_string("function_info", 2); vector functions = tservice->get_functions(); vector::iterator f_iter; f_service_ << "%%% interface" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << indent() << "% " << function_signature(*f_iter) << endl; generate_function_info(tservice, *f_iter); } // Inheritance - pass unknown functions to base class if (tservice->get_extends() != nullptr) { indent(f_service_) << "function_info(Function, InfoType) ->" << endl; indent_up(); indent(f_service_) << make_safe_for_module_name(tservice->get_extends()->get_name()) << "_thrift:function_info(Function, InfoType)." << endl; indent_down(); } else { // return function_clause error for non-existent functions indent(f_service_) << "function_info(_Func, _Info) -> erlang:error(function_clause)." << endl; } indent(f_service_) << endl; } /** * Generates a function_info(FunctionName, params_type) and * function_info(FunctionName, reply_type) */ void t_erl_generator::generate_function_info(t_service* tservice, t_function* tfunction) { (void)tservice; string name_atom = atomify(tfunction->get_name()); t_struct* xs = tfunction->get_xceptions(); t_struct* arg_struct = tfunction->get_arglist(); // function_info(Function, params_type): indent(f_service_) << "function_info(" << name_atom << ", params_type) ->" << endl; indent_up(); indent(f_service_) << render_type_term(arg_struct, true) << ";" << endl; indent_down(); // function_info(Function, reply_type): indent(f_service_) << "function_info(" << name_atom << ", reply_type) ->" << endl; indent_up(); if (!tfunction->get_returntype()->is_void()) indent(f_service_) << render_type_term(tfunction->get_returntype(), false) << ";" << endl; else if (tfunction->is_oneway()) indent(f_service_) << "oneway_void;" << endl; else indent(f_service_) << "{struct, []}" << ";" << endl; indent_down(); // function_info(Function, exceptions): indent(f_service_) << "function_info(" << name_atom << ", exceptions) ->" << endl; indent_up(); indent(f_service_) << render_type_term(xs, true) << ";" << endl; indent_down(); } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_erl_generator::function_signature(t_function* tfunction, string prefix) { return prefix + tfunction->get_name() + "(This" + capitalize(argument_list(tfunction->get_arglist())) + ")"; } /** * Add a function to the exports list */ void t_erl_generator::export_string(string name, int num) { if (export_lines_first_) { export_lines_first_ = false; } else { export_lines_ << ", "; } export_lines_ << name << "/" << num; } void t_erl_generator::export_types_string(string name, int num) { if (export_types_lines_first_) { export_types_lines_first_ = false; } else { export_types_lines_ << ", "; } export_types_lines_ << name << "/" << num; } void t_erl_generator::export_function(t_function* tfunction, string prefix) { t_struct::members_type::size_type num = tfunction->get_arglist()->get_members().size(); if (num > static_cast(std::numeric_limits().max())) { throw "integer overflow in t_erl_generator::export_function, name " + tfunction->get_name(); } export_string(prefix + tfunction->get_name(), 1 // This + static_cast(num)); } /** * Renders a field list */ string t_erl_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; result += ", "; // initial comma to compensate for initial This } else { result += ", "; } result += capitalize((*f_iter)->get_name()); } return result; } string t_erl_generator::type_name(t_type* ttype) { string prefix = ttype->get_program()->get_namespace("erl"); size_t prefix_length = prefix.length(); if (prefix_length > 0 && prefix[prefix_length - 1] != '_') { size_t delimiter_length = delimiter_.length(); if (delimiter_length > 0 && delimiter_length < prefix_length) { bool not_match = prefix.compare(prefix_length - delimiter_length, prefix_length, delimiter_) != 0; if (not_match) { prefix += delimiter_; } } } string name = ttype->get_name(); return atomify(prefix + name); } /** * Converts the parse type to a Erlang "type" (macro for int constants) */ string t_erl_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "?tType_STRING"; case t_base_type::TYPE_BOOL: return "?tType_BOOL"; case t_base_type::TYPE_I8: return "?tType_I8"; case t_base_type::TYPE_I16: return "?tType_I16"; case t_base_type::TYPE_I32: return "?tType_I32"; case t_base_type::TYPE_I64: return "?tType_I64"; case t_base_type::TYPE_DOUBLE: return "?tType_DOUBLE"; } } else if (type->is_enum()) { return "?tType_I32"; } else if (type->is_struct() || type->is_xception()) { return "?tType_STRUCT"; } else if (type->is_map()) { return "?tType_MAP"; } else if (type->is_set()) { return "?tType_SET"; } else if (type->is_list()) { return "?tType_LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Generate an Erlang term which represents a thrift type */ std::string t_erl_generator::render_type_term(t_type* type, bool expand_structs, bool extended_info) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "string"; case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: return "byte"; case t_base_type::TYPE_I16: return "i16"; case t_base_type::TYPE_I32: return "i32"; case t_base_type::TYPE_I64: return "i64"; case t_base_type::TYPE_DOUBLE: return "double"; } } else if (type->is_enum()) { return "i32"; } else if (type->is_struct() || type->is_xception()) { if (expand_structs) { std::stringstream buf; buf << "{struct, ["; string field_indent(buf.str().size(), ' '); t_struct::members_type const& fields = static_cast(type)->get_members(); t_struct::members_type::const_iterator i, end = fields.end(); for (i = fields.begin(); i != end;) { t_struct::members_type::value_type member = *i; int32_t key = member->get_key(); string type = render_type_term(member->get_type(), false, false); // recursive call if (!extended_info) { // Convert to format: {struct, [{Fid, Type}|...]} buf << "{" << key << ", " << type << "}"; } else { // Convert to format: {struct, [{Fid, Req, Type, Name, Def}|...]} string name = member->get_name(); string value = render_member_value(member); string requiredness = render_member_requiredness(member); buf << "{" << key << ", " << requiredness << ", " << type << ", " << atomify(name) << ", " << value << "}"; } if (++i != end) { buf << "," << endl << field_indent; } } buf << "]}" << endl; return buf.str(); } else { return "{struct, {" + atomify(type_module(type)) + ", " + type_name(type) + "}}"; } } else if (type->is_map()) { // {map, KeyType, ValType} t_type* key_type = ((t_map*)type)->get_key_type(); t_type* val_type = ((t_map*)type)->get_val_type(); return "{map, " + render_type_term(key_type, false) + ", " + render_type_term(val_type, false) + "}"; } else if (type->is_set()) { t_type* elem_type = ((t_set*)type)->get_elem_type(); return "{set, " + render_type_term(elem_type, false) + "}"; } else if (type->is_list()) { t_type* elem_type = ((t_list*)type)->get_elem_type(); return "{list, " + render_type_term(elem_type, false) + "}"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } std::string t_erl_generator::type_module(t_type* ttype) { return make_safe_for_module_name(ttype->get_program()->get_name()) + "_types"; } THRIFT_REGISTER_GENERATOR( erl, "Erlang", " legacynames: Output files retain naming conventions of Thrift 0.9.1 and earlier.\n" " delimiter= Delimiter between namespace prefix and record name. Default is '.'.\n" " app_prefix= Application prefix for generated Erlang files.\n" " maps: Generate maps instead of dicts.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_generator.cc000066400000000000000000000226521420101504100241660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "thrift/generate/t_generator.h" using namespace std; /** * Top level program generation function. Calls the generator subclass methods * for preparing file streams etc. then iterates over all the parts of the * program to perform the correct actions. * * @param program The thrift program to compile into C++ source */ void t_generator::generate_program() { // Initialize the generator init_generator(); // Generate enums vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } // Generate typedefs vector typedefs = program_->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { generate_typedef(*td_iter); } // Generate structs, exceptions, and unions in declared order vector objects = program_->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { generate_forward_declaration(*o_iter); } for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { if ((*o_iter)->is_xception()) { generate_xception(*o_iter); } else { generate_struct(*o_iter); } } // Generate constants vector consts = program_->get_consts(); generate_consts(consts); // Generate services vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { service_name_ = get_service_name(*sv_iter); generate_service(*sv_iter); } // Close the generator close_generator(); } std::set t_generator::lang_keywords() const { std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__", "__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as", "assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare", "def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif", "end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure", "except", "exec", "finally", "float", "for", "foreach", "from", "function", "global", "goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is", "lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass", "public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register", "return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this", "throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var", "virtual", "volatile", "when", "while", "with", "xor", "yield" }; return std::set(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) ); } void t_generator::validate_input() const { validate(program_->get_enums()); validate(program_->get_typedefs()); validate(program_->get_objects()); validate(program_->get_consts()); validate(program_->get_services()); } template void t_generator::validate(const vector& list) const{ typename vector::const_iterator it; for(it=list.begin(); it != list.end(); ++it) { validate(*it); } } void t_generator::validate(t_function const* f) const { validate_id(f->get_name()); validate(f->get_arglist()); validate(f->get_xceptions()); } void t_generator::validate(t_service const* s) const { validate_id(s->get_name()); validate(s->get_functions()); } void t_generator::validate(t_enum const* en) const { validate_id(en->get_name()); validate(en->get_constants()); } void t_generator::validate(t_struct const* s) const { validate_id(s->get_name()); validate(s->get_members()); } void t_generator::validate(t_enum_value const* en_val) const { validate_id(en_val->get_name()); } void t_generator::validate(t_typedef const* td) const { validate_id(td->get_name()); } void t_generator::validate(t_const const* c) const { validate_id(c->get_name()); } void t_generator::validate(t_field const* f) const { validate_id(f->get_name()); } void t_generator::validate_id(const string& id) const { if (keywords_.find(id) != keywords_.end()) { failure("Cannot use reserved language keyword: \"%s\"", id.c_str()); } } string t_generator::escape_string(const string& in) const { string result = ""; for (string::const_iterator it = in.begin(); it < in.end(); it++) { std::map::const_iterator res = escape_.find(*it); if (res != escape_.end()) { result.append(res->second); } else { result.push_back(*it); } } return result; } void t_generator::generate_consts(vector consts) { vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { generate_const(*c_iter); } } void t_generator::generate_docstring_comment(ostream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end) { if (!comment_start.empty()) indent(out) << comment_start; stringstream docs(contents, ios_base::in); while (!(docs.eof() || docs.fail())) { char line[1024]; docs.getline(line, 1024); if (strlen(line) > 0) { indent(out) << line_prefix << line << std::endl; } else if (line_prefix.empty()){ out << std::endl; } else if(!docs.eof()) { indent(out) << line_prefix << std::endl; } } if (!comment_end.empty()) indent(out) << comment_end; } void t_generator_registry::register_generator(t_generator_factory* factory) { gen_map_t& the_map = get_generator_map(); if (the_map.find(factory->get_short_name()) != the_map.end()) { failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str()); } the_map[factory->get_short_name()] = factory; } void t_generator::parse_options(const string& options, string& language, map& parsed_options) { string::size_type colon = options.find(':'); language = options.substr(0, colon); if (colon != string::npos) { string::size_type pos = colon + 1; while (pos != string::npos && pos < options.size()) { string::size_type next_pos = options.find(',', pos); string option = options.substr(pos, next_pos - pos); pos = ((next_pos == string::npos) ? next_pos : next_pos + 1); string::size_type separator = option.find('='); string key, value; if (separator == string::npos) { key = option; value = ""; } else { key = option.substr(0, separator); value = option.substr(separator + 1); } parsed_options[key] = value; } } } t_generator* t_generator_registry::get_generator(t_program* program, const string& language, const map& parsed_options, const std::string& options) { gen_map_t& the_map = get_generator_map(); gen_map_t::iterator iter = the_map.find(language); if ((language == "csharp") || (language == "netcore")) { failure("The '%s' target is no longer available. Use 'netstd' instead.", language.c_str()); } if (language == "cl") { pwarning(1, "The '%s' target is deprecated and will be removed in future versions.", language.c_str()); } if (iter == the_map.end()) { return nullptr; } return iter->second->get_generator(program, parsed_options, options); } t_generator* t_generator_registry::get_generator(t_program* program, const string& options) { string language; map parsed_options; t_generator::parse_options(options, language, parsed_options); return get_generator(program, language, parsed_options, options); } t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() { // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 static gen_map_t* the_map = new gen_map_t(); return *the_map; } t_generator_factory::t_generator_factory(const std::string& short_name, const std::string& long_name, const std::string& documentation) : short_name_(short_name), long_name_(long_name), documentation_(documentation) { t_generator_registry::register_generator(this); } thrift-0.16.0/compiler/cpp/src/thrift/generate/t_generator.h000066400000000000000000000315211420101504100240230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_GENERATOR_H #define T_GENERATOR_H #define MSC_2015_VER 1900 #include #include #include #include #include #include #include #include "thrift/common.h" #include "thrift/logging.h" #include "thrift/version.h" #include "thrift/generate/t_generator_registry.h" #include "thrift/parse/t_program.h" /** * Base class for a thrift code generator. This class defines the basic * routines for code generation and contains the top level method that * dispatches code generation across various components. * */ class t_generator { public: t_generator(t_program* program) { update_keywords(); tmp_ = 0; indent_ = 0; program_ = program; program_name_ = get_program_name(program); escape_['\n'] = "\\n"; escape_['\r'] = "\\r"; escape_['\t'] = "\\t"; escape_['"'] = "\\\""; escape_['\\'] = "\\\\"; } virtual ~t_generator() {} /** * Framework generator method that iterates over all the parts of a program * and performs general actions. This is implemented by the base class and * should not normally be overwritten in the subclasses. */ virtual void generate_program(); const t_program* get_program() const { return program_; } void generate_docstring_comment(std::ostream& out, const std::string& comment_start, const std::string& line_prefix, const std::string& contents, const std::string& comment_end); static void parse_options(const std::string& options, std::string& language, std::map& parsed_options); /** * check whether sub-namespace declaraction is used by generator. * e.g. allow * namespace py.twisted bar * to specify namespace to use when -gen py:twisted is specified. * Will be called with subnamespace, i.e. is_valid_namespace("twisted") * will be called for the above example. */ static bool is_valid_namespace(const std::string& sub_namespace) { (void)sub_namespace; return false; } /** * Escape string to use one in generated sources. */ virtual std::string escape_string(const std::string& in) const; std::string get_escaped_string(t_const_value* constval) { return escape_string(constval->get_string()); } /** * Check if all identifiers are valid for the target language * See update_keywords() */ virtual void validate_input() const; protected: virtual std::set lang_keywords() const; /** * Call this from constructor if you implement lang_keywords() */ void update_keywords() { keywords_ = lang_keywords(); } /** * A list of reserved words that cannot be used as identifiers. */ std::set keywords_; virtual void validate_id(const std::string& id) const; virtual void validate(t_enum const* en) const; virtual void validate(t_enum_value const* en_val) const; virtual void validate(t_typedef const* td) const; virtual void validate(t_const const* c) const; virtual void validate(t_service const* s) const; virtual void validate(t_struct const* c) const; virtual void validate(t_field const* f) const; virtual void validate(t_function const* f) const; template void validate(const std::vector& list) const; /** * Optional methods that may be implemented by subclasses to take necessary * steps at the beginning or end of code generation. */ virtual void init_generator() {} virtual void close_generator() {} virtual void generate_consts(std::vector consts); /** * Pure virtual methods implemented by the generator subclasses. */ virtual void generate_typedef(t_typedef* ttypedef) = 0; virtual void generate_enum(t_enum* tenum) = 0; virtual void generate_const(t_const* tconst) { (void)tconst; } virtual void generate_struct(t_struct* tstruct) = 0; virtual void generate_service(t_service* tservice) = 0; virtual void generate_forward_declaration(t_struct*) {} virtual void generate_xception(t_struct* txception) { // By default exceptions are the same as structs generate_struct(txception); } /** * Method to get the program name, may be overridden */ virtual std::string get_program_name(t_program* tprogram) { return tprogram->get_name(); } /** * Method to get the service name, may be overridden */ virtual std::string get_service_name(t_service* tservice) { return tservice->get_name(); } /** * Get the current output directory */ virtual std::string get_out_dir() const { if (program_->is_out_path_absolute()) { return program_->get_out_path() + "/"; } return program_->get_out_path() + out_dir_base_ + "/"; } /** * Creates a unique temporary variable name, which is just "name" with a * number appended to it (i.e. name35) */ std::string tmp(std::string name) { std::ostringstream out; out << name << tmp_++; return out.str(); } /** * Generates a comment about this code being autogenerated, using C++ style * comments, which are also fair game in Java / PHP, yay! * * @return C-style comment mentioning that this file is autogenerated. */ virtual std::string autogen_comment() { return std::string("/**\n") + " * " + autogen_summary() + "\n" + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + " * @generated\n" + " */\n"; } virtual std::string autogen_summary() { return std::string("Autogenerated by Thrift Compiler (") + THRIFT_VERSION + ")"; } /** * Indentation level modifiers */ void indent_up() { ++indent_; } void indent_down() { --indent_; } /** * Indentation validation helper */ int indent_count() { return indent_; } void indent_validate( int expected, const char * func_name) { if (indent_ != expected) { pverbose("Wrong indent count in %s: difference = %i \n", func_name, (expected - indent_)); } } /** * Indentation print function */ std::string indent() { std::string ind = ""; int i; for (i = 0; i < indent_; ++i) { ind += indent_str(); } return ind; } /** * Indentation utility wrapper */ std::ostream& indent(std::ostream& os) { return os << indent(); } /** * Capitalization helpers */ std::string capitalize(std::string in) { in[0] = toupper(in[0]); return in; } std::string decapitalize(std::string in) { in[0] = tolower(in[0]); return in; } static std::string lowercase(std::string in) { for (size_t i = 0; i < in.size(); ++i) { in[i] = tolower(in[i]); } return in; } static std::string uppercase(std::string in) { for (size_t i = 0; i < in.size(); ++i) { in[i] = toupper(in[i]); } return in; } /** * Transforms a camel case string to an equivalent one separated by underscores * e.g. aMultiWord -> a_multi_word * someName -> some_name * CamelCase -> camel_case * name -> name * Name -> name */ std::string underscore(std::string in) { in[0] = tolower(in[0]); for (size_t i = 1; i < in.size(); ++i) { if (isupper(in[i])) { in[i] = tolower(in[i]); in.insert(i, "_"); } } return in; } /** * Transforms a string with words separated by underscores to a camel case equivalent * e.g. a_multi_word -> aMultiWord * some_name -> someName * name -> name */ std::string camelcase(std::string in) { std::ostringstream out; bool underscore = false; for (size_t i = 0; i < in.size(); i++) { if (in[i] == '_') { underscore = true; continue; } if (underscore) { out << (char)toupper(in[i]); underscore = false; continue; } out << in[i]; } return out.str(); } const std::string emit_double_as_string(const double value) { std::stringstream double_output_stream; // sets the maximum precision: http://en.cppreference.com/w/cpp/io/manip/setprecision // sets the output format to fixed: http://en.cppreference.com/w/cpp/io/manip/fixed (not in scientific notation) double_output_stream << std::setprecision(std::numeric_limits::digits10 + 1); #ifdef _MSC_VER // strtod is broken in MSVC compilers older than 2015, so std::fixed fails to format a double literal. // more details: https://blogs.msdn.microsoft.com/vcblog/2014/06/18/ // c-runtime-crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1/ // and // http://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/ #if _MSC_VER >= MSC_2015_VER double_output_stream << std::fixed; #endif #else double_output_stream << std::fixed; #endif double_output_stream << value; return double_output_stream.str(); } public: /** * Get the true type behind a series of typedefs. */ static const t_type* get_true_type(const t_type* type) { return type->get_true_type(); } static t_type* get_true_type(t_type* type) { return type->get_true_type(); } protected: /** * The program being generated */ t_program* program_; /** * Quick accessor for formatted program name that is currently being * generated. */ std::string program_name_; /** * Quick accessor for formatted service name that is currently being * generated. */ std::string service_name_; /** * Output type-specifc directory name ("gen-*") */ std::string out_dir_base_; /** * Map of characters to escape in string literals. */ std::map escape_; virtual std::string indent_str() const { return " "; } private: /** * Current code indentation level */ int indent_; /** * Temporary variable counter, for making unique variable names */ int tmp_; }; template > class template_ofstream_with_content_based_conditional_update : public std::ostringstream { public: template_ofstream_with_content_based_conditional_update(): contents_written(false) {} template_ofstream_with_content_based_conditional_update(std::string const& output_file_path_) : output_file_path(output_file_path_), contents_written(false) {} ~template_ofstream_with_content_based_conditional_update() { if (!contents_written) { close(); } } void open(std::string const& output_file_path_) { output_file_path = output_file_path_; clear_buf(); contents_written = false; } void close() { if (contents_written || output_file_path == "") return; if (!is_readable(output_file_path)) { dump(); return; } std::ifstream old_file; old_file.exceptions(old_file.exceptions() | std::ifstream::badbit | std::ifstream::failbit); old_file.open(output_file_path.c_str(), std::ios::in); if (old_file) { std::string const old_file_contents(static_cast(std::ostringstream() << old_file.rdbuf()).str()); old_file.close(); if (old_file_contents != str()) { dump(); } } } protected: void dump() { std::ofstream out_file; out_file.exceptions(out_file.exceptions() | std::ofstream::badbit | std::ofstream::failbit); try { out_file.open(output_file_path.c_str(), std::ios::out); } catch (const std::ios_base::failure& e) { ::failure("failed to write the output to the file '%s', details: '%s'", output_file_path.c_str(), e.what()); } out_file << str(); out_file.close(); clear_buf(); contents_written = true; } void clear_buf() { str(std::string()); } static bool is_readable(std::string const& file_name) { return static_cast(std::ifstream(file_name.c_str())); } private: std::string output_file_path; bool contents_written; }; typedef template_ofstream_with_content_based_conditional_update ofstream_with_content_based_conditional_update; #endif thrift-0.16.0/compiler/cpp/src/thrift/generate/t_generator_registry.h000066400000000000000000000103061420101504100257510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_GENERATOR_REGISTRY_H #define T_GENERATOR_REGISTRY_H class t_generator; /** * A factory for producing generator classes of a particular language. * * This class is also responsible for: * - Registering itself with the generator registry. * - Providing documentation for the generators it produces. */ class t_generator_factory { public: t_generator_factory(const std::string& short_name, const std::string& long_name, const std::string& documentation); virtual ~t_generator_factory() = default; virtual t_generator* get_generator( // The program to generate. t_program* program, // Note: parsed_options will not exist beyond the call to get_generator. const std::map& parsed_options, // Note: option_string might not exist beyond the call to get_generator. const std::string& option_string) = 0; virtual bool is_valid_namespace(const std::string& sub_namespace) = 0; std::string get_short_name() { return short_name_; } std::string get_long_name() { return long_name_; } std::string get_documentation() { return documentation_; } private: std::string short_name_; std::string long_name_; std::string documentation_; }; template class t_generator_factory_impl : public t_generator_factory { public: t_generator_factory_impl(const std::string& short_name, const std::string& long_name, const std::string& documentation) : t_generator_factory(short_name, long_name, documentation) {} t_generator* get_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) override { return new generator(program, parsed_options, option_string); } bool is_valid_namespace(const std::string& sub_namespace) override { return generator::is_valid_namespace(sub_namespace); } }; class t_generator_registry { public: static void register_generator(t_generator_factory* factory); static t_generator* get_generator(t_program* program, const std::string& options); static t_generator* get_generator(t_program* program, const std::string& laugnage, const std::map& parsed_options, const std::string& options); typedef std::map gen_map_t; static gen_map_t& get_generator_map(); private: t_generator_registry(); t_generator_registry(const t_generator_registry&); }; #define THRIFT_REGISTER_GENERATOR(language, long_name, doc) \ class t_##language##_generator_factory_impl \ : public t_generator_factory_impl { \ public: \ t_##language##_generator_factory_impl() \ : t_generator_factory_impl(#language, long_name, doc) {} \ }; \ static t_##language##_generator_factory_impl _registerer; #endif thrift-0.16.0/compiler/cpp/src/thrift/generate/t_go_generator.cc000066400000000000000000004611551420101504100246600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* * This file is programmatically sanitized for style: * astyle --style=1tbs -f -p -H -j -U t_go_generator.cc * * The output of astyle should not be taken unquestioningly, but it is a good * guide for ensuring uniformity and readability. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" #include "thrift/generate/t_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * A helper for automatically formatting the emitted Go code from the Thrift * IDL per the Go style guide. * * Returns: * - true, if the formatting process succeeded. * - false, if the formatting process failed, which means the basic output was * still generated. */ bool format_go_output(const string& file_path); const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift"; static std::string package_flag; /** * Go code generator. */ class t_go_generator : public t_generator { public: t_go_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; gen_thrift_import_ = DEFAULT_THRIFT_IMPORT; gen_package_prefix_ = ""; package_flag = ""; read_write_private_ = false; ignore_initialisms_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("package_prefix") == 0) { gen_package_prefix_ = (iter->second); } else if( iter->first.compare("thrift_import") == 0) { gen_thrift_import_ = (iter->second); } else if( iter->first.compare("package") == 0) { package_flag = (iter->second); } else if( iter->first.compare("read_write_private") == 0) { read_write_private_ = true; } else if( iter->first.compare("ignore_initialisms") == 0) { ignore_initialisms_ = true; } else { throw "unknown option go:" + iter->first; } } out_dir_base_ = "gen-go"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; std::string render_const_value(t_type* type, t_const_value* value, const string& name, bool opt = false); /** * Struct generation code */ void generate_go_struct(t_struct* tstruct, bool is_exception); void generate_go_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool is_result = false, bool is_args = false); void generate_go_struct_initializer(std::ostream& out, t_struct* tstruct, bool is_args_or_result = false); void generate_isset_helpers(std::ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false); void generate_countsetfields_helper(std::ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false); void generate_go_struct_reader(std::ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false); void generate_go_struct_writer(std::ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false, bool uses_countsetfields = false); void generate_go_struct_equals(std::ostream& out, t_struct* tstruct, const string& tstruct_name); void generate_go_function_helpers(t_function* tfunction); void get_publicized_name_and_def_value(t_field* tfield, string* OUT_pub_name, t_const_value** OUT_def_value) const; /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_remote(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, bool declare, std::string prefix = "", bool inclass = false, bool coerceData = false, bool inkey = false, bool in_container = false); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, bool is_pointer_field, bool declare, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, bool pointer_field, bool declare, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, bool declare, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, bool declare, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, bool declare, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", bool inkey = false); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, bool pointer_field, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); void generate_go_equals(std::ostream& out, t_type* ttype, string tgt, string src); void generate_go_equals_struct(std::ostream& out, t_type* ttype, string tgt, string src); void generate_go_equals_container(std::ostream& out, t_type* ttype, string tgt, string src); void generate_go_docstring(std::ostream& out, t_struct* tstruct); void generate_go_docstring(std::ostream& out, t_function* tfunction); void generate_go_docstring(std::ostream& out, t_doc* tdoc, t_struct* tstruct, const char* subheader); void generate_go_docstring(std::ostream& out, t_doc* tdoc); void parse_go_tags(map* tags, const string in); /** * Helper rendering functions */ std::string go_autogen_comment(); std::string go_package(); std::string go_imports_begin(bool consts); std::string go_imports_end(); std::string render_includes(bool consts); std::string render_included_programs(string& unused_protection); std::string render_program_import(const t_program* program, string& unused_protection); std::string render_system_packages(std::vector &system_packages); std::string render_import_protection(); std::string render_fastbinary_includes(); std::string declare_argument(t_field* tfield); std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field); std::string type_name(t_type* ttype); std::string module_name(t_type* ttype); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string function_signature_if(t_function* tfunction, std::string prefix = "", bool addError = false); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string type_to_go_type(t_type* ttype); std::string type_to_go_type_with_opt(t_type* ttype, bool optional_field); std::string type_to_go_key_type(t_type* ttype); std::string type_to_spec_args(t_type* ttype); static std::string get_real_go_module(const t_program* program) { if (!package_flag.empty()) { return package_flag; } std::string real_module = program->get_namespace("go"); if (!real_module.empty()) { return real_module; } return lowercase(program->get_name()); } private: std::string gen_package_prefix_; std::string gen_thrift_import_; bool read_write_private_; bool ignore_initialisms_; /** * File streams */ ofstream_with_content_based_conditional_update f_types_; std::string f_types_name_; ofstream_with_content_based_conditional_update f_consts_; std::string f_consts_name_; std::stringstream f_const_values_; std::string package_name_; std::string package_dir_; std::unordered_map package_identifiers_; std::set package_identifiers_set_; std::string read_method_name_; std::string write_method_name_; std::string equals_method_name_; std::set commonInitialisms; std::string camelcase(const std::string& value) const; void fix_common_initialism(std::string& value, int i) const; std::string publicize(const std::string& value, bool is_args_or_result = false) const; std::string publicize(const std::string& value, bool is_args_or_result, const std::string& service_name) const; std::string privatize(const std::string& value) const; std::string new_prefix(const std::string& value) const; static std::string variable_name_to_go_name(const std::string& value); static bool is_pointer_field(t_field* tfield, bool in_container = false); static bool omit_initialization(t_field* tfield); }; // returns true if field initialization can be omitted since it has corresponding go type zero value // or default value is not set bool t_go_generator::omit_initialization(t_field* tfield) { t_const_value* value = tfield->get_value(); if (!value) { return true; } t_type* type = tfield->get_type()->get_true_type(); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw ""; case t_base_type::TYPE_STRING: if (type->is_binary()) { //[]byte are always inline return false; } // strings are pointers if has no default return value->get_string().empty(); case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: return value->get_integer() == 0; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { return value->get_integer() == 0; } else { return value->get_double() == 0.; } } } return false; } // Returns true if the type need a reference if used as optional without default static bool type_need_reference(t_type* type) { type = type->get_true_type(); if (type->is_map() || type->is_set() || type->is_list() || type->is_struct() || type->is_xception() || type->is_binary()) { return false; } return true; } // returns false if field could not use comparison to default value as !IsSet* bool t_go_generator::is_pointer_field(t_field* tfield, bool in_container_value) { (void)in_container_value; if (tfield->annotations_.count("cpp.ref") != 0) { return true; } t_type* type = tfield->get_type()->get_true_type(); // Structs in containers are pointers if (type->is_struct() || type->is_xception()) { return true; } if (!(tfield->get_req() == t_field::T_OPTIONAL)) { return false; } bool has_default = tfield->get_value(); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw ""; case t_base_type::TYPE_STRING: if (type->is_binary()) { //[]byte are always inline return false; } // strings are pointers if has no default return !has_default; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: return !has_default; } } else if (type->is_enum()) { return !has_default; } else if (type->is_struct() || type->is_xception()) { return true; } else if (type->is_map()) { return has_default; } else if (type->is_set()) { return has_default; } else if (type->is_list()) { return has_default; } else if (type->is_typedef()) { return has_default; } throw "INVALID TYPE IN type_to_go_type: " + type->get_name(); } std::string t_go_generator::camelcase(const std::string& value) const { std::string value2(value); std::setlocale(LC_ALL, "C"); // set locale to classic // Fix common initialism in first word fix_common_initialism(value2, 0); // as long as we are changing things, let's change _ followed by lowercase to // capital and fix common initialisms for (std::string::size_type i = 1; i < value2.size() - 1; ++i) { if (value2[i] == '_') { if (islower(value2[i + 1])) { value2.replace(i, 2, 1, toupper(value2[i + 1])); } if (i > static_cast(std::numeric_limits().max())) { throw "integer overflow in t_go_generator::camelcase, value = " + value; } fix_common_initialism(value2, static_cast(i)); } } return value2; } // Checks to see if the word starting at i in value contains a common initialism // and if so replaces it with the upper case version of the word. void t_go_generator::fix_common_initialism(std::string& value, int i) const { if (!ignore_initialisms_) { size_t wordLen = value.find('_', i); if (wordLen != std::string::npos) { wordLen -= i; } std::string word = value.substr(i, wordLen); std::transform(word.begin(), word.end(), word.begin(), ::toupper); if (commonInitialisms.find(word) != commonInitialisms.end()) { value.replace(i, word.length(), word); } } } std::string t_go_generator::publicize(const std::string& value, bool is_args_or_result, const std::string& service_name) const { if (value.size() <= 0) { return value; } std::string value2(value), prefix; string::size_type dot_pos = value.rfind('.'); if (dot_pos != string::npos) { prefix = value.substr(0, dot_pos + 1) + prefix; value2 = value.substr(dot_pos + 1); } if (!isupper(value2[0])) { value2[0] = toupper(value2[0]); } value2 = camelcase(value2); // final length before further checks, the string may become longer size_t len_before = value2.length(); // IDL identifiers may start with "New" which interferes with the CTOR pattern // Adding an extra underscore to all those identifiers solves this if ((len_before >= 3) && (value2.substr(0, 3) == "New")) { value2 += '_'; } // IDL identifiers may end with "Args"/"Result" which interferes with the implicit service // function structs // Adding another extra underscore to all those identifiers solves this // Suppress this check for the actual helper struct names if (!is_args_or_result) { bool ends_with_args = (len_before >= 4) && (value2.substr(len_before - 4, 4) == "Args"); bool ends_with_rslt = (len_before >= 6) && (value2.substr(len_before - 6, 6) == "Result"); if (ends_with_args || ends_with_rslt) { value2 += '_'; } } // Avoid naming collisions with other services if (is_args_or_result) { prefix += publicize(service_name); } return prefix + value2; } std::string t_go_generator::publicize(const std::string& value, bool is_args_or_result) const { return publicize(value, is_args_or_result, service_name_); } std::string t_go_generator::new_prefix(const std::string& value) const { if (value.size() <= 0) { return value; } string::size_type dot_pos = value.rfind('.'); if (dot_pos != string::npos) { return value.substr(0, dot_pos + 1) + "New" + publicize(value.substr(dot_pos + 1)); } return "New" + publicize(value); } std::string t_go_generator::privatize(const std::string& value) const { if (value.size() <= 0) { return value; } std::string value2(value); if (!islower(value2[0])) { value2[0] = tolower(value2[0]); } value2 = camelcase(value2); return value2; } std::string t_go_generator::variable_name_to_go_name(const std::string& value) { if (value.size() <= 0) { return value; } std::string value2(value); std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower); switch (value[0]) { case 'b': case 'B': if (value2 != "break") { return value; } break; case 'c': case 'C': if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") { return value; } break; case 'd': case 'D': if (value2 != "default" && value2 != "defer") { return value; } break; case 'e': case 'E': if (value2 != "else" && value2 != "error") { return value; } break; case 'f': case 'F': if (value2 != "fallthrough" && value2 != "for" && value2 != "func") { return value; } break; case 'g': case 'G': if (value2 != "go" && value2 != "goto") { return value; } break; case 'i': case 'I': if (value2 != "if" && value2 != "import" && value2 != "interface") { return value; } break; case 'm': case 'M': if (value2 != "map") { return value; } break; case 'p': case 'P': if (value2 != "package") { return value; } break; case 'r': case 'R': if (value2 != "range" && value2 != "return") { return value; } break; case 's': case 'S': if (value2 != "select" && value2 != "struct" && value2 != "switch") { return value; } break; case 't': case 'T': if (value2 != "type") { return value; } break; case 'v': case 'V': if (value2 != "var") { return value; } break; default: return value; } return value2 + "_a1"; } /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_go_generator::init_generator() { // Make output directory string module = get_real_go_module(program_); string target = module; package_dir_ = get_out_dir(); // This set is taken from https://github.com/golang/lint/blob/master/lint.go#L692 commonInitialisms.insert("API"); commonInitialisms.insert("ASCII"); commonInitialisms.insert("CPU"); commonInitialisms.insert("CSS"); commonInitialisms.insert("DNS"); commonInitialisms.insert("EOF"); commonInitialisms.insert("GUID"); commonInitialisms.insert("HTML"); commonInitialisms.insert("HTTP"); commonInitialisms.insert("HTTPS"); commonInitialisms.insert("ID"); commonInitialisms.insert("IP"); commonInitialisms.insert("JSON"); commonInitialisms.insert("LHS"); commonInitialisms.insert("QPS"); commonInitialisms.insert("RAM"); commonInitialisms.insert("RHS"); commonInitialisms.insert("RPC"); commonInitialisms.insert("SLA"); commonInitialisms.insert("SMTP"); commonInitialisms.insert("SSH"); commonInitialisms.insert("TCP"); commonInitialisms.insert("TLS"); commonInitialisms.insert("TTL"); commonInitialisms.insert("UDP"); commonInitialisms.insert("UI"); commonInitialisms.insert("UID"); commonInitialisms.insert("UUID"); commonInitialisms.insert("URI"); commonInitialisms.insert("URL"); commonInitialisms.insert("UTF8"); commonInitialisms.insert("VM"); commonInitialisms.insert("XML"); commonInitialisms.insert("XSRF"); commonInitialisms.insert("XSS"); // names of read and write methods if (read_write_private_) { read_method_name_ = "read"; write_method_name_ = "write"; } else { read_method_name_ = "Read"; write_method_name_ = "Write"; } equals_method_name_ = "Equals"; while (true) { // TODO: Do better error checking here. MKDIR(package_dir_.c_str()); if (module.empty()) { break; } string::size_type pos = module.find('.'); if (pos == string::npos) { package_dir_ += "/"; package_dir_ += module; package_name_ = module; module.clear(); } else { package_dir_ += "/"; package_dir_ += module.substr(0, pos); module.erase(0, pos + 1); } } string::size_type loc; while ((loc = target.find(".")) != string::npos) { target.replace(loc, 1, 1, '/'); } // Make output files f_types_name_ = package_dir_ + "/" + program_name_ + ".go"; f_types_.open(f_types_name_); f_consts_name_ = package_dir_ + "/" + program_name_ + "-consts.go"; f_consts_.open(f_consts_name_); // Print header f_types_ << go_autogen_comment() << go_package() << render_includes(false); f_consts_ << go_autogen_comment() << go_package() << render_includes(true); f_const_values_ << endl << "func init() {" << endl; // Create file for the GoUnusedProtection__ variable string f_unused_prot_name_ = package_dir_ + "/" + "GoUnusedProtection__.go"; ofstream_with_content_based_conditional_update f_unused_prot_; f_unused_prot_.open(f_unused_prot_name_.c_str()); f_unused_prot_ << go_autogen_comment() << go_package() << render_import_protection(); f_unused_prot_.close(); } string t_go_generator::render_included_programs(string& unused_prot) { const vector& includes = program_->get_includes(); string result = ""; string local_namespace = get_real_go_module(program_); std::set included; for (auto include : includes) { std::string includeModule = get_real_go_module(include); if (!local_namespace.empty() && local_namespace == includeModule) { continue; } if (!included.insert(includeModule).second) { continue; } result += render_program_import(include, unused_prot); } return result; } string t_go_generator::render_program_import(const t_program* program, string& unused_protection) { string result = ""; string go_module = get_real_go_module(program); string go_path = go_module; size_t found = 0; for (size_t j = 0; j < go_module.size(); j++) { // Import statement uses slashes ('/') in namespace if (go_module[j] == '.') { go_path[j] = '/'; found = j + 1; } } auto it = package_identifiers_.find(go_module); auto last_component = go_module.substr(found); if (it == package_identifiers_.end()) { auto value = last_component; // This final path component has already been used, let's construct a more unique alias if (package_identifiers_set_.find(value) != package_identifiers_set_.end()) { // TODO: This would produce more readable code if it appended trailing go_module // path components to generate a more readable name unique identifier (e.g. use // packageacommon as the alias for packagea/common instead of common=). But just // appending an integer is much simpler code value = tmp(value); } package_identifiers_set_.insert(value); it = package_identifiers_.emplace(go_module, std::move(value)).first; } auto const& package_identifier = it->second; result += "\t"; // if the package_identifier is different than final path component we need an alias if (last_component.compare(package_identifier) != 0) { result += package_identifier + " "; } string s; for (auto const& e : package_identifiers_set_) { s += e; s += ','; } s.pop_back(); result += "\"" + gen_package_prefix_ + go_path + "\"\n"; unused_protection += "var _ = " + package_identifier + ".GoUnusedProtection__\n"; return result; } /** * Render import lines for the system packages. * * The arg system_packages supports the following two options for import auto * rename in case duplications happens: * * 1. The full import path without double quotation marks, with part after the * last "/" as the import identifier. e.g.: * - "context" (context) * - "database/sql/driver" (driver) * 2. A rename import with double quotation marks around the full import path, * with the part before the first space as the import identifier. e.g.: * - "thrift \"github.com/apache/thrift/lib/go/thrift\"" (thrift) * * If a system package's package name is different from the last part of its * full import path, please always rename import it for dedup to work correctly, * e.g. "package \"github.com/org/go-package\"". * * @param system_packages */ string t_go_generator::render_system_packages(std::vector& system_packages) { string result = ""; for (vector::iterator iter = system_packages.begin(); iter != system_packages.end(); ++iter) { string package = *iter; string identifier = package; auto space_pos = package.find(" "); if (space_pos != string::npos) { // This is a rename import line, no need to wrap double quotation marks. result += "\t"+ package +"\n"; // The part before the first space is the import identifier. identifier = package.substr(0, space_pos); } else { result += "\t\""+ package +"\"\n"; // The part after the last / is the import identifier. auto slash_pos = package.rfind("/"); if (slash_pos != string::npos) { identifier = package.substr(slash_pos+1); } } // Reserve these package names in case the collide with imported Thrift packages package_identifiers_set_.insert(identifier); package_identifiers_.emplace(package, identifier); } return result; } /** * Renders all the imports necessary for including another Thrift program. * If consts include the additional imports. */ string t_go_generator::render_includes(bool consts) { const vector& includes = program_->get_includes(); string result = ""; string unused_prot = ""; result += go_imports_begin(consts); result += render_included_programs(unused_prot); if (includes.size() > 0) { result += "\n"; } return result + go_imports_end() + unused_prot; } string t_go_generator::render_import_protection() { return string("var GoUnusedProtection__ int;\n\n"); } /** * Renders all the imports necessary to use the accelerated TBinaryProtocol */ string t_go_generator::render_fastbinary_includes() { return ""; } /** * Autogen'd comment. The different text is necessary due to * https://github.com/golang/go/issues/13560#issuecomment-288457920 */ string t_go_generator::go_autogen_comment() { return std::string() + "// Code generated by Thrift Compiler (" + THRIFT_VERSION + "). DO NOT EDIT.\n\n"; } /** * Prints standard thrift package */ string t_go_generator::go_package() { return string("package ") + package_name_ + "\n\n"; } /** * Render the beginning of the import statement. * If consts include the additional imports. */ string t_go_generator::go_imports_begin(bool consts) { std::vector system_packages; system_packages.push_back("bytes"); system_packages.push_back("context"); // If not writing constants, and there are enums, need extra imports. if (!consts && get_program()->get_enums().size() > 0) { system_packages.push_back("database/sql/driver"); system_packages.push_back("errors"); } system_packages.push_back("fmt"); system_packages.push_back("time"); // For the thrift import, always do rename import to make sure it's called thrift. system_packages.push_back("thrift \"" + gen_thrift_import_ + "\""); return "import (\n" + render_system_packages(system_packages); } /** * End the import statement, include undscore-assignments * * These "_ =" prevent the go compiler complaining about unused imports. * This will have to do in lieu of more intelligent import statement construction */ string t_go_generator::go_imports_end() { return string( ")\n\n" "// (needed to ensure safety because of naive import list construction.)\n" "var _ = thrift.ZERO\n" "var _ = fmt.Printf\n" "var _ = context.Background\n" "var _ = time.Now\n" "var _ = bytes.Equal\n\n"); } /** * Closes the type files */ void t_go_generator::close_generator() { f_const_values_ << "}" << endl << endl; f_consts_ << f_const_values_.str(); // Close types and constants files f_consts_.close(); f_types_.close(); format_go_output(f_types_name_); format_go_output(f_consts_name_); } /** * Generates a typedef. * * @param ttypedef The type definition */ void t_go_generator::generate_typedef(t_typedef* ttypedef) { generate_go_docstring(f_types_, ttypedef); string new_type_name(publicize(ttypedef->get_symbolic())); string base_type(type_to_go_type(ttypedef->get_type())); if (base_type == new_type_name) { return; } f_types_ << "type " << new_type_name << " " << base_type << endl << endl; // Generate a convenience function that converts an instance of a type // (which may be a constant) into a pointer to an instance of a type. f_types_ << "func " << new_type_name << "Ptr(v " << new_type_name << ") *" << new_type_name << " { return &v }" << endl << endl; } /** * Generates code for an enumerated type. Done using a class to scope * the values. * * @param tenum The enumeration */ void t_go_generator::generate_enum(t_enum* tenum) { std::ostringstream to_string_mapping, from_string_mapping; std::string tenum_name(publicize(tenum->get_name())); generate_go_docstring(f_types_, tenum); f_types_ << "type " << tenum_name << " int64" << endl << "const (" << endl; to_string_mapping << indent() << "func (p " << tenum_name << ") String() string {" << endl; to_string_mapping << indent() << " switch p {" << endl; from_string_mapping << indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name << ", error) {" << endl; from_string_mapping << indent() << " switch s {" << endl; vector constants = tenum->get_constants(); vector::iterator c_iter; int value = -1; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { value = (*c_iter)->get_value(); string iter_std_name(escape_string((*c_iter)->get_name())); string iter_name((*c_iter)->get_name()); f_types_ << indent() << " " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = " << value << endl; // Dictionaries to/from string names of enums to_string_mapping << indent() << " case " << tenum_name << "_" << iter_name << ": return \"" << iter_std_name << "\"" << endl; if (iter_std_name != escape_string(iter_name)) { from_string_mapping << indent() << " case \"" << iter_std_name << "\", \"" << escape_string(iter_name) << "\": return " << tenum_name << "_" << iter_name << ", nil " << endl; } else { from_string_mapping << indent() << " case \"" << iter_std_name << "\": return " << tenum_name << "_" << iter_name << ", nil " << endl; } } to_string_mapping << indent() << " }" << endl; to_string_mapping << indent() << " return \"\"" << endl; to_string_mapping << indent() << "}" << endl; from_string_mapping << indent() << " }" << endl; from_string_mapping << indent() << " return " << tenum_name << "(0)," << " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl; from_string_mapping << indent() << "}" << endl; f_types_ << ")" << endl << endl << to_string_mapping.str() << endl << from_string_mapping.str() << endl << endl; // Generate a convenience function that converts an instance of an enum // (which may be a constant) into a pointer to an instance of that enum // type. f_types_ << "func " << tenum_name << "Ptr(v " << tenum_name << ") *" << tenum_name << " { return &v }" << endl << endl; // Generate MarshalText f_types_ << "func (p " << tenum_name << ") MarshalText() ([]byte, error) {" << endl; f_types_ << "return []byte(p.String()), nil" << endl; f_types_ << "}" << endl << endl; // Generate UnmarshalText f_types_ << "func (p *" << tenum_name << ") UnmarshalText(text []byte) error {" << endl; f_types_ << "q, err := " << tenum_name << "FromString(string(text))" << endl; f_types_ << "if (err != nil) {" << endl << "return err" << endl << "}" << endl; f_types_ << "*p = q" << endl; f_types_ << "return nil" << endl; f_types_ << "}" << endl << endl; // Generate Scan for sql.Scanner interface f_types_ << "func (p *" << tenum_name << ") Scan(value interface{}) error {" <get_type(); string name = publicize(tconst->get_name()); t_const_value* value = tconst->get_value(); if (type->is_base_type() || type->is_enum()) { indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl; } else { f_const_values_ << indent() << name << " = " << render_const_value(type, value, name) << endl << endl; f_consts_ << indent() << "var " << name << " " << type_to_go_type(type) << endl; } } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name, bool opt) { string typedef_opt_ptr; if (type->is_typedef()) { typedef_opt_ptr = type_name(type) + "Ptr"; } type = get_true_type(type); std::ostringstream out; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); if (opt) { switch (tbase) { case t_base_type::TYPE_BOOL: if (typedef_opt_ptr != "") { out << typedef_opt_ptr; } else { out << "thrift.BoolPtr"; } out << "("; out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: if (typedef_opt_ptr != "") { out << typedef_opt_ptr; } else { out << "thrift.Int8Ptr"; } out << "("; out << value->get_integer(); break; case t_base_type::TYPE_I16: if (typedef_opt_ptr != "") { out << typedef_opt_ptr; } else { out << "thrift.Int16Ptr"; } out << "("; out << value->get_integer(); break; case t_base_type::TYPE_I32: if (typedef_opt_ptr != "") { out << typedef_opt_ptr; } else { out << "thrift.Int32Ptr"; } out << "("; out << value->get_integer(); break; case t_base_type::TYPE_I64: if (typedef_opt_ptr != "") { out << typedef_opt_ptr; } else { out << "thrift.Int64Ptr"; } out << "("; out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (typedef_opt_ptr != "") { out << typedef_opt_ptr; } else { out << "thrift.Float64Ptr"; } out << "("; if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; case t_base_type::TYPE_STRING: if (typedef_opt_ptr != "") { out << typedef_opt_ptr; } else { out << "thrift.StringPtr"; } out << "("; out << '"' + get_escaped_string(value) + '"'; break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } out << ")"; } else { switch (tbase) { case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "[]byte(\"" << get_escaped_string(value) << "\")"; } else { out << '"' << get_escaped_string(value) << '"'; } break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: if (opt) { out << "&(&struct{x int}{"; } out << value->get_integer(); if (opt) { out << "}).x"; } break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } } else if (type->is_enum()) { if (opt) { if (typedef_opt_ptr != "") { out << typedef_opt_ptr << "("; } else { out << type_name(type) << "Ptr("; } } out << value->get_integer(); if (opt) { out << ")"; } } else if (type->is_struct() || type->is_xception()) { out << "&" << publicize(type_name(type)) << "{"; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; bool is_optional = false; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); is_optional = is_pointer_field(*f_iter); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } out << endl << indent() << publicize(v_iter->first->get_string()) << ": " << render_const_value(field_type, v_iter->second, name, is_optional) << "," << endl; } indent_down(); out << "}"; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); out << "map[" << type_to_go_key_type(ktype) << "]" << type_to_go_type(vtype) << "{" << endl; indent_up(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent() << render_const_value(ktype, v_iter->first, name) << ": " << render_const_value(vtype, v_iter->second, name) << "," << endl; } indent_down(); out << indent() << "}"; } else if (type->is_list()) { t_type* etype = ((t_list*)type)->get_elem_type(); const vector& val = value->get_list(); out << "[]" << type_to_go_type(etype) << "{" << endl; indent_up(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent() << render_const_value(etype, *v_iter, name) << ", "; } indent_down(); out << indent() << "}"; } else if (type->is_set()) { t_type* etype = ((t_set*)type)->get_elem_type(); const vector& val = value->get_list(); out << "[]" << type_to_go_type(etype) << "{" << endl; indent_up(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent() << render_const_value(etype, *v_iter, name) << ", "; } indent_down(); out << indent() << "}"; } else { throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); } return out.str(); } /** * Generates a go struct */ void t_go_generator::generate_struct(t_struct* tstruct) { generate_go_struct(tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_go_generator::generate_xception(t_struct* txception) { generate_go_struct(txception, true); } /** * Generates a go struct */ void t_go_generator::generate_go_struct(t_struct* tstruct, bool is_exception) { generate_go_struct_definition(f_types_, tstruct, is_exception); } void t_go_generator::get_publicized_name_and_def_value(t_field* tfield, string* OUT_pub_name, t_const_value** OUT_def_value) const { const string base_field_name = tfield->get_name(); const string escaped_field_name = escape_string(base_field_name); *OUT_pub_name = publicize(escaped_field_name); *OUT_def_value = tfield->get_value(); } void t_go_generator::generate_go_struct_initializer(ostream& out, t_struct* tstruct, bool is_args_or_result) { out << publicize(type_name(tstruct), is_args_or_result) << "{"; const vector& members = tstruct->get_members(); for (auto member : members) { bool pointer_field = is_pointer_field(member); string publicized_name; t_const_value* def_value; get_publicized_name_and_def_value(member, &publicized_name, &def_value); if (!pointer_field && def_value != nullptr && !omit_initialization(member)) { out << endl << indent() << publicized_name << ": " << render_field_initial_value(member, member->get_name(), pointer_field) << "," << endl; } } out << "}" << endl; } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_go_generator::generate_go_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool is_result, bool is_args) { const vector& members = tstruct->get_members(); const vector& sorted_members = tstruct->get_sorted_members(); vector::const_iterator m_iter; std::string tstruct_name(publicize(tstruct->get_name(), is_args || is_result)); generate_go_docstring(out, tstruct); out << indent() << "type " << tstruct_name << " struct {" << endl; /* Here we generate the structure specification for the fastbinary codec. These specifications have the following structure: thrift_spec -> tuple of item_spec item_spec -> nil | (tag, type_enum, name, spec_args, default) tag -> integer type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ... name -> string_literal default -> nil # Handled by __init__ spec_args -> nil # For simple types | (type_enum, spec_args) # Value type for list/set | (type_enum, spec_args, type_enum, spec_args) # Key and value for map | (class_name, spec_args_ptr) # For struct/exception class_name -> identifier # Basically a pointer to the class spec_args_ptr -> expression # just class_name.spec_args TODO(dreiss): Consider making this work for structs with negative tags. */ // TODO(dreiss): Look into generating an empty tuple instead of nil // for structures with no members. // TODO(dreiss): Test encoding of structs where some inner structs // don't have thrift_spec. indent_up(); int num_setable = 0; if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) { int sorted_keys_pos = 0; for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) { // Set field to optional if field is union, this is so we can get a // pointer to the field. if (tstruct->is_union()) (*m_iter)->set_req(t_field::T_OPTIONAL); if (sorted_keys_pos != (*m_iter)->get_key()) { int first_unused = (std::max)(1, sorted_keys_pos++); while (sorted_keys_pos != (*m_iter)->get_key()) { ++sorted_keys_pos; } int last_unused = sorted_keys_pos - 1; if (first_unused < last_unused) { indent(out) << "// unused fields # " << first_unused << " to " << last_unused << endl; } else if (first_unused == last_unused) { indent(out) << "// unused field # " << first_unused << endl; } } t_type* fieldType = (*m_iter)->get_type(); string goType = type_to_go_type_with_opt(fieldType, is_pointer_field(*m_iter)); maptags; tags["db"]=escape_string((*m_iter)->get_name()); // Only add the `omitempty` tag if this field is optional and has no default value. // Otherwise a proper value like `false` for a bool field will be ommitted from // the JSON output since Go Marshal won't output `zero values`. bool has_default = (*m_iter)->get_value(); bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; if (is_optional && !has_default) { tags["json"]=escape_string((*m_iter)->get_name())+",omitempty"; } else { tags["json"]=escape_string((*m_iter)->get_name()); } // Check for user defined tags and them if there are any. User defined tags // can override the above db and json tags. std::map::iterator it = (*m_iter)->annotations_.find("go.tag"); if (it != (*m_iter)->annotations_.end()) { parse_go_tags(&tags, it->second); } string gotag; for (auto it = tags.begin(); it != tags.end(); ++it) { gotag += it->first + ":\"" + it->second + "\" "; } // Trailing whitespace gotag.resize(gotag.size()-1); indent(out) << publicize((*m_iter)->get_name()) << " " << goType << " `thrift:\"" << escape_string((*m_iter)->get_name()) << "," << sorted_keys_pos; if ((*m_iter)->get_req() == t_field::T_REQUIRED) { out << ",required"; } out << "\" " << gotag << "`" << endl; sorted_keys_pos++; } } else { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { // This fills in default values, as opposed to nulls out << indent() << publicize((*m_iter)->get_name()) << " " << type_to_go_type((*m_iter)->get_type()) << endl; } } indent_down(); out << indent() << "}" << endl << endl; out << indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl; out << indent() << " return &"; generate_go_struct_initializer(out, tstruct, is_result || is_args); out << indent() << "}" << endl << endl; // Default values for optional fields for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { string publicized_name; t_const_value* def_value; get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value); t_type* fieldType = (*m_iter)->get_type(); string goType = type_to_go_type_with_opt(fieldType, false); string def_var_name = tstruct_name + "_" + publicized_name + "_DEFAULT"; if ((*m_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*m_iter)) { out << indent() << "var " << def_var_name << " " << goType; if (def_value != nullptr) { out << " = " << render_const_value(fieldType, def_value, (*m_iter)->get_name()); } out << endl; } // num_setable is used for deciding if Count* methods will be generated for union fields. // This applies to all nullable fields including slices (used for set, list and binary) and maps, not just pointers. t_type* type = fieldType->get_true_type(); if (is_pointer_field(*m_iter)|| type->is_map() || type->is_set() || type->is_list() || type->is_binary()) { num_setable += 1; } if (is_pointer_field(*m_iter)) { string goOptType = type_to_go_type_with_opt(fieldType, true); string maybepointer = goOptType != goType ? "*" : ""; out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() " << goType << " {" << endl; out << indent() << " if !p.IsSet" << publicized_name << "() {" << endl; out << indent() << " return " << def_var_name << endl; out << indent() << " }" << endl; out << indent() << "return " << maybepointer << "p." << publicized_name << endl; out << indent() << "}" << endl; } else { out << endl; out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() " << goType << " {" << endl; out << indent() << " return p." << publicized_name << endl; out << indent() << "}" << endl; } } if (tstruct->is_union() && num_setable > 0) { generate_countsetfields_helper(out, tstruct, tstruct_name, is_result); } generate_isset_helpers(out, tstruct, tstruct_name, is_result); generate_go_struct_reader(out, tstruct, tstruct_name, is_result); generate_go_struct_writer(out, tstruct, tstruct_name, is_result, num_setable > 0); if (!is_result && !is_args) { generate_go_struct_equals(out, tstruct, tstruct_name); } out << indent() << "func (p *" << tstruct_name << ") String() string {" << endl; out << indent() << " if p == nil {" << endl; out << indent() << " return \"\"" << endl; out << indent() << " }" << endl; out << indent() << " return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)" << endl; out << indent() << "}" << endl << endl; if (is_exception) { out << indent() << "func (p *" << tstruct_name << ") Error() string {" << endl; indent_up(); out << indent() << "return p.String()" << endl; indent_down(); out << indent() << "}" << endl << endl; out << indent() << "func (" << tstruct_name << ") TExceptionType() thrift.TExceptionType {" << endl; indent_up(); out << indent() << "return thrift.TExceptionTypeCompiled" << endl; indent_down(); out << indent() << "}" << endl << endl; out << indent() << "var _ thrift.TException = (*" << tstruct_name << ")(nil)" << endl << endl; } } /** * Generates the IsSet helper methods for a struct */ void t_go_generator::generate_isset_helpers(ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result) { (void)is_result; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; const string escaped_tstruct_name(escape_string(tstruct->get_name())); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { const string field_name(publicize(escape_string((*f_iter)->get_name()))); if ((*f_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*f_iter)) { out << indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {" << endl; indent_up(); t_type* ttype = (*f_iter)->get_type()->get_true_type(); bool is_byteslice = ttype->is_binary(); bool compare_to_nil_only = ttype->is_set() || ttype->is_list() || ttype->is_map() || (is_byteslice && !(*f_iter)->get_value()); if (is_pointer_field(*f_iter) || compare_to_nil_only) { out << indent() << "return p." << field_name << " != nil" << endl; } else { string def_var_name = tstruct_name + "_" + field_name + "_DEFAULT"; if (is_byteslice) { out << indent() << "return !bytes.Equal(p." << field_name << ", " << def_var_name << ")" << endl; } else { out << indent() << "return p." << field_name << " != " << def_var_name << endl; } } indent_down(); out << indent() << "}" << endl << endl; } } } /** * Generates the CountSetFields helper method for a struct */ void t_go_generator::generate_countsetfields_helper(ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result) { (void)is_result; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; const string escaped_tstruct_name(escape_string(tstruct->get_name())); out << indent() << "func (p *" << tstruct_name << ") CountSetFields" << tstruct_name << "() int {" << endl; indent_up(); out << indent() << "count := 0" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) continue; t_type* type = (*f_iter)->get_type()->get_true_type(); if (!(is_pointer_field(*f_iter) || type->is_map() || type->is_set() || type->is_list() || type->is_binary())) continue; const string field_name(publicize(escape_string((*f_iter)->get_name()))); out << indent() << "if (p.IsSet" << field_name << "()) {" << endl; indent_up(); out << indent() << "count++" << endl; indent_down(); out << indent() << "}" << endl; } out << indent() << "return count" << endl << endl; indent_down(); out << indent() << "}" << endl << endl; } /** * Generates the read method for a struct */ void t_go_generator::generate_go_struct_reader(ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result) { (void)is_result; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; string escaped_tstruct_name(escape_string(tstruct->get_name())); out << indent() << "func (p *" << tstruct_name << ") " << read_method_name_ << "(ctx context.Context, iprot thrift.TProtocol) error {" << endl; indent_up(); out << indent() << "if _, err := iprot.ReadStructBegin(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)" << endl; out << indent() << "}" << endl << endl; // Required variables does not have IsSet functions, so we need tmp vars to check them. for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { const string field_name(publicize(escape_string((*f_iter)->get_name()))); indent(out) << "var isset" << field_name << " bool = false;" << endl; } } out << endl; // Loop over reading in fields indent(out) << "for {" << endl; indent_up(); // Read beginning field marker out << indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin(ctx)" << endl; out << indent() << "if err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(" "\"%T field %d read error: \", p, fieldId), err)" << endl; out << indent() << "}" << endl; // Check for field STOP marker and break out << indent() << "if fieldTypeId == thrift.STOP { break; }" << endl; string thriftFieldTypeId; // Generate deserialization code for known cases int32_t field_id = -1; // Switch statement on the field we are reading, false if no fields present bool have_switch = !fields.empty(); if (have_switch) { indent(out) << "switch fieldId {" << endl; } // All the fields we know for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { field_id = (*f_iter)->get_key(); // if negative id, ensure we generate a valid method name string field_method_prefix("ReadField"); int32_t field_method_suffix = field_id; if (field_method_suffix < 0) { field_method_prefix += "_"; field_method_suffix *= -1; } out << indent() << "case " << field_id << ":" << endl; indent_up(); thriftFieldTypeId = type_to_enum((*f_iter)->get_type()); if (thriftFieldTypeId == "thrift.BINARY") { thriftFieldTypeId = "thrift.STRING"; } out << indent() << "if fieldTypeId == " << thriftFieldTypeId << " {" << endl; out << indent() << " if err := p." << field_method_prefix << field_method_suffix << "(ctx, iprot); err != nil {" << endl; out << indent() << " return err" << endl; out << indent() << " }" << endl; // Mark required field as read if ((*f_iter)->get_req() == t_field::T_REQUIRED) { const string field_name(publicize(escape_string((*f_iter)->get_name()))); out << indent() << " isset" << field_name << " = true" << endl; } out << indent() << "} else {" << endl; out << indent() << " if err := iprot.Skip(ctx, fieldTypeId); err != nil {" << endl; out << indent() << " return err" << endl; out << indent() << " }" << endl; out << indent() << "}" << endl; indent_down(); } // Begin switch default case if (have_switch) { out << indent() << "default:" << endl; indent_up(); } // Skip unknown fields in either case out << indent() << "if err := iprot.Skip(ctx, fieldTypeId); err != nil {" << endl; out << indent() << " return err" << endl; out << indent() << "}" << endl; // End switch default case if (have_switch) { indent_down(); out << indent() << "}" << endl; } // Read field end marker out << indent() << "if err := iprot.ReadFieldEnd(ctx); err != nil {" << endl; out << indent() << " return err" << endl; out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl; out << indent() << "if err := iprot.ReadStructEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(" "\"%T read struct end error: \", p), err)" << endl; out << indent() << "}" << endl; // Return error if any required fields are missing. for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { const string field_name(publicize(escape_string((*f_iter)->get_name()))); out << indent() << "if !isset" << field_name << "{" << endl; out << indent() << " return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, " "fmt.Errorf(\"Required field " << field_name << " is not set\"));" << endl; out << indent() << "}" << endl; } } out << indent() << "return nil" << endl; indent_down(); out << indent() << "}" << endl << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { string field_type_name(publicize((*f_iter)->get_type()->get_name())); string field_name(publicize((*f_iter)->get_name())); string field_method_prefix("ReadField"); int32_t field_id = (*f_iter)->get_key(); int32_t field_method_suffix = field_id; if (field_method_suffix < 0) { field_method_prefix += "_"; field_method_suffix *= -1; } out << indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_method_suffix << "(ctx context.Context, iprot thrift.TProtocol) error {" << endl; indent_up(); generate_deserialize_field(out, *f_iter, false, "p."); indent_down(); out << indent() << " return nil" << endl; out << indent() << "}" << endl << endl; } } void t_go_generator::generate_go_struct_writer(ostream& out, t_struct* tstruct, const string& tstruct_name, bool is_result, bool uses_countsetfields) { (void)is_result; string name(tstruct->get_name()); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent(out) << "func (p *" << tstruct_name << ") " << write_method_name_ << "(ctx context.Context, oprot thrift.TProtocol) error {" << endl; indent_up(); if (tstruct->is_union() && uses_countsetfields) { std::string tstruct_name(publicize(tstruct->get_name())); out << indent() << "if c := p.CountSetFields" << tstruct_name << "(); c != 1 {" << endl << indent() << " return fmt.Errorf(\"%T write union: exactly one field must be set (%d set)\", p, c)" << endl << indent() << "}" << endl; } out << indent() << "if err := oprot.WriteStructBegin(ctx, \"" << name << "\"); err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(" "\"%T write struct begin error: \", p), err) }" << endl; string field_name; string escape_field_name; // t_const_value* field_default_value; t_field::e_req field_required; int32_t field_id = -1; out << indent() << "if p != nil {" << endl; indent_up(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { string field_method_prefix("writeField"); field_name = (*f_iter)->get_name(); escape_field_name = escape_string(field_name); field_id = (*f_iter)->get_key(); int32_t field_method_suffix = field_id; if (field_method_suffix < 0) { field_method_prefix += "_"; field_method_suffix *= -1; } out << indent() << "if err := p." << field_method_prefix << field_method_suffix << "(ctx, oprot); err != nil { return err }" << endl; } indent_down(); out << indent() << "}" << endl; // Write the struct map out << indent() << "if err := oprot.WriteFieldStop(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"write field stop error: \", err) }" << endl; out << indent() << "if err := oprot.WriteStructEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"write struct stop error: \", err) }" << endl; out << indent() << "return nil" << endl; indent_down(); out << indent() << "}" << endl << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { string field_method_prefix("writeField"); field_id = (*f_iter)->get_key(); field_name = (*f_iter)->get_name(); escape_field_name = escape_string(field_name); // field_default_value = (*f_iter)->get_value(); field_required = (*f_iter)->get_req(); int32_t field_method_suffix = field_id; if (field_method_suffix < 0) { field_method_prefix += "_"; field_method_suffix *= -1; } out << indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_method_suffix << "(ctx context.Context, oprot thrift.TProtocol) (err error) {" << endl; indent_up(); if (field_required == t_field::T_OPTIONAL) { out << indent() << "if p.IsSet" << publicize(field_name) << "() {" << endl; indent_up(); } out << indent() << "if err := oprot.WriteFieldBegin(ctx, \"" << escape_field_name << "\", " << type_to_enum((*f_iter)->get_type()) << ", " << field_id << "); err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T write field begin error " << field_id << ":" << escape_field_name << ": \", p), err) }" << endl; // Write field contents generate_serialize_field(out, *f_iter, "p."); // Write field closer out << indent() << "if err := oprot.WriteFieldEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T write field end error " << field_id << ":" << escape_field_name << ": \", p), err) }" << endl; if (field_required == t_field::T_OPTIONAL) { indent_down(); out << indent() << "}" << endl; } indent_down(); out << indent() << " return err" << endl; out << indent() << "}" << endl << endl; } } void t_go_generator::generate_go_struct_equals(ostream& out, t_struct* tstruct, const string& tstruct_name) { string name(tstruct->get_name()); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent(out) << "func (p *" << tstruct_name << ") " << equals_method_name_ << "(other *" << tstruct_name << ") bool {" << endl; indent_up(); string field_name; string publicize_field_name; out << indent() << "if p == other {" << endl; indent_up(); out << indent() << "return true" << endl; indent_down(); out << indent() << "} else if p == nil || other == nil {" << endl; indent_up(); out << indent() << "return false" << endl; indent_down(); out << indent() << "}" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { field_name = (*f_iter)->get_name(); t_type* field_type = (*f_iter)->get_type(); publicize_field_name = publicize(field_name); string goType = type_to_go_type_with_opt(field_type, is_pointer_field(*f_iter)); string tgt = "p." + publicize_field_name; string src = "other." + publicize_field_name; t_type* ttype = field_type->get_true_type(); // Compare field contents if (is_pointer_field(*f_iter) && (ttype->is_base_type() || ttype->is_enum() || ttype->is_container())) { string tgtv = "(*" + tgt + ")"; string srcv = "(*" + src + ")"; out << indent() << "if " << tgt << " != " << src << " {" << endl; indent_up(); out << indent() << "if " << tgt << " == nil || " << src << " == nil {" << endl; indent_up(); out << indent() << "return false" << endl; indent_down(); out << indent() << "}" << endl; generate_go_equals(out, field_type, tgtv, srcv); indent_down(); out << indent() << "}" << endl; } else { generate_go_equals(out, field_type, tgt, src); } } out << indent() << "return true" << endl; indent_down(); out << indent() << "}" << endl << endl; } /** * Generates a thrift service. * * @param tservice The service definition */ void t_go_generator::generate_service(t_service* tservice) { string test_suffix("_test"); string filename = lowercase(service_name_); string f_service_name; generate_service_interface(tservice); generate_service_client(tservice); generate_service_server(tservice); generate_service_helpers(tservice); generate_service_remote(tservice); f_types_ << endl; } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_go_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; f_types_ << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_go_struct_definition(f_types_, ts, false, false, true); generate_go_function_helpers(*f_iter); } } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_go_generator::generate_go_function_helpers(t_function* tfunction) { if (!tfunction->is_oneway()) { t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); success.set_req(t_field::T_OPTIONAL); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* f = *f_iter; f->set_req(t_field::T_OPTIONAL); result.append(f); } generate_go_struct_definition(f_types_, &result, false, true); } } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_go_generator::generate_service_interface(t_service* tservice) { string extends = ""; string extends_if = ""; string serviceName(publicize(tservice->get_name())); string interfaceName = serviceName; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); size_t index = extends.rfind("."); if (index != string::npos) { extends_if = "\n" + indent() + " " + extends.substr(0, index + 1) + publicize(extends.substr(index + 1)) + "\n"; } else { extends_if = "\n" + indent() + publicize(extends) + "\n"; } } f_types_ << indent() << "type " << interfaceName << " interface {" << extends_if; indent_up(); generate_go_docstring(f_types_, tservice); vector functions = tservice->get_functions(); if (!functions.empty()) { f_types_ << endl; vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_go_docstring(f_types_, (*f_iter)); f_types_ << indent() << function_signature_if(*f_iter, "", true) << endl; } } indent_down(); f_types_ << indent() << "}" << endl << endl; } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_go_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_field = ""; string extends_client = ""; string extends_client_new = ""; string serviceName(publicize(tservice->get_name())); if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); size_t index = extends.rfind("."); if (index != string::npos) { extends_client = extends.substr(0, index + 1) + publicize(extends.substr(index + 1)) + "Client"; extends_client_new = extends.substr(0, index + 1) + "New" + publicize(extends.substr(index + 1)) + "Client"; } else { extends_client = publicize(extends) + "Client"; extends_client_new = "New" + extends_client; } } extends_field = extends_client.substr(extends_client.find(".") + 1); generate_go_docstring(f_types_, tservice); f_types_ << indent() << "type " << serviceName << "Client struct {" << endl; indent_up(); if (!extends_client.empty()) { f_types_ << indent() << "*" << extends_client << endl; } else { f_types_ << indent() << "c thrift.TClient" << endl; f_types_ << indent() << "meta thrift.ResponseMeta" << endl; } indent_down(); f_types_ << indent() << "}" << endl << endl; // Legacy constructor function f_types_ << indent() << "func New" << serviceName << "ClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *" << serviceName << "Client {" << endl; indent_up(); f_types_ << indent() << "return &" << serviceName << "Client"; if (!extends.empty()) { f_types_ << "{" << extends_field << ": " << extends_client_new << "Factory(t, f)}"; } else { indent_up(); f_types_ << "{" << endl; f_types_ << indent() << "c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t))," << endl; indent_down(); f_types_ << indent() << "}" << endl; } indent_down(); f_types_ << indent() << "}" << endl << endl; // Legacy constructor function with custom input & output protocols f_types_ << indent() << "func New" << serviceName << "ClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *" << serviceName << "Client {" << endl; indent_up(); f_types_ << indent() << "return &" << serviceName << "Client"; if (!extends.empty()) { f_types_ << "{" << extends_field << ": " << extends_client_new << "Protocol(t, iprot, oprot)}" << endl; } else { indent_up(); f_types_ << "{" << endl; f_types_ << indent() << "c: thrift.NewTStandardClient(iprot, oprot)," << endl; indent_down(); f_types_ << indent() << "}" << endl; } indent_down(); f_types_ << indent() << "}" << endl << endl; // Constructor function f_types_ << indent() << "func New" << serviceName << "Client(c thrift.TClient) *" << serviceName << "Client {" << endl; indent_up(); f_types_ << indent() << "return &" << serviceName << "Client{" << endl; indent_up(); if (!extends.empty()) { f_types_ << indent() << extends_field << ": " << extends_client_new << "(c)," << endl; } else { f_types_ << indent() << "c: c," << endl; } indent_down(); f_types_ << indent() << "}" << endl; indent_down(); f_types_ << indent() << "}" << endl << endl; if (extends.empty()) { f_types_ << indent() << "func (p *" << serviceName << "Client) Client_() thrift.TClient {" << endl; indent_up(); f_types_ << indent() << "return p.c" << endl; indent_down(); f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func (p *" << serviceName << "Client) LastResponseMeta_() thrift.ResponseMeta {" << endl; indent_up(); f_types_ << indent() << "return p.meta" << endl; indent_down(); f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func (p *" << serviceName << "Client) SetLastResponseMeta_(meta thrift.ResponseMeta) {" << endl; indent_up(); f_types_ << indent() << "p.meta = meta" << endl; indent_down(); f_types_ << indent() << "}" << endl << endl; } // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = publicize((*f_iter)->get_name()); // Open function generate_go_docstring(f_types_, (*f_iter)); f_types_ << indent() << "func (p *" << serviceName << "Client) " << function_signature_if(*f_iter, "", true) << " {" << endl; indent_up(); std::string method = (*f_iter)->get_name(); std::string argsType = publicize(method + "_args", true); std::string argsName = tmp("_args"); f_types_ << indent() << "var " << argsName << " " << argsType << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_types_ << indent() << argsName << "." << publicize((*fld_iter)->get_name()) << " = " << variable_name_to_go_name((*fld_iter)->get_name()) << endl; } if (!(*f_iter)->is_oneway()) { std::string metaName = tmp("_meta"); std::string resultName = tmp("_result"); std::string resultType = publicize(method + "_result", true); f_types_ << indent() << "var " << resultName << " " << resultType << endl; f_types_ << indent() << "var " << metaName << " thrift.ResponseMeta" << endl; f_types_ << indent() << metaName << ", _err = p.Client_().Call(ctx, \"" << method << "\", &" << argsName << ", &" << resultName << ")" << endl; f_types_ << indent() << "p.SetLastResponseMeta_(" << metaName << ")" << endl; f_types_ << indent() << "if _err != nil {" << endl; indent_up(); f_types_ << indent() << "return" << endl; indent_down(); f_types_ << indent() << "}" << endl; t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; if (!xceptions.empty()) { f_types_ << indent() << "switch {" << endl; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { const std::string pubname = publicize((*x_iter)->get_name()); const std::string field = resultName + "." + pubname; f_types_ << indent() << "case " << field << "!= nil:" << endl; indent_up(); if (!(*f_iter)->get_returntype()->is_void()) { f_types_ << indent() << "return _r, " << field << endl; } else { f_types_ << indent() << "return "<< field << endl; } indent_down(); } f_types_ << indent() << "}" << endl << endl; } if ((*f_iter)->get_returntype()->is_struct()) { // Check if the result is nil, which likely means we have a new // exception added but unknown to the client yet // (e.g. client hasn't updated the thrift file). // Sadly this check can only be reliable done when the return type is a // struct in go. std::string retName = tmp("_ret"); f_types_ << indent() << "if " << retName << " := " << resultName << ".GetSuccess(); " << retName << " != nil {" << endl; indent_up(); f_types_ << indent() << "return " << retName << ", nil" << endl; indent_down(); f_types_ << indent() << "}" << endl; f_types_ << indent() << "return nil, " << "thrift.NewTApplicationException(thrift.MISSING_RESULT, \"" << method << " failed: unknown result\")" << endl; } else if (!(*f_iter)->get_returntype()->is_void()) { f_types_ << indent() << "return " << resultName << ".GetSuccess(), nil" << endl; } else { f_types_ << indent() << "return nil" << endl; } } else { // Since we don't have response meta for oneway calls, overwrite it with // an empty one to avoid users getting the meta from last call and // mistaken it as from the oneway call. f_types_ << indent() << "p.SetLastResponseMeta_(thrift.ResponseMeta{})" << endl; // TODO: would be nice to not to duplicate the call generation f_types_ << indent() << "if _, err := p.Client_().Call(ctx, \"" << method << "\", &" << argsName << ", nil); err != nil {" << endl; indent_up(); f_types_ << indent() << "return err" << endl; indent_down(); f_types_ << indent() << "}" << endl; f_types_ << indent() << "return nil" << endl; } indent_down(); f_types_ << "}" << endl << endl; } } /** * Generates a command line tool for making remote requests * * @param tservice The service to generate a remote for. */ void t_go_generator::generate_service_remote(t_service* tservice) { vector functions; std::unordered_map func_to_service; // collect all functions including inherited functions t_service* parent = tservice; while (parent != nullptr) { vector p_functions = parent->get_functions(); functions.insert(functions.end(), p_functions.begin(), p_functions.end()); // We need to maintain a map of functions names to the name of their parent. // This is because functions may come from a parent service, and if we need // to create the arguments struct (e.g. `NewParentServiceNameFuncNameArgs()`) // we need to make sure to specify the correct service name. for (vector::iterator f_iter = p_functions.begin(); f_iter != p_functions.end(); ++f_iter) { auto it = func_to_service.find((*f_iter)->get_name()); if (it == func_to_service.end()) { func_to_service.emplace((*f_iter)->get_name(), parent->get_name()); } } parent = parent->get_extends(); } // This file is not useful if there are no functions; don't generate it if (functions.size() == 0) { return; } string f_remote_dir = package_dir_ + "/" + underscore(service_name_) + "-remote"; MKDIR(f_remote_dir.c_str()); vector::iterator f_iter; string f_remote_name = f_remote_dir + "/" + underscore(service_name_) + "-remote.go"; ofstream_with_content_based_conditional_update f_remote; f_remote.open(f_remote_name.c_str()); string unused_protection; std::vector system_packages; system_packages.push_back("context"); system_packages.push_back("flag"); system_packages.push_back("fmt"); system_packages.push_back("math"); system_packages.push_back("net"); system_packages.push_back("net/url"); system_packages.push_back("os"); system_packages.push_back("strconv"); system_packages.push_back("strings"); // For the thrift import, always do rename import to make sure it's called thrift. system_packages.push_back("thrift \"" + gen_thrift_import_ + "\""); f_remote << go_autogen_comment(); f_remote << indent() << "package main" << endl << endl; f_remote << indent() << "import (" << endl; f_remote << render_system_packages(system_packages); f_remote << indent() << render_included_programs(unused_protection); f_remote << render_program_import(program_, unused_protection); f_remote << indent() << ")" << endl; f_remote << indent() << endl; f_remote << indent() << unused_protection; // filled in render_included_programs() f_remote << indent() << endl; f_remote << indent() << "func Usage() {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Usage of \", os.Args[0], \" " "[-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\")" << endl; f_remote << indent() << " flag.PrintDefaults()" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"\\nFunctions:\")" << endl; string package_name_aliased = package_identifiers_[get_real_go_module(program_)]; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_remote << " fmt.Fprintln(os.Stderr, \" " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "("; t_struct* arg_struct = (*f_iter)->get_arglist(); const std::vector& args = arg_struct->get_members(); std::vector::size_type num_args = args.size(); bool first = true; for (std::vector::size_type i = 0; i < num_args; ++i) { if (first) { first = false; } else { f_remote << ", "; } f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name(); } f_remote << ")\")" << endl; } f_remote << indent() << " fmt.Fprintln(os.Stderr)" << endl; f_remote << indent() << " os.Exit(0)" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << endl; f_remote << indent() << "type httpHeaders map[string]string" << endl; f_remote << indent() << endl; f_remote << indent() << "func (h httpHeaders) String() string {" << endl; f_remote << indent() << " var m map[string]string = h" << endl; f_remote << indent() << " return fmt.Sprintf(\"%s\", m)" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << endl; f_remote << indent() << "func (h httpHeaders) Set(value string) error {" << endl; f_remote << indent() << " parts := strings.Split(value, \": \")" << endl; f_remote << indent() << " if len(parts) != 2 {" << endl; f_remote << indent() << " return fmt.Errorf(\"header should be of format 'Key: Value'\")" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << " h[parts[0]] = parts[1]" << endl; f_remote << indent() << " return nil" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << endl; f_remote << indent() << "func main() {" << endl; indent_up(); f_remote << indent() << "flag.Usage = Usage" << endl; f_remote << indent() << "var host string" << endl; f_remote << indent() << "var port int" << endl; f_remote << indent() << "var protocol string" << endl; f_remote << indent() << "var urlString string" << endl; f_remote << indent() << "var framed bool" << endl; f_remote << indent() << "var useHttp bool" << endl; f_remote << indent() << "headers := make(httpHeaders)" << endl; f_remote << indent() << "var parsedUrl *url.URL" << endl; f_remote << indent() << "var trans thrift.TTransport" << endl; f_remote << indent() << "_ = strconv.Atoi" << endl; f_remote << indent() << "_ = math.Abs" << endl; f_remote << indent() << "flag.Usage = Usage" << endl; f_remote << indent() << "flag.StringVar(&host, \"h\", \"localhost\", \"Specify host and port\")" << endl; f_remote << indent() << "flag.IntVar(&port, \"p\", 9090, \"Specify port\")" << endl; f_remote << indent() << "flag.StringVar(&protocol, \"P\", \"binary\", \"" "Specify the protocol (binary, compact, simplejson, json)\")" << endl; f_remote << indent() << "flag.StringVar(&urlString, \"u\", \"\", \"Specify the url\")" << endl; f_remote << indent() << "flag.BoolVar(&framed, \"framed\", false, \"Use framed transport\")" << endl; f_remote << indent() << "flag.BoolVar(&useHttp, \"http\", false, \"Use http\")" << endl; f_remote << indent() << "flag.Var(headers, \"H\", \"Headers to set on the http(s) request (e.g. -H \\\"Key: Value\\\")\")" << endl; f_remote << indent() << "flag.Parse()" << endl; f_remote << indent() << endl; f_remote << indent() << "if len(urlString) > 0 {" << endl; f_remote << indent() << " var err error" << endl; f_remote << indent() << " parsedUrl, err = url.Parse(urlString)" << endl; f_remote << indent() << " if err != nil {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl; f_remote << indent() << " flag.Usage()" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << " host = parsedUrl.Host" << endl; f_remote << indent() << " useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == \"http\" || parsedUrl.Scheme == \"https\"" << endl; f_remote << indent() << "} else if useHttp {" << endl; f_remote << indent() << " _, err := url.Parse(fmt.Sprint(\"http://\", host, \":\", port))" << endl; f_remote << indent() << " if err != nil {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl; f_remote << indent() << " flag.Usage()" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << endl; f_remote << indent() << "cmd := flag.Arg(0)" << endl; f_remote << indent() << "var err error" << endl; f_remote << indent() << "var cfg *thrift.TConfiguration = nil" << endl; f_remote << indent() << "if useHttp {" << endl; f_remote << indent() << " trans, err = thrift.NewTHttpClient(parsedUrl.String())" << endl; f_remote << indent() << " if len(headers) > 0 {" << endl; f_remote << indent() << " httptrans := trans.(*thrift.THttpClient)" << endl; f_remote << indent() << " for key, value := range headers {" << endl; f_remote << indent() << " httptrans.SetHeader(key, value)" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << "} else {" << endl; f_remote << indent() << " portStr := fmt.Sprint(port)" << endl; f_remote << indent() << " if strings.Contains(host, \":\") {" << endl; f_remote << indent() << " host, portStr, err = net.SplitHostPort(host)" << endl; f_remote << indent() << " if err != nil {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"error with host:\", err)" << endl; f_remote << indent() << " os.Exit(1)" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << " trans = thrift.NewTSocketConf(net.JoinHostPort(host, portStr), cfg)" << endl; f_remote << indent() << " if err != nil {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"error resolving address:\", err)" << endl; f_remote << indent() << " os.Exit(1)" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << " if framed {" << endl; f_remote << indent() << " trans = thrift.NewTFramedTransportConf(trans, cfg)" << endl; f_remote << indent() << " }" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "if err != nil {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error creating transport\", err)" << endl; f_remote << indent() << " os.Exit(1)" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "defer trans.Close()" << endl; f_remote << indent() << "var protocolFactory thrift.TProtocolFactory" << endl; f_remote << indent() << "switch protocol {" << endl; f_remote << indent() << "case \"compact\":" << endl; f_remote << indent() << " protocolFactory = thrift.NewTCompactProtocolFactoryConf(cfg)" << endl; f_remote << indent() << " break" << endl; f_remote << indent() << "case \"simplejson\":" << endl; f_remote << indent() << " protocolFactory = thrift.NewTSimpleJSONProtocolFactoryConf(cfg)" << endl; f_remote << indent() << " break" << endl; f_remote << indent() << "case \"json\":" << endl; f_remote << indent() << " protocolFactory = thrift.NewTJSONProtocolFactory()" << endl; f_remote << indent() << " break" << endl; f_remote << indent() << "case \"binary\", \"\":" << endl; f_remote << indent() << " protocolFactory = thrift.NewTBinaryProtocolFactoryConf(cfg)" << endl; f_remote << indent() << " break" << endl; f_remote << indent() << "default:" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Invalid protocol specified: \", protocol)" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " os.Exit(1)" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "iprot := protocolFactory.GetProtocol(trans)" << endl; f_remote << indent() << "oprot := protocolFactory.GetProtocol(trans)" << endl; f_remote << indent() << "client := " << package_name_aliased << ".New" << publicize(service_name_) << "Client(thrift.NewTStandardClient(iprot, oprot))" << endl; f_remote << indent() << "if err := trans.Open(); err != nil {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Error opening socket to \", " "host, \":\", port, \" \", err)" << endl; f_remote << indent() << " os.Exit(1)" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << endl; f_remote << indent() << "switch cmd {" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const std::vector& args = arg_struct->get_members(); std::vector::size_type num_args = args.size(); string funcName((*f_iter)->get_name()); string pubName(publicize(funcName)); string argumentsName(publicize(funcName + "_args", true, func_to_service[funcName])); f_remote << indent() << "case \"" << escape_string(funcName) << "\":" << endl; indent_up(); f_remote << indent() << "if flag.NArg() - 1 != " << num_args << " {" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"" << escape_string(pubName) << " requires " << num_args << " args\")" << endl; f_remote << indent() << " flag.Usage()" << endl; f_remote << indent() << "}" << endl; for (std::vector::size_type i = 0; i < num_args; ++i) { std::vector::size_type flagArg = i + 1; t_type* the_type(args[i]->get_type()); t_type* the_type2(get_true_type(the_type)); if (the_type2->is_enum()) { f_remote << indent() << "tmp" << i << ", err := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl; f_remote << indent() << "if err != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "argvalue" << i << " := " << package_name_aliased << "." << publicize(the_type->get_name()) << "(tmp" << i << ")" << endl; } else if (the_type2->is_base_type()) { t_base_type::t_base e = ((t_base_type*)the_type2)->get_base(); string err(tmp("err")); switch (e) { case t_base_type::TYPE_VOID: break; case t_base_type::TYPE_STRING: if (the_type2->is_binary()) { f_remote << indent() << "argvalue" << i << " := []byte(flag.Arg(" << flagArg << "))" << endl; } else { f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ")" << endl; } break; case t_base_type::TYPE_BOOL: f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ") == \"true\"" << endl; break; case t_base_type::TYPE_I8: f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl; f_remote << indent() << "if " << err << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "argvalue" << i << " := int8(tmp" << i << ")" << endl; break; case t_base_type::TYPE_I16: f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl; f_remote << indent() << "if " << err << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "argvalue" << i << " := int16(tmp" << i << ")" << endl; break; case t_base_type::TYPE_I32: f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl; f_remote << indent() << "if " << err << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "argvalue" << i << " := int32(tmp" << i << ")" << endl; break; case t_base_type::TYPE_I64: f_remote << indent() << "argvalue" << i << ", " << err << " := (strconv.ParseInt(flag.Arg(" << flagArg << "), 10, 64))" << endl; f_remote << indent() << "if " << err << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; break; case t_base_type::TYPE_DOUBLE: f_remote << indent() << "argvalue" << i << ", " << err << " := (strconv.ParseFloat(flag.Arg(" << flagArg << "), 64))" << endl; f_remote << indent() << "if " << err << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; break; default: throw("Invalid base type in generate_service_remote"); } // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg << // ")))"; } else if (the_type2->is_struct()) { string arg(tmp("arg")); string mbTrans(tmp("mbTrans")); string err1(tmp("err")); string factory(tmp("factory")); string jsProt(tmp("jsProt")); string err2(tmp("err")); std::string tstruct_name(publicize(the_type->get_name())); std::string tstruct_module( module_name(the_type)); if(tstruct_module.empty()) { tstruct_module = package_name_aliased; } f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl; f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))" << endl; f_remote << indent() << "defer " << mbTrans << ".Close()" << endl; f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")" << endl; f_remote << indent() << "if " << err1 << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << factory << " := thrift.NewTJSONProtocolFactory()" << endl; f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")" << endl; f_remote << indent() << "argvalue" << i << " := " << tstruct_module << ".New" << tstruct_name << "()" << endl; f_remote << indent() << err2 << " := argvalue" << i << "." << read_method_name_ << "(context.Background(), " << jsProt << ")" << endl; f_remote << indent() << "if " << err2 << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; } else if (the_type2->is_container() || the_type2->is_xception()) { string arg(tmp("arg")); string mbTrans(tmp("mbTrans")); string err1(tmp("err")); string factory(tmp("factory")); string jsProt(tmp("jsProt")); string err2(tmp("err")); std::string argName(publicize(args[i]->get_name())); f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl; f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))" << endl; f_remote << indent() << "defer " << mbTrans << ".Close()" << endl; f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")" << endl; f_remote << indent() << "if " << err1 << " != nil { " << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << factory << " := thrift.NewTJSONProtocolFactory()" << endl; f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")" << endl; f_remote << indent() << "containerStruct" << i << " := " << package_name_aliased << ".New" << argumentsName << "()" << endl; f_remote << indent() << err2 << " := containerStruct" << i << ".ReadField" << (i + 1) << "(context.Background(), " << jsProt << ")" << endl; f_remote << indent() << "if " << err2 << " != nil {" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " return" << endl; f_remote << indent() << "}" << endl; f_remote << indent() << "argvalue" << i << " := containerStruct" << i << "." << argName << endl; } else { throw("Invalid argument type in generate_service_remote"); } if (the_type->is_typedef()) { std::string typedef_module(module_name(the_type)); if(typedef_module.empty()) { typedef_module = package_name_aliased; } f_remote << indent() << "value" << i << " := " << typedef_module << "." << publicize(the_type->get_name()) << "(argvalue" << i << ")" << endl; } else { f_remote << indent() << "value" << i << " := argvalue" << i << endl; } } f_remote << indent() << "fmt.Print(client." << pubName << "("; bool argFirst = true; f_remote << "context.Background()"; for (std::vector::size_type i = 0; i < num_args; ++i) { if (argFirst) { argFirst = false; f_remote << ", "; } else { f_remote << ", "; } if (args[i]->get_type()->is_enum()) { f_remote << "value" << i; } else if (args[i]->get_type()->is_base_type()) { t_base_type::t_base e = ((t_base_type*)(args[i]->get_type()))->get_base(); switch (e) { case t_base_type::TYPE_VOID: break; case t_base_type::TYPE_STRING: case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: f_remote << "value" << i; break; default: throw("Invalid base type in generate_service_remote"); } // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg << // ")))"; } else { f_remote << "value" << i; } } f_remote << "))" << endl; f_remote << indent() << "fmt.Print(\"\\n\")" << endl; f_remote << indent() << "break" << endl; indent_down(); } f_remote << indent() << "case \"\":" << endl; f_remote << indent() << " Usage()" << endl; f_remote << indent() << " break" << endl; f_remote << indent() << "default:" << endl; f_remote << indent() << " fmt.Fprintln(os.Stderr, \"Invalid function \", cmd)" << endl; f_remote << indent() << "}" << endl; indent_down(); f_remote << indent() << "}" << endl; // Close service file f_remote.close(); format_go_output(f_remote_name); #ifndef _MSC_VER // Make file executable, love that bitwise OR action chmod(f_remote_name.c_str(), S_IRUSR | S_IWUSR | S_IXUSR #ifndef _WIN32 | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH #endif ); #endif } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_go_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_processor = ""; string extends_processor_new = ""; string serviceName(publicize(tservice->get_name())); if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); size_t index = extends.rfind("."); if (index != string::npos) { extends_processor = extends.substr(0, index + 1) + publicize(extends.substr(index + 1)) + "Processor"; extends_processor_new = extends.substr(0, index + 1) + "New" + publicize(extends.substr(index + 1)) + "Processor"; } else { extends_processor = publicize(extends) + "Processor"; extends_processor_new = "New" + extends_processor; } } string pServiceName(privatize(tservice->get_name())); // Generate the header portion string self(tmp("self")); if (extends_processor.empty()) { f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl; f_types_ << indent() << " processorMap map[string]thrift.TProcessorFunction" << endl; f_types_ << indent() << " handler " << serviceName << endl; f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func (p *" << serviceName << "Processor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {" << endl; f_types_ << indent() << " p.processorMap[key] = processor" << endl; f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func (p *" << serviceName << "Processor) GetProcessorFunction(key string) " "(processor thrift.TProcessorFunction, ok bool) {" << endl; f_types_ << indent() << " processor, ok = p.processorMap[key]" << endl; f_types_ << indent() << " return processor, ok" << endl; f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func (p *" << serviceName << "Processor) ProcessorMap() map[string]thrift.TProcessorFunction {" << endl; f_types_ << indent() << " return p.processorMap" << endl; f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName << ") *" << serviceName << "Processor {" << endl << endl; f_types_ << indent() << " " << self << " := &" << serviceName << "Processor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string escapedFuncName(escape_string((*f_iter)->get_name())); f_types_ << indent() << " " << self << ".processorMap[\"" << escapedFuncName << "\"] = &" << pServiceName << "Processor" << publicize((*f_iter)->get_name()) << "{handler:handler}" << endl; } string x(tmp("x")); f_types_ << indent() << "return " << self << endl; f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func (p *" << serviceName << "Processor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err " "thrift.TException) {" << endl; f_types_ << indent() << " name, _, seqId, err2 := iprot.ReadMessageBegin(ctx)" << endl; f_types_ << indent() << " if err2 != nil { return false, thrift.WrapTException(err2) }" << endl; f_types_ << indent() << " if processor, ok := p.GetProcessorFunction(name); ok {" << endl; f_types_ << indent() << " return processor.Process(ctx, seqId, iprot, oprot)" << endl; f_types_ << indent() << " }" << endl; f_types_ << indent() << " iprot.Skip(ctx, thrift.STRUCT)" << endl; f_types_ << indent() << " iprot.ReadMessageEnd(ctx)" << endl; f_types_ << indent() << " " << x << " := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, \"Unknown function " "\" + name)" << endl; f_types_ << indent() << " oprot.WriteMessageBegin(ctx, name, thrift.EXCEPTION, seqId)" << endl; f_types_ << indent() << " " << x << ".Write(ctx, oprot)" << endl; f_types_ << indent() << " oprot.WriteMessageEnd(ctx)" << endl; f_types_ << indent() << " oprot.Flush(ctx)" << endl; f_types_ << indent() << " return false, " << x << endl; f_types_ << indent() << "" << endl; f_types_ << indent() << "}" << endl << endl; } else { f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl; f_types_ << indent() << " *" << extends_processor << endl; f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName << ") *" << serviceName << "Processor {" << endl; f_types_ << indent() << " " << self << " := &" << serviceName << "Processor{" << extends_processor_new << "(handler)}" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string escapedFuncName(escape_string((*f_iter)->get_name())); f_types_ << indent() << " " << self << ".AddToProcessorMap(\"" << escapedFuncName << "\", &" << pServiceName << "Processor" << publicize((*f_iter)->get_name()) << "{handler:handler})" << endl; } f_types_ << indent() << " return " << self << endl; f_types_ << indent() << "}" << endl << endl; } // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } f_types_ << endl; } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_go_generator::generate_process_function(t_service* tservice, t_function* tfunction) { // Open function string processorName = privatize(tservice->get_name()) + "Processor" + publicize(tfunction->get_name()); string argsname = publicize(tfunction->get_name() + "_args", true); string resultname = publicize(tfunction->get_name() + "_result", true); // t_struct* xs = tfunction->get_xceptions(); // const std::vector& xceptions = xs->get_members(); f_types_ << indent() << "type " << processorName << " struct {" << endl; f_types_ << indent() << " handler " << publicize(tservice->get_name()) << endl; f_types_ << indent() << "}" << endl << endl; f_types_ << indent() << "func (p *" << processorName << ") Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err " "thrift.TException) {" << endl; indent_up(); f_types_ << indent() << "args := " << argsname << "{}" << endl; f_types_ << indent() << "var err2 error" << endl; f_types_ << indent() << "if err2 = args." << read_method_name_ << "(ctx, iprot); err2 != nil {" << endl; f_types_ << indent() << " iprot.ReadMessageEnd(ctx)" << endl; if (!tfunction->is_oneway()) { f_types_ << indent() << " x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())" << endl; f_types_ << indent() << " oprot.WriteMessageBegin(ctx, \"" << escape_string(tfunction->get_name()) << "\", thrift.EXCEPTION, seqId)" << endl; f_types_ << indent() << " x.Write(ctx, oprot)" << endl; f_types_ << indent() << " oprot.WriteMessageEnd(ctx)" << endl; f_types_ << indent() << " oprot.Flush(ctx)" << endl; } f_types_ << indent() << " return false, thrift.WrapTException(err2)" << endl; f_types_ << indent() << "}" << endl; f_types_ << indent() << "iprot.ReadMessageEnd(ctx)" << endl << endl; // Even though we never create the goroutine in oneway handlers, // always have (nop) tickerCancel defined makes the writing part of code // generating easier and less error-prone. f_types_ << indent() << "tickerCancel := func() {}" << endl; // Only create the goroutine for non-oneways. if (!tfunction->is_oneway()) { f_types_ << indent() << "// Start a goroutine to do server side connectivity check." << endl; f_types_ << indent() << "if thrift.ServerConnectivityCheckInterval > 0 {" << endl; indent_up(); f_types_ << indent() << "var cancel context.CancelFunc" << endl; f_types_ << indent() << "ctx, cancel = context.WithCancel(ctx)" << endl; f_types_ << indent() << "defer cancel()" << endl; f_types_ << indent() << "var tickerCtx context.Context" << endl; f_types_ << indent() << "tickerCtx, tickerCancel = context.WithCancel(context.Background())" << endl; f_types_ << indent() << "defer tickerCancel()" << endl; f_types_ << indent() << "go func(ctx context.Context, cancel context.CancelFunc) {" << endl; indent_up(); f_types_ << indent() << "ticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)" << endl; f_types_ << indent() << "defer ticker.Stop()" << endl; f_types_ << indent() << "for {" << endl; indent_up(); f_types_ << indent() << "select {" << endl; f_types_ << indent() << "case <-ctx.Done():" << endl; indent_up(); f_types_ << indent() << "return" << endl; indent_down(); f_types_ << indent() << "case <-ticker.C:" << endl; indent_up(); f_types_ << indent() << "if !iprot.Transport().IsOpen() {" << endl; indent_up(); f_types_ << indent() << "cancel()" << endl; f_types_ << indent() << "return" << endl; indent_down(); f_types_ << indent() << "}" << endl; indent_down(); f_types_ << indent() << "}" << endl; indent_down(); f_types_ << indent() << "}" << endl; indent_down(); f_types_ << indent() << "}(tickerCtx, cancel)" << endl; indent_down(); f_types_ << indent() << "}" << endl << endl; } else { // Make sure we don't get the defined but unused compiling error. f_types_ << indent() << "_ = tickerCancel" << endl << endl; } if (!tfunction->is_oneway()) { f_types_ << indent() << "result := " << resultname << "{}" << endl; } bool need_reference = type_need_reference(tfunction->get_returntype()); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_types_ << indent() << "var retval " << type_to_go_type(tfunction->get_returntype()) << endl; } f_types_ << indent() << "if "; if (!tfunction->is_oneway()) { if (!tfunction->get_returntype()->is_void()) { f_types_ << "retval, "; } } // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_types_ << "err2 = p.handler." << publicize(tfunction->get_name()) << "("; bool first = true; f_types_ << "ctx"; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; f_types_ << ", "; } else { f_types_ << ", "; } f_types_ << "args." << publicize((*f_iter)->get_name()); } f_types_ << "); err2 != nil {" << endl; f_types_ << indent() << " tickerCancel()" << endl; t_struct* exceptions = tfunction->get_xceptions(); const vector& x_fields = exceptions->get_members(); if (!x_fields.empty()) { f_types_ << indent() << "switch v := err2.(type) {" << endl; vector::const_iterator xf_iter; for (xf_iter = x_fields.begin(); xf_iter != x_fields.end(); ++xf_iter) { f_types_ << indent() << " case " << type_to_go_type(((*xf_iter)->get_type())) << ":" << endl; f_types_ << indent() << "result." << publicize((*xf_iter)->get_name()) << " = v" << endl; } f_types_ << indent() << " default:" << endl; } if (!tfunction->is_oneway()) { // Avoid writing the error to the wire if it's ErrAbandonRequest f_types_ << indent() << " if err2 == thrift.ErrAbandonRequest {" << endl; f_types_ << indent() << " return false, thrift.WrapTException(err2)" << endl; f_types_ << indent() << " }" << endl; f_types_ << indent() << " x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, " "\"Internal error processing " << escape_string(tfunction->get_name()) << ": \" + err2.Error())" << endl; f_types_ << indent() << " oprot.WriteMessageBegin(ctx, \"" << escape_string(tfunction->get_name()) << "\", thrift.EXCEPTION, seqId)" << endl; f_types_ << indent() << " x.Write(ctx, oprot)" << endl; f_types_ << indent() << " oprot.WriteMessageEnd(ctx)" << endl; f_types_ << indent() << " oprot.Flush(ctx)" << endl; } f_types_ << indent() << " return true, thrift.WrapTException(err2)" << endl; if (!x_fields.empty()) { f_types_ << indent() << "}" << endl; } f_types_ << indent() << "}"; // closes err2 != nil if (!tfunction->is_oneway()) { if (!tfunction->get_returntype()->is_void()) { f_types_ << " else {" << endl; // make sure we set Success retval only on success indent_up(); f_types_ << indent() << "result.Success = "; if (need_reference) { f_types_ << "&"; } f_types_ << "retval" << endl; indent_down(); f_types_ << indent() << "}" << endl; } else { f_types_ << endl; } f_types_ << indent() << "tickerCancel()" << endl; f_types_ << indent() << "if err2 = oprot.WriteMessageBegin(ctx, \"" << escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqId); err2 != nil {" << endl; f_types_ << indent() << " err = thrift.WrapTException(err2)" << endl; f_types_ << indent() << "}" << endl; f_types_ << indent() << "if err2 = result." << write_method_name_ << "(ctx, oprot); err == nil && err2 != nil {" << endl; f_types_ << indent() << " err = thrift.WrapTException(err2)" << endl; f_types_ << indent() << "}" << endl; f_types_ << indent() << "if err2 = oprot.WriteMessageEnd(ctx); err == nil && err2 != nil {" << endl; f_types_ << indent() << " err = thrift.WrapTException(err2)" << endl; f_types_ << indent() << "}" << endl; f_types_ << indent() << "if err2 = oprot.Flush(ctx); err == nil && err2 != nil {" << endl; f_types_ << indent() << " err = thrift.WrapTException(err2)" << endl; f_types_ << indent() << "}" << endl; f_types_ << indent() << "if err != nil {" << endl; f_types_ << indent() << " return" << endl; f_types_ << indent() << "}" << endl; f_types_ << indent() << "return true, err" << endl; } else { f_types_ << endl; f_types_ << indent() << "tickerCancel()" << endl; f_types_ << indent() << "return true, nil" << endl; } indent_down(); f_types_ << indent() << "}" << endl << endl; } /** * Deserializes a field of any type. */ void t_go_generator::generate_deserialize_field(ostream& out, t_field* tfield, bool declare, string prefix, bool inclass, bool coerceData, bool inkey, bool in_container_value) { (void)inclass; (void)coerceData; t_type* orig_type = tfield->get_type(); t_type* type = get_true_type(orig_type); string name(prefix + publicize(tfield->get_name())); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + name; } if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, is_pointer_field(tfield, in_container_value), declare, name); } else if (type->is_container()) { generate_deserialize_container(out, orig_type, is_pointer_field(tfield), declare, name); } else if (type->is_base_type() || type->is_enum()) { if (declare) { string type_name = inkey ? type_to_go_key_type(tfield->get_type()) : type_to_go_type(tfield->get_type()); out << "var " << tfield->get_name() << " " << type_name << endl; } indent(out) << "if v, err := iprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary() && !inkey) { out << "ReadBinary(ctx)"; } else { out << "ReadString(ctx)"; } break; case t_base_type::TYPE_BOOL: out << "ReadBool(ctx)"; break; case t_base_type::TYPE_I8: out << "ReadByte(ctx)"; break; case t_base_type::TYPE_I16: out << "ReadI16(ctx)"; break; case t_base_type::TYPE_I32: out << "ReadI32(ctx)"; break; case t_base_type::TYPE_I64: out << "ReadI64(ctx)"; break; case t_base_type::TYPE_DOUBLE: out << "ReadDouble(ctx)"; break; default: throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "ReadI32(ctx)"; } out << "; err != nil {" << endl; out << indent() << "return thrift.PrependError(\"error reading field " << tfield->get_key() << ": \", err)" << endl; out << "} else {" << endl; string wrap; if (type->is_enum() || orig_type->is_typedef()) { wrap = publicize(type_name(orig_type)); } else if (((t_base_type*)type)->get_base() == t_base_type::TYPE_I8) { wrap = "int8"; } string maybe_address = (is_pointer_field(tfield) ? "&" : ""); if (wrap == "") { indent(out) << name << " = " << maybe_address << "v" << endl; } else { indent(out) << "temp := " << wrap << "(v)" << endl; indent(out) << name << " = " << maybe_address << "temp" << endl; } out << "}" << endl; } else { throw "INVALID TYPE IN generate_deserialize_field '" + type->get_name() + "' for field '" + tfield->get_name() + "'"; } } /** * Generates an unserializer for a struct, calling read() */ void t_go_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, bool pointer_field, bool declare, string prefix) { string eq(declare ? " := " : " = "); out << indent() << prefix << eq << (pointer_field ? "&" : ""); generate_go_struct_initializer(out, tstruct); out << indent() << "if err := " << prefix << "." << read_method_name_ << "(ctx, iprot); err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", " << prefix << "), err)" << endl; out << indent() << "}" << endl; } /** * Serialize a container by writing out the header followed by * data and then a footer. */ void t_go_generator::generate_deserialize_container(ostream& out, t_type* orig_type, bool pointer_field, bool declare, string prefix) { t_type* ttype = get_true_type(orig_type); string eq(" = "); if (declare) { eq = " := "; } // Declare variables, read header if (ttype->is_map()) { out << indent() << "_, _, size, err := iprot.ReadMapBegin(ctx)" << endl; out << indent() << "if err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error reading map begin: \", err)" << endl; out << indent() << "}" << endl; out << indent() << "tMap := make(" << type_to_go_type(orig_type) << ", size)" << endl; out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tMap" << endl; } else if (ttype->is_set()) { out << indent() << "_, size, err := iprot.ReadSetBegin(ctx)" << endl; out << indent() << "if err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error reading set begin: \", err)" << endl; out << indent() << "}" << endl; out << indent() << "tSet := make(" << type_to_go_type(orig_type) << ", 0, size)" << endl; out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSet" << endl; } else if (ttype->is_list()) { out << indent() << "_, size, err := iprot.ReadListBegin(ctx)" << endl; out << indent() << "if err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error reading list begin: \", err)" << endl; out << indent() << "}" << endl; out << indent() << "tSlice := make(" << type_to_go_type(orig_type) << ", 0, size)" << endl; out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSlice" << endl; } else { throw "INVALID TYPE IN generate_deserialize_container '" + ttype->get_name() + "' for prefix '" + prefix + "'"; } // For loop iterates over elements out << indent() << "for i := 0; i < size; i ++ {" << endl; indent_up(); if (pointer_field) { prefix = "(*" + prefix + ")"; } if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, declare, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, declare, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, declare, prefix); } indent_down(); out << indent() << "}" << endl; // Read container end if (ttype->is_map()) { out << indent() << "if err := iprot.ReadMapEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error reading map end: \", err)" << endl; out << indent() << "}" << endl; } else if (ttype->is_set()) { out << indent() << "if err := iprot.ReadSetEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error reading set end: \", err)" << endl; out << indent() << "}" << endl; } else if (ttype->is_list()) { out << indent() << "if err := iprot.ReadListEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error reading list end: \", err)" << endl; out << indent() << "}" << endl; } } /** * Generates code to deserialize a map */ void t_go_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, bool declare, string prefix) { (void)declare; string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); fkey.set_req(t_field::T_OPT_IN_REQ_OUT); fval.set_req(t_field::T_OPT_IN_REQ_OUT); generate_deserialize_field(out, &fkey, true, "", false, false, true); generate_deserialize_field(out, &fval, true, "", false, false, false, true); indent(out) << prefix << "[" << key << "] = " << val << endl; } /** * Write a set element */ void t_go_generator::generate_deserialize_set_element(ostream& out, t_set* tset, bool declare, string prefix) { (void)declare; string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); felem.set_req(t_field::T_OPT_IN_REQ_OUT); generate_deserialize_field(out, &felem, true, "", false, false, false, true); indent(out) << prefix << " = append(" << prefix << ", " << elem << ")" << endl; } /** * Write a list element */ void t_go_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, bool declare, string prefix) { (void)declare; string elem = tmp("_elem"); t_field felem(((t_list*)tlist)->get_elem_type(), elem); felem.set_req(t_field::T_OPT_IN_REQ_OUT); generate_deserialize_field(out, &felem, true, "", false, false, false, true); indent(out) << prefix << " = append(" << prefix << ", " << elem << ")" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_go_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, bool inkey) { t_type* type = get_true_type(tfield->get_type()); string name(prefix + publicize(tfield->get_name())); // Do nothing for void types if (type->is_void()) { throw "compiler error: cannot generate serialize for void type: " + name; } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_serialize_container(out, type, is_pointer_field(tfield), name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << "if err := oprot."; if (is_pointer_field(tfield)) { name = "*" + name; } if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary() && !inkey) { out << "WriteBinary(ctx, " << name << ")"; } else { out << "WriteString(ctx, string(" << name << "))"; } break; case t_base_type::TYPE_BOOL: out << "WriteBool(ctx, bool(" << name << "))"; break; case t_base_type::TYPE_I8: out << "WriteByte(ctx, int8(" << name << "))"; break; case t_base_type::TYPE_I16: out << "WriteI16(ctx, int16(" << name << "))"; break; case t_base_type::TYPE_I32: out << "WriteI32(ctx, int32(" << name << "))"; break; case t_base_type::TYPE_I64: out << "WriteI64(ctx, int64(" << name << "))"; break; case t_base_type::TYPE_DOUBLE: out << "WriteDouble(ctx, float64(" << name << "))"; break; default: throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "WriteI32(ctx, int32(" << name << "))"; } out << "; err != nil {" << endl; out << indent() << "return thrift.PrependError(fmt.Sprintf(\"%T." << escape_string(tfield->get_name()) << " (" << tfield->get_key() << ") field write error: \", p), err) }" << endl; } else { throw "compiler error: Invalid type in generate_serialize_field '" + type->get_name() + "' for field '" + name + "'"; } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_go_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; out << indent() << "if err := " << prefix << "." << write_method_name_ << "(ctx, oprot); err != nil {" << endl; out << indent() << " return thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", " << prefix << "), err)" << endl; out << indent() << "}" << endl; } void t_go_generator::generate_serialize_container(ostream& out, t_type* ttype, bool pointer_field, string prefix) { if (pointer_field) { prefix = "*" + prefix; } if (ttype->is_map()) { out << indent() << "if err := oprot.WriteMapBegin(ctx, " << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "len(" << prefix << ")); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error writing map begin: \", err)" << endl; out << indent() << "}" << endl; } else if (ttype->is_set()) { out << indent() << "if err := oprot.WriteSetBegin(ctx, " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << "len(" << prefix << ")); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error writing set begin: \", err)" << endl; out << indent() << "}" << endl; } else if (ttype->is_list()) { out << indent() << "if err := oprot.WriteListBegin(ctx, " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << "len(" << prefix << ")); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error writing list begin: \", err)" << endl; out << indent() << "}" << endl; } else { throw "compiler error: Invalid type in generate_serialize_container '" + ttype->get_name() + "' for prefix '" + prefix + "'"; } if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; out << indent() << "for k, v := range " << prefix << " {" << endl; indent_up(); generate_serialize_map_element(out, tmap, "k", "v"); indent_down(); indent(out) << "}" << endl; } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; out << indent() << "for i := 0; iget_elem_type()); out << indent() << "if func(tgt, src " << goType << ") bool {" << endl; indent_up(); generate_go_equals(out, tset->get_elem_type(), "tgt", "src"); out << indent() << "return true" << endl; indent_down(); out << indent() << "}(" << wrapped_prefix << "[i], " << wrapped_prefix << "[j]) {" << endl; indent_up(); out << indent() << "return thrift.PrependError(\"\", fmt.Errorf(\"%T error writing set field: slice is not " "unique\", " << wrapped_prefix << "))" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl; out << indent() << "for _, v := range " << prefix << " {" << endl; indent_up(); generate_serialize_set_element(out, tset, "v"); indent_down(); indent(out) << "}" << endl; } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; out << indent() << "for _, v := range " << prefix << " {" << endl; indent_up(); generate_serialize_list_element(out, tlist, "v"); indent_down(); indent(out) << "}" << endl; } if (ttype->is_map()) { out << indent() << "if err := oprot.WriteMapEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error writing map end: \", err)" << endl; out << indent() << "}" << endl; } else if (ttype->is_set()) { out << indent() << "if err := oprot.WriteSetEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error writing set end: \", err)" << endl; out << indent() << "}" << endl; } else if (ttype->is_list()) { out << indent() << "if err := oprot.WriteListEnd(ctx); err != nil {" << endl; out << indent() << " return thrift.PrependError(\"error writing list end: \", err)" << endl; out << indent() << "}" << endl; } } /** * Serializes the members of a map. * */ void t_go_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter) { t_field kfield(tmap->get_key_type(), ""); t_field vfield(tmap->get_val_type(), ""); kfield.set_req(t_field::T_OPT_IN_REQ_OUT); vfield.set_req(t_field::T_OPT_IN_REQ_OUT); generate_serialize_field(out, &kfield, kiter, true); generate_serialize_field(out, &vfield, viter); } /** * Serializes the members of a set. */ void t_go_generator::generate_serialize_set_element(ostream& out, t_set* tset, string prefix) { t_field efield(tset->get_elem_type(), ""); efield.set_req(t_field::T_OPT_IN_REQ_OUT); generate_serialize_field(out, &efield, prefix); } /** * Serializes the members of a list. */ void t_go_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string prefix) { t_field efield(tlist->get_elem_type(), ""); efield.set_req(t_field::T_OPT_IN_REQ_OUT); generate_serialize_field(out, &efield, prefix); } /** * Compares any type */ void t_go_generator::generate_go_equals(ostream& out, t_type* ori_type, string tgt, string src) { t_type* ttype = get_true_type(ori_type); // Do nothing for void types if (ttype->is_void()) { throw "compiler error: cannot generate equals for void type: " + tgt; } if (ttype->is_struct() || ttype->is_xception()) { generate_go_equals_struct(out, ttype, tgt, src); } else if (ttype->is_container()) { generate_go_equals_container(out, ttype, tgt, src); } else if (ttype->is_base_type() || ttype->is_enum()) { out << indent() << "if "; if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot equals void: " + tgt; break; case t_base_type::TYPE_STRING: if (ttype->is_binary()) { out << "bytes.Compare(" << tgt << ", " << src << ") != 0"; } else { out << tgt << " != " << src; } break; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: out << tgt << " != " << src; break; default: throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase); } } else if (ttype->is_enum()) { out << tgt << " != " << src; } out << " { return false }" << endl; } else { throw "compiler error: Invalid type in generate_go_equals '" + ttype->get_name() + "' for '" + tgt + "'"; } } /** * Compares the members of a struct */ void t_go_generator::generate_go_equals_struct(ostream& out, t_type* ttype, string tgt, string src) { (void)ttype; out << indent() << "if !" << tgt << "." << equals_method_name_ << "(" << src << ") { return false }" << endl; } /** * Compares any container type */ void t_go_generator::generate_go_equals_container(ostream& out, t_type* ttype, string tgt, string src) { out << indent() << "if len(" << tgt << ") != len(" << src << ") { return false }" << endl; if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; out << indent() << "for k, _tgt := range " << tgt << " {" << endl; indent_up(); string element_source = tmp("_src"); out << indent() << element_source << " := " << src << "[k]" << endl; generate_go_equals(out, tmap->get_val_type(), "_tgt", element_source); indent_down(); indent(out) << "}" << endl; } else if (ttype->is_list() || ttype->is_set()) { t_type* elem; if (ttype->is_list()) { t_list* temp = (t_list*)ttype; elem = temp->get_elem_type(); } else { t_set* temp = (t_set*)ttype; elem = temp->get_elem_type(); } out << indent() << "for i, _tgt := range " << tgt << " {" << endl; indent_up(); string element_source = tmp("_src"); out << indent() << element_source << " := " << src << "[i]" << endl; generate_go_equals(out, elem, "_tgt", element_source); indent_down(); indent(out) << "}" << endl; } else { throw "INVALID TYPE IN generate_go_equals_container '" + ttype->get_name(); } } /** * Generates the docstring for a given struct. */ void t_go_generator::generate_go_docstring(ostream& out, t_struct* tstruct) { generate_go_docstring(out, tstruct, tstruct, "Attributes"); } /** * Generates the docstring for a given function. */ void t_go_generator::generate_go_docstring(ostream& out, t_function* tfunction) { generate_go_docstring(out, tfunction, tfunction->get_arglist(), "Parameters"); } /** * Generates the docstring for a struct or function. */ void t_go_generator::generate_go_docstring(ostream& out, t_doc* tdoc, t_struct* tstruct, const char* subheader) { bool has_doc = false; stringstream ss; if (tdoc->has_doc()) { has_doc = true; ss << tdoc->get_doc(); } const vector& fields = tstruct->get_members(); if (fields.size() > 0) { if (has_doc) { ss << endl; } has_doc = true; ss << subheader << ":\n"; vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; ss << " - " << publicize(p->get_name()); if (p->has_doc()) { ss << ": " << p->get_doc(); } else { ss << endl; } } } if (has_doc) { generate_docstring_comment(out, "", "// ", ss.str(), ""); } } /** * Generates the docstring for a generic object. */ void t_go_generator::generate_go_docstring(ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_docstring_comment(out, "", "//", tdoc->get_doc(), ""); } } /** * Declares an argument, which may include initialization as necessary. * * @param tfield The field */ string t_go_generator::declare_argument(t_field* tfield) { std::ostringstream result; result << publicize(tfield->get_name()) << "="; if (tfield->get_value() != nullptr) { result << "thrift_spec[" << tfield->get_key() << "][4]"; } else { result << "nil"; } return result.str(); } /** * Renders a struct field initial value. * * @param tfield The field, which must have `tfield->get_value() != nullptr` */ string t_go_generator::render_field_initial_value(t_field* tfield, const string& name, bool optional_field) { t_type* type = get_true_type(tfield->get_type()); if (optional_field) { // The caller will make a second pass for optional fields, // assigning the result of render_const_value to "*field_name". It // is maddening that Go syntax does not allow for a type-agnostic // way to initialize a pointer to a const value, but so it goes. // The alternative would be to write type specific functions that // convert from const values to pointer types, but given the lack // of overloading it would be messy. return "new(" + type_to_go_type(tfield->get_type()) + ")"; } else { return render_const_value(type, tfield->get_value(), name); } } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_go_generator::function_signature(t_function* tfunction, string prefix) { // TODO(mcslee): Nitpicky, no ',' if argument_list is empty return publicize(prefix + tfunction->get_name()) + "(" + argument_list(tfunction->get_arglist()) + ")"; } /** * Renders an interface function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_go_generator::function_signature_if(t_function* tfunction, string prefix, bool addError) { string signature = publicize(prefix + tfunction->get_name()) + "("; signature += "ctx context.Context"; if (!tfunction->get_arglist()->get_members().empty()) { signature += ", " + argument_list(tfunction->get_arglist()); } signature += ") ("; t_type* ret = tfunction->get_returntype(); t_struct* exceptions = tfunction->get_xceptions(); string errs = argument_list(exceptions); if (!ret->is_void()) { signature += "_r " + type_to_go_type(ret); if (addError || errs.size() == 0) { signature += ", "; } } if (addError) { signature += "_err error"; } signature += ")"; return signature; } /** * Renders a field list */ string t_go_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += variable_name_to_go_name((*f_iter)->get_name()) + " " + type_to_go_type((*f_iter)->get_type()); } return result; } string t_go_generator::type_name(t_type* ttype) { string module( module_name(ttype)); if( ! module.empty()) { return module + "." + ttype->get_name(); } return ttype->get_name(); } string t_go_generator::module_name(t_type* ttype) { t_program* program = ttype->get_program(); if (program != nullptr && program != program_) { if (program->get_namespace("go").empty() || program_->get_namespace("go").empty() || program->get_namespace("go") != program_->get_namespace("go")) { string module(get_real_go_module(program)); return package_identifiers_[module]; } } return ""; } /** * Converts the parse type to a go tyoe */ string t_go_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: /* this is wrong, binary is still a string type internally if (type->is_binary()) { return "thrift.BINARY"; } */ return "thrift.STRING"; case t_base_type::TYPE_BOOL: return "thrift.BOOL"; case t_base_type::TYPE_I8: return "thrift.BYTE"; case t_base_type::TYPE_I16: return "thrift.I16"; case t_base_type::TYPE_I32: return "thrift.I32"; case t_base_type::TYPE_I64: return "thrift.I64"; case t_base_type::TYPE_DOUBLE: return "thrift.DOUBLE"; } } else if (type->is_enum()) { return "thrift.I32"; } else if (type->is_struct() || type->is_xception()) { return "thrift.STRUCT"; } else if (type->is_map()) { return "thrift.MAP"; } else if (type->is_set()) { return "thrift.SET"; } else if (type->is_list()) { return "thrift.LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Converts the parse type to a go map type, will throw an exception if it will * not produce a valid go map type. */ string t_go_generator::type_to_go_key_type(t_type* type) { t_type* resolved_type = type; while (resolved_type->is_typedef()) { resolved_type = ((t_typedef*)resolved_type)->get_type()->get_true_type(); } if (resolved_type->is_map() || resolved_type->is_list() || resolved_type->is_set()) { throw "Cannot produce a valid type for a Go map key: " + type_to_go_type(type) + " - aborting."; } if (resolved_type->is_binary()) return "string"; return type_to_go_type(type); } /** * Converts the parse type to a go type */ string t_go_generator::type_to_go_type(t_type* type) { return type_to_go_type_with_opt(type, false); } /** * Converts the parse type to a go type, taking into account whether the field * associated with the type is T_OPTIONAL. */ string t_go_generator::type_to_go_type_with_opt(t_type* type, bool optional_field) { string maybe_pointer(optional_field ? "*" : ""); if (type->is_typedef() && ((t_typedef*)type)->is_forward_typedef()) { type = ((t_typedef*)type)->get_true_type(); } if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw ""; case t_base_type::TYPE_STRING: if (type->is_binary()) { return maybe_pointer + "[]byte"; } return maybe_pointer + "string"; case t_base_type::TYPE_BOOL: return maybe_pointer + "bool"; case t_base_type::TYPE_I8: return maybe_pointer + "int8"; case t_base_type::TYPE_I16: return maybe_pointer + "int16"; case t_base_type::TYPE_I32: return maybe_pointer + "int32"; case t_base_type::TYPE_I64: return maybe_pointer + "int64"; case t_base_type::TYPE_DOUBLE: return maybe_pointer + "float64"; } } else if (type->is_enum()) { return maybe_pointer + publicize(type_name(type)); } else if (type->is_struct() || type->is_xception()) { return "*" + publicize(type_name(type)); } else if (type->is_map()) { t_map* t = (t_map*)type; string keyType = type_to_go_key_type(t->get_key_type()); string valueType = type_to_go_type(t->get_val_type()); return maybe_pointer + string("map[") + keyType + "]" + valueType; } else if (type->is_set()) { t_set* t = (t_set*)type; string elemType = type_to_go_type(t->get_elem_type()); return maybe_pointer + string("[]") + elemType; } else if (type->is_list()) { t_list* t = (t_list*)type; string elemType = type_to_go_type(t->get_elem_type()); return maybe_pointer + string("[]") + elemType; } else if (type->is_typedef()) { return maybe_pointer + publicize(type_name(type)); } throw "INVALID TYPE IN type_to_go_type: " + type->get_name(); } /** See the comment inside generate_go_struct_definition for what this is. */ string t_go_generator::type_to_spec_args(t_type* ttype) { while (ttype->is_typedef()) { ttype = ((t_typedef*)ttype)->get_type(); } if (ttype->is_base_type() || ttype->is_enum()) { return "nil"; } else if (ttype->is_struct() || ttype->is_xception()) { return "(" + type_name(ttype) + ", " + type_name(ttype) + ".thrift_spec)"; } else if (ttype->is_map()) { return "(" + type_to_enum(((t_map*)ttype)->get_key_type()) + "," + type_to_spec_args(((t_map*)ttype)->get_key_type()) + "," + type_to_enum(((t_map*)ttype)->get_val_type()) + "," + type_to_spec_args(((t_map*)ttype)->get_val_type()) + ")"; } else if (ttype->is_set()) { return "(" + type_to_enum(((t_set*)ttype)->get_elem_type()) + "," + type_to_spec_args(((t_set*)ttype)->get_elem_type()) + ")"; } else if (ttype->is_list()) { return "(" + type_to_enum(((t_list*)ttype)->get_elem_type()) + "," + type_to_spec_args(((t_list*)ttype)->get_elem_type()) + ")"; } throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name(); } // parses a string of struct tags into key/value pairs and writes them to the given map void t_go_generator::parse_go_tags(map* tags, const string in) { string key; string value; size_t mode=0; // 0/1/2 for key/value/whitespace size_t index=0; for (auto it=in.begin(); it #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostringstream; using std::pair; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * Graphviz code generator */ class t_gv_generator : public t_generator { public: t_gv_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; exception_arrows = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("exceptions") == 0) { exception_arrows = true; } else { throw "unknown option gv:" + iter->first; } } out_dir_base_ = "gen-gv"; } /** * Init and end of generator */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_service(t_service* tservice) override; protected: /** * Helpers */ void print_type(t_type* ttype, string struct_field_ref); void print_const_value(t_type* type, t_const_value* tvalue); private: ofstream_with_content_based_conditional_update f_out_; std::list edges; bool exception_arrows; }; /** * Init generator: * - Adds some escaping for the Graphviz domain. * - Create output directory and open file for writting. * - Write the file header. */ void t_gv_generator::init_generator() { escape_['{'] = "\\{"; escape_['}'] = "\\}"; // Make output directory MKDIR(get_out_dir().c_str()); string fname = get_out_dir() + program_->get_name() + ".gv"; f_out_.open(fname.c_str()); f_out_ << "digraph \"" << escape_string(program_name_) << "\" {" << endl; f_out_ << "node [style=filled, shape=record];" << endl; f_out_ << "edge [arrowsize=0.5];" << endl; f_out_ << "rankdir=LR" << endl; } /** * Closes generator: * - Print accumulated nodes connections. * - Print footnote. * - Closes file. */ void t_gv_generator::close_generator() { // Print edges std::list::iterator iter = edges.begin(); for (; iter != edges.end(); iter++) { f_out_ << (*iter) << endl; } // Print graph end } and close file f_out_ << "}" << endl; f_out_.close(); } void t_gv_generator::generate_typedef(t_typedef* ttypedef) { string name = ttypedef->get_name(); f_out_ << "node [fillcolor=azure];" << endl; f_out_ << name << " [label=\""; f_out_ << escape_string(name); f_out_ << " :: "; print_type(ttypedef->get_type(), name); f_out_ << "\"];" << endl; } void t_gv_generator::generate_enum(t_enum* tenum) { string name = tenum->get_name(); f_out_ << "node [fillcolor=white];" << endl; f_out_ << name << " [label=\"enum " << escape_string(name); vector values = tenum->get_constants(); vector::iterator val_iter; for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { f_out_ << '|' << (*val_iter)->get_name(); f_out_ << " = "; f_out_ << (*val_iter)->get_value(); } f_out_ << "\"];" << endl; } void t_gv_generator::generate_const(t_const* tconst) { string name = tconst->get_name(); f_out_ << "node [fillcolor=aliceblue];" << endl; f_out_ << "const_" << name << " [label=\""; f_out_ << escape_string(name); f_out_ << " = "; print_const_value(tconst->get_type(), tconst->get_value()); f_out_ << " :: "; print_type(tconst->get_type(), "const_" + name); f_out_ << "\"];" << endl; } void t_gv_generator::generate_struct(t_struct* tstruct) { string name = tstruct->get_name(); if (tstruct->is_xception()) { f_out_ << "node [fillcolor=lightpink];" << endl; f_out_ << name << " [label=\""; f_out_ << "exception " << escape_string(name); } else if (tstruct->is_union()) { f_out_ << "node [fillcolor=lightcyan];" << endl; f_out_ << name << " [label=\""; f_out_ << "union " << escape_string(name); } else { f_out_ << "node [fillcolor=beige];" << endl; f_out_ << name << " [label=\""; f_out_ << "struct " << escape_string(name); } vector members = tstruct->get_members(); vector::iterator mem_iter = members.begin(); for (; mem_iter != members.end(); mem_iter++) { string field_name = (*mem_iter)->get_name(); // print port (anchor reference) f_out_ << "|'; // field name :: field type f_out_ << (*mem_iter)->get_name(); f_out_ << " :: "; print_type((*mem_iter)->get_type(), name + ":field_" + field_name); } f_out_ << "\"];" << endl; } void t_gv_generator::print_type(t_type* ttype, string struct_field_ref) { if (ttype->is_container()) { if (ttype->is_list()) { f_out_ << "list\\<"; print_type(((t_list*)ttype)->get_elem_type(), struct_field_ref); f_out_ << "\\>"; } else if (ttype->is_set()) { f_out_ << "set\\<"; print_type(((t_set*)ttype)->get_elem_type(), struct_field_ref); f_out_ << "\\>"; } else if (ttype->is_map()) { f_out_ << "map\\<"; print_type(((t_map*)ttype)->get_key_type(), struct_field_ref); f_out_ << ", "; print_type(((t_map*)ttype)->get_val_type(), struct_field_ref); f_out_ << "\\>"; } } else if (ttype->is_base_type()) { f_out_ << (ttype->is_binary() ? "binary" : ttype->get_name()); } else { f_out_ << ttype->get_name(); edges.push_back(struct_field_ref + " -> " + ttype->get_name()); } } /** * Prints out an string representation of the provided constant value */ void t_gv_generator::print_const_value(t_type* type, t_const_value* tvalue) { bool first = true; switch (tvalue->get_type()) { case t_const_value::CV_INTEGER: f_out_ << tvalue->get_integer(); break; case t_const_value::CV_DOUBLE: f_out_ << tvalue->get_double(); break; case t_const_value::CV_STRING: f_out_ << "\\\"" << get_escaped_string(tvalue) << "\\\""; break; case t_const_value::CV_MAP: { f_out_ << "\\{ "; map map_elems = tvalue->get_map(); map::iterator map_iter; for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_map*)type)->get_key_type(), map_iter->first); f_out_ << " = "; print_const_value(((t_map*)type)->get_val_type(), map_iter->second); } f_out_ << " \\}"; } break; case t_const_value::CV_LIST: { f_out_ << "\\{ "; vector list_elems = tvalue->get_list(); ; vector::iterator list_iter; for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { if (!first) { f_out_ << ", "; } first = false; if (type->is_list()) { print_const_value(((t_list*)type)->get_elem_type(), *list_iter); } else { print_const_value(((t_set*)type)->get_elem_type(), *list_iter); } } f_out_ << " \\}"; } break; case t_const_value::CV_IDENTIFIER: f_out_ << escape_string(type->get_name()) << "." << escape_string(tvalue->get_identifier_name()); break; default: f_out_ << "UNKNOWN"; break; } } void t_gv_generator::generate_service(t_service* tservice) { string service_name = get_service_name(tservice); f_out_ << "subgraph cluster_" << service_name << " {" << endl; f_out_ << "node [fillcolor=bisque];" << endl; f_out_ << "style=dashed;" << endl; f_out_ << "label = \"" << escape_string(service_name) << " service\";" << endl; // TODO: service extends vector functions = tservice->get_functions(); vector::iterator fn_iter = functions.begin(); for (; fn_iter != functions.end(); fn_iter++) { string fn_name = (*fn_iter)->get_name(); f_out_ << "function_" << service_name << fn_name; f_out_ << "[label=\"function " << escape_string(fn_name); f_out_ << " :: "; print_type((*fn_iter)->get_returntype(), "function_" + service_name + fn_name + ":return_type"); vector args = (*fn_iter)->get_arglist()->get_members(); vector::iterator arg_iter = args.begin(); for (; arg_iter != args.end(); arg_iter++) { f_out_ << "|get_name() << ">"; f_out_ << (*arg_iter)->get_name(); if ((*arg_iter)->get_value() != nullptr) { f_out_ << " = "; print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value()); } f_out_ << " :: "; print_type((*arg_iter)->get_type(), "function_" + service_name + fn_name + ":param_" + (*arg_iter)->get_name()); } // end of node f_out_ << "\"];" << endl; // Exception edges if (exception_arrows) { vector excepts = (*fn_iter)->get_xceptions()->get_members(); vector::iterator ex_iter = excepts.begin(); for (; ex_iter != excepts.end(); ex_iter++) { edges.push_back("function_" + service_name + fn_name + " -> " + (*ex_iter)->get_type()->get_name() + " [color=red]"); } } } f_out_ << " }" << endl; } THRIFT_REGISTER_GENERATOR( gv, "Graphviz", " exceptions: Whether to draw arrows from functions to exception.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_haxe_generator.cc000066400000000000000000003055011420101504100251700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * Haxe code generator. * */ class t_haxe_generator : public t_oop_generator { public: t_haxe_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; rtti_ = false; buildmacro_ = ""; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("callbacks") == 0) { printf("Hint: The 'callbacks' option is no longer necessary.\n"); } else if( iter->first.compare("rtti") == 0) { rtti_ = true; } else if( iter->first.compare("buildmacro") == 0) { buildmacro_ = (iter->second); } else { throw "unknown option haxe:" + iter->first; } } out_dir_base_ = "gen-haxe"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; void generate_consts(std::vector consts) override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void print_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval = false); std::string render_const_value(ostream& out, std::string name, t_type* type, t_const_value* value); /** * Service-level generation functions */ void generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result = false); void generate_haxe_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool is_result = false); // removed -- equality,compare_to void generate_haxe_struct_reader(std::ostream& out, t_struct* tstruct); void generate_haxe_validator(std::ostream& out, t_struct* tstruct); void generate_haxe_struct_result_writer(std::ostream& out, t_struct* tstruct); void generate_haxe_struct_writer(std::ostream& out, t_struct* tstruct); void generate_haxe_struct_tostring(std::ostream& out, t_struct* tstruct, bool is_override); void generate_haxe_meta_data_map(std::ostream& out, t_struct* tstruct); void generate_field_value_meta_data(std::ostream& out, t_type* type); std::string get_haxe_type_string(t_type* type); void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name); void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name); void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct); void generate_generic_isset_method(std::ostream& out, t_struct* tstruct); void generate_property_getters_setters(std::ostream& out, t_struct* tstruct); void generate_function_helpers(t_function* tfunction); std::string get_cap_name(std::string name); std::string generate_isset_check(t_field* field); std::string generate_isset_check(std::string field); void generate_isset_set(ostream& out, t_field* field); // removed std::string isset_field_id(t_field* field); void generate_service_interface(t_service* tservice, bool combined); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); void generate_service_method_signature(t_function* tfunction, bool is_interface, bool combined); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string iter, std::string map); void generate_haxe_doc(std::ostream& out, t_doc* tdoc); void generate_haxe_doc(std::ostream& out, t_function* tdoc); void generate_rtti_decoration(std::ostream& out); void generate_macro_decoration(std::ostream& out); /** * Helper rendering functions */ std::string haxe_package(); std::string haxe_type_imports(); std::string haxe_thrift_imports(); std::string haxe_thrift_gen_imports(t_struct* tstruct, string& imports); std::string haxe_thrift_gen_imports(t_service* tservice); std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false); std::string base_type_name(t_base_type* tbase, bool in_container = false); std::string declare_field(t_field* tfield, bool init = false); std::string function_signature_combined(t_function* tfunction); std::string function_signature_normal(t_function* tfunction); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string get_enum_class_name(t_type* type) override; string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name); void generate_service_method_signature_combined(t_function* tfunction, bool is_interface); void generate_service_method_signature_normal(t_function* tfunction, bool is_interface); bool type_can_be_null(t_type* ttype) { ttype = get_true_type(ttype); if (ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()) { return true; } if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: // case t_base_type::TYPE_I64: - Int64 is not really nullable, even though it behaved that // way before Haxe 3.2.0 return true; default: return false; } } return false; } std::string constant_name(std::string name); std::string make_package_name(std::string value); private: bool rtti_; string buildmacro_; /** * File streams */ std::string package_name_; ofstream_with_content_based_conditional_update f_service_; std::string package_dir_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_haxe_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); package_name_ = make_package_name( program_->get_namespace("haxe")); string dir = package_name_; string subdir = get_out_dir(); string::size_type loc; while ((loc = dir.find(".")) != string::npos) { subdir = subdir + "/" + dir.substr(0, loc); MKDIR(subdir.c_str()); dir = dir.substr(loc + 1); } if (dir.size() > 0) { subdir = subdir + "/" + dir; MKDIR(subdir.c_str()); } package_dir_ = subdir; } // Haxe package names start with lowercase letters std::string t_haxe_generator::make_package_name(std::string value) { std::string retval(value); if (retval.length() > 0) { retval[0] = tolower(retval[0]); size_t index = retval.find('.'); while (index != std::string::npos) { if (++index < retval.length()) { retval[index] = tolower(retval[index]); } index = retval.find('.', index); } } return retval; } /** * Packages the generated file * * @return String of the package, i.e. "package org.apache.thriftdemo;" */ string t_haxe_generator::haxe_package() { if (!package_name_.empty()) { return string("package ") + package_name_; } return "package"; } /** * Prints standard haxe imports * * @return List of imports for haxe types that are used in here */ string t_haxe_generator::haxe_type_imports() { return string() + "import org.apache.thrift.helper.*;\n" + "import haxe.io.Bytes;\n" + "import haxe.ds.IntMap;\n" + "import haxe.ds.StringMap;\n" + "import haxe.ds.ObjectMap;\n" + "\n" + "#if flash\n" + "import flash.errors.ArgumentError;\n" + "#end\n" + "\n"; } /** * Prints standard haxe imports * * @return List of imports necessary for thrift */ string t_haxe_generator::haxe_thrift_imports() { return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + "import org.apache.thrift.protocol.*;\n" + "\n"; } /** * Prints imports needed for a given type * * @return List of imports necessary for a given t_struct */ string t_haxe_generator::haxe_thrift_gen_imports(t_struct* tstruct, string& imports) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; // For each type check if it is from a different namespace for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_program* program = (*m_iter)->get_type()->get_program(); if (program != nullptr && program != program_) { string package = make_package_name( program->get_namespace("haxe")); if (!package.empty()) { if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) { imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n"); } } } } return imports; } /** * Prints imports needed for a given type * * @return List of imports necessary for a given t_service */ string t_haxe_generator::haxe_thrift_gen_imports(t_service* tservice) { string imports; const vector& functions = tservice->get_functions(); vector::const_iterator f_iter; // For each type check if it is from a different namespace for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_program* program = (*f_iter)->get_returntype()->get_program(); if (program != nullptr && program != program_) { string package = make_package_name( program->get_namespace("haxe")); if (!package.empty()) { if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) { imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name()+ ";\n"); } } } haxe_thrift_gen_imports((*f_iter)->get_arglist(), imports); haxe_thrift_gen_imports((*f_iter)->get_xceptions(), imports); } return imports; } /** * Nothing in haxe */ void t_haxe_generator::close_generator() { } /** * Generates a typedef. This is not done in haxe, since it does * not support arbitrary name replacements, and it'd be a wacky waste * of overhead to make wrapper classes. * * @param ttypedef The type definition */ void t_haxe_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Enums are a class with a set of static constants. * * @param tenum The enumeration */ void t_haxe_generator::generate_enum(t_enum* tenum) { // Make output file string f_enum_name = package_dir_ + "/" + get_cap_name(tenum->get_name()) + ".hx"; ofstream_with_content_based_conditional_update f_enum; f_enum.open(f_enum_name.c_str()); // Comment and package it f_enum << autogen_comment() << haxe_package() << ";" << endl << endl; // Add haxe imports f_enum << string() + "import org.apache.thrift.helper.*;" << endl << endl; generate_rtti_decoration(f_enum); generate_macro_decoration(f_enum); indent(f_enum) << "class " << get_cap_name(tenum->get_name()) << " "; scope_up(f_enum); vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); indent(f_enum) << "public static inline var " << (*c_iter)->get_name() << " : Int = " << value << ";" << endl; } // Create a static Set with all valid values for this enum f_enum << endl; indent(f_enum) << "public static var VALID_VALUES = { new IntSet( ["; indent_up(); bool firstValue = true; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { // populate set f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name(); firstValue = false; } indent_down(); f_enum << "]); };" << endl; indent(f_enum) << "public static var VALUES_TO_NAMES = { ["; indent_up(); firstValue = true; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { f_enum << (firstValue ? "" : ",") << endl; indent(f_enum) << (*c_iter)->get_name() << " => \"" << (*c_iter)->get_name() << "\""; firstValue = false; } f_enum << endl; indent_down(); indent(f_enum) << "]; };" << endl; scope_down(f_enum); // end class f_enum.close(); } /** * Generates a class that holds all the constants. */ void t_haxe_generator::generate_consts(std::vector consts) { if (consts.empty()) { return; } string f_consts_name = package_dir_ + "/" + get_cap_name(program_name_) + "Constants.hx"; ofstream_with_content_based_conditional_update f_consts; f_consts.open(f_consts_name.c_str()); // Print header f_consts << autogen_comment() << haxe_package() << ";" << endl << endl; f_consts << endl; f_consts << haxe_type_imports(); generate_rtti_decoration(f_consts); generate_macro_decoration(f_consts); indent(f_consts) << "class " << get_cap_name(program_name_) << "Constants {" << endl << endl; indent_up(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false); } indent_down(); indent(f_consts) << "}" << endl; f_consts.close(); } void t_haxe_generator::print_const_value(std::ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) { type = get_true_type(type); indent(out); if (!defval) { out << (in_static ? "var " : "public static inline var "); } if (type->is_base_type()) { string v2 = render_const_value(out, name, type, value); out << name; if (!defval) { out << ":" << type_name(type); } out << " = " << v2 << ";" << endl << endl; } else if (type->is_enum()) { out << name; if (!defval) { out << ":" << type_name(type); } out << " = " << value->get_integer() << ";" << endl << endl; } else if (type->is_struct() || type->is_xception()) { const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();" << endl; if (!in_static) { indent(out) << "{" << endl; indent_up(); indent(out) << "new function() : Void {" << endl; indent_up(); } for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string val = render_const_value(out, name, field_type, v_iter->second); indent(out) << name << "."; out << v_iter->first->get_string() << " = " << val << ";" << endl; } if (!in_static) { indent_down(); indent(out) << "}();" << endl; indent_down(); indent(out) << "}" << endl; } out << endl; } else if (type->is_map()) { out << name; if (!defval) { out << ":" << type_name(type); } out << " = new " << type_name(type, false, true) << "();" << endl; if (!in_static) { indent(out) << "{" << endl; indent_up(); indent(out) << "new function() : Void {" << endl; indent_up(); } t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(out, name, ktype, v_iter->first); string val = render_const_value(out, name, vtype, v_iter->second); indent(out) << name << "[" << key << "] = " << val << ";" << endl; } if (!in_static) { indent_down(); indent(out) << "}();" << endl; indent_down(); indent(out) << "}" << endl; } out << endl; } else if (type->is_list() || type->is_set()) { out << name; if (!defval) { out << ":" << type_name(type); } out << " = new " << type_name(type, false, true) << "();" << endl; if (!in_static) { indent(out) << "{" << endl; indent_up(); indent(out) << "new function() : Void {" << endl; indent_up(); } t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(out, name, etype, *v_iter); indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");" << endl; } if (!in_static) { indent_down(); indent(out) << "}();" << endl; indent_down(); indent(out) << "}" << endl; } out << endl; } else { throw "compiler error: no const of type " + type->get_name(); } } string t_haxe_generator::render_const_value(ostream& out, string name, t_type* type, t_const_value* value) { (void)name; type = get_true_type(type); std::ostringstream render; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: render << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: render << "(byte)" << value->get_integer(); break; case t_base_type::TYPE_I16: render << "(short)" << value->get_integer(); break; case t_base_type::TYPE_I32: render << value->get_integer(); break; case t_base_type::TYPE_I64: render << value->get_integer() << "L"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << "(double)" << value->get_integer(); } else { render << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { render << value->get_integer(); } else { string t = tmp("tmp"); print_const_value(out, t, type, value, true); render << t; } return render.str(); } /** * Generates a struct definition for a thrift data type. This is a class * with data members, read(), write(), and an inner Isset class. * * @param tstruct The struct definition */ void t_haxe_generator::generate_struct(t_struct* tstruct) { generate_haxe_struct(tstruct, false); } /** * Exceptions are structs, but they inherit from Exception * * @param tstruct The struct definition */ void t_haxe_generator::generate_xception(t_struct* txception) { generate_haxe_struct(txception, true); } /** * Haxe struct definition. * * @param tstruct The struct definition */ void t_haxe_generator::generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result) { // Make output file string f_struct_name = package_dir_ + "/" + get_cap_name(tstruct->get_name()) + ".hx"; ofstream_with_content_based_conditional_update f_struct; f_struct.open(f_struct_name.c_str()); f_struct << autogen_comment() << haxe_package() << ";" << endl; f_struct << endl; string imports; f_struct << haxe_type_imports() << haxe_thrift_imports() << haxe_thrift_gen_imports(tstruct, imports) << endl; generate_haxe_struct_definition(f_struct, tstruct, is_exception, is_result); f_struct.close(); } /** * haxe struct definition. This has various parameters, as it could be * generated standalone or inside another class as a helper. If it * is a helper than it is a static class. * * @param tstruct The struct definition * @param is_exception Is this an exception? * @param in_class If inside a class, needs to be static class * @param is_result If this is a result it needs a different writer */ void t_haxe_generator::generate_haxe_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool is_result) { generate_haxe_doc(out, tstruct); string clsname = get_cap_name(tstruct->get_name()); generate_rtti_decoration(out); generate_macro_decoration(out); indent(out) << "class " << clsname << " "; if (is_exception) { out << "extends TException "; } out << "implements TBase {" << endl << endl; indent_up(); indent(out) << "static var STRUCT_DESC = { new TStruct(\"" << tstruct->get_name() << "\"); };" << endl; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "static var " << constant_name((*m_iter)->get_name()) << "_FIELD_DESC = { new TField(\"" << (*m_iter)->get_name() << "\", " << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << "); };" << endl; } out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_haxe_doc(out, *m_iter); // indent(out) << "private var _" << (*m_iter)->get_name() + " : " + // type_name((*m_iter)->get_type()) << ";" << endl; indent(out) << "@:isVar" << endl; indent(out) << "public var " << (*m_iter)->get_name() + "(get,set) : " + get_cap_name(type_name((*m_iter)->get_type())) << ";" << endl; } out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "inline static var " << upcase_string((*m_iter)->get_name()) << "_FIELD_ID : Int = " << (*m_iter)->get_key() << ";" << endl; } out << endl; // Inner Isset class if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!type_can_be_null((*m_iter)->get_type())) { indent(out) << "private var __isset_" << (*m_iter)->get_name() << " : Bool = false;" << endl; } } } out << endl; // Static initializer to populate global class to struct metadata map if (false) { // TODO: reactivate when needed generate_haxe_meta_data_map(out, tstruct); indent(out) << "{" << endl; indent_up(); indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);" << endl; indent_down(); indent(out) << "}" << endl; indent(out) << "}" << endl; } // Default constructor indent(out) << "public function new() {" << endl; indent_up(); if (is_exception) { indent(out) << "super();" << endl; } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_value() != nullptr) { indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_value()->get_integer() << ";" << endl; } } indent_down(); indent(out) << "}" << endl << endl; generate_property_getters_setters(out, tstruct); generate_generic_field_getters_setters(out, tstruct); generate_generic_isset_method(out, tstruct); generate_haxe_struct_reader(out, tstruct); if (is_result) { generate_haxe_struct_result_writer(out, tstruct); } else { generate_haxe_struct_writer(out, tstruct); } generate_haxe_struct_tostring(out, tstruct, is_exception); generate_haxe_validator(out, tstruct); scope_down(out); out << endl; } /** * Generates a function to read all the fields of the struct. * * @param tstruct The struct definition */ void t_haxe_generator::generate_haxe_struct_reader(ostream& out, t_struct* tstruct) { out << indent() << "public function read( iprot : TProtocol) : Void {" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; indent(out) << "iprot.IncrementRecursionDepth();" << endl; indent(out) << "try" << endl; scope_up(out); // Declare stack tmp variables and read struct header out << indent() << "var field : TField;" << endl << indent() << "iprot.readStructBegin();" << endl; // Loop over reading in fields indent(out) << "while (true)" << endl; scope_up(out); // Read beginning field marker indent(out) << "field = iprot.readFieldBegin();" << endl; // Check for field STOP marker and break indent(out) << "if (field.type == TType.STOP) { " << endl; indent_up(); indent(out) << "break;" << endl; indent_down(); indent(out) << "}" << endl; // Switch statement on the field we are reading indent(out) << "switch (field.id)" << endl; scope_up(out); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << upcase_string((*f_iter)->get_name()) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); generate_deserialize_field(out, *f_iter, "this."); generate_isset_set(out, *f_iter); indent_down(); out << indent() << "} else { " << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" << endl << indent() << "}" << endl; indent_down(); } // In the default case we skip the field out << indent() << "default:" << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" << endl; scope_down(out); // Read field end marker indent(out) << "iprot.readFieldEnd();" << endl; scope_down(out); out << indent() << "iprot.readStructEnd();" << endl << endl; indent(out) << "iprot.DecrementRecursionDepth();" << endl; scope_down(out); indent(out) << "catch(e:Dynamic)" << endl; scope_up(out); indent(out) << "iprot.DecrementRecursionDepth();" << endl; indent(out) << "throw e;" << endl; scope_down(out); // check for required fields of primitive type // (which can be checked here but not in the general validate method) out << endl << indent() << "// check for required fields of primitive type, which can't be " "checked in the validate method" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { out << indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl << indent() << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl << indent() << "}" << endl; } } // performs various checks (e.g. check that all required fields are set) indent(out) << "validate();" << endl; indent_down(); out << indent() << "}" << endl << endl; } // generates haxe method to perform various checks // (e.g. check that all required fields are set) void t_haxe_generator::generate_haxe_validator(ostream& out, t_struct* tstruct) { indent(out) << "public function validate() : Void {" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; out << indent() << "// check for required fields" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { if (type_can_be_null((*f_iter)->get_type())) { indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl; indent(out) << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl; indent(out) << "}" << endl; } else { indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() << "' because it's a primitive." << endl; } } } // check that fields of type enum have valid values out << indent() << "// check that fields of type enum have valid values" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = (*f_iter); t_type* type = field->get_type(); // if field is an enum, check that its value is valid if (type->is_enum()) { indent(out) << "if (" << generate_isset_check(field) << " && !" << get_cap_name(get_enum_class_name(type)) << ".VALID_VALUES.contains(" << field->get_name() << ")){" << endl; indent_up(); indent(out) << "throw new TProtocolException(TProtocolException.UNKNOWN, \"The field '" << field->get_name() << "' has been assigned the invalid value \" + " << field->get_name() << ");" << endl; indent_down(); indent(out) << "}" << endl; } } indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a function to write all the fields of the struct * * @param tstruct The struct definition */ void t_haxe_generator::generate_haxe_struct_writer(ostream& out, t_struct* tstruct) { out << indent() << "public function write(oprot:TProtocol) : Void {" << endl; indent_up(); string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; // performs various checks (e.g. check that all required fields are set) indent(out) << "validate();" << endl; indent(out) << "oprot.IncrementRecursionDepth();" << endl; indent(out) << "try" << endl; scope_up(out); indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; if (could_be_unset) { indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; indent_up(); } bool null_allowed = type_can_be_null((*f_iter)->get_type()); if (null_allowed) { out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl; indent_up(); } indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this."); // Write field closer indent(out) << "oprot.writeFieldEnd();" << endl; if (null_allowed) { indent_down(); indent(out) << "}" << endl; } if (could_be_unset) { indent_down(); indent(out) << "}" << endl; } } indent(out) << "oprot.writeFieldStop();" << endl; indent(out) << "oprot.writeStructEnd();" << endl; indent(out) << "oprot.DecrementRecursionDepth();" << endl; scope_down(out); indent(out) << "catch(e:Dynamic)" << endl; scope_up(out); indent(out) << "oprot.DecrementRecursionDepth();" << endl; indent(out) << "throw e;" << endl; scope_down(out); indent_down(); out << indent() << "}" << endl << endl; } /** * Generates a function to write all the fields of the struct, * which is a function result. These fields are only written * if they are set in the Isset array, and only one of them * can be set at a time. * * @param tstruct The struct definition */ void t_haxe_generator::generate_haxe_struct_result_writer(ostream& out, t_struct* tstruct) { out << indent() << "public function write(oprot:TProtocol) : Void {" << endl; indent_up(); string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent(out) << "oprot.IncrementRecursionDepth();" << endl; indent(out) << "try" << endl; scope_up(out); indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; out << endl << indent() << "if "; } else { out << " else if "; } out << "(this." << generate_isset_check(*f_iter) << ") {" << endl; indent_up(); indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this."); // Write field closer indent(out) << "oprot.writeFieldEnd();" << endl; indent_down(); indent(out) << "}"; } indent(out) << endl; indent(out) << "oprot.writeFieldStop();" << endl; indent(out) << "oprot.writeStructEnd();" << endl; indent(out) << "oprot.DecrementRecursionDepth();" << endl; scope_down(out); indent(out) << "catch(e:Dynamic)" << endl; scope_up(out); indent(out) << "oprot.DecrementRecursionDepth();" << endl; indent(out) << "throw e;" << endl; scope_down(out); indent_down(); out << indent() << "}" << endl << endl; } void t_haxe_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) { (void)type; (void)cap_name; indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "return this." << field_name << ";" << endl; indent_down(); } void t_haxe_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) { (void)type; (void)cap_name; indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "if (value == null) {" << endl; indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; indent(out) << "} else {" << endl; indent(out) << " this." << field_name << " = value;" << endl; indent(out) << "}" << endl << endl; indent_down(); } void t_haxe_generator::generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct) { std::ostringstream getter_stream; std::ostringstream setter_stream; // build up the bodies of both the getter and setter at once const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; t_type* type = get_true_type(field->get_type()); std::string field_name = field->get_name(); std::string cap_name = get_cap_name(field_name); indent_up(); generate_reflection_setters(setter_stream, type, field_name, cap_name); generate_reflection_getters(getter_stream, type, field_name, cap_name); indent_down(); } // create the setter indent(out) << "public function setFieldValue(fieldID : Int, value : Dynamic) : Void {" << endl; indent_up(); if (fields.size() > 0) { indent(out) << "switch (fieldID) {" << endl; out << setter_stream.str(); indent(out) << "default:" << endl; indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; indent(out) << "}" << endl; } else { indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; } indent_down(); indent(out) << "}" << endl << endl; // create the getter indent(out) << "public function getFieldValue(fieldID : Int) : Dynamic {" << endl; indent_up(); if (fields.size() > 0) { indent(out) << "switch (fieldID) {" << endl; out << getter_stream.str(); indent(out) << "default:" << endl; indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; indent(out) << "}" << endl; } else { indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; } indent_down(); indent(out) << "}" << endl << endl; } // Creates a generic isSet method that takes the field number as argument void t_haxe_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // create the isSet method indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a " "value) and false otherwise" << endl; indent(out) << "public function isSet(fieldID : Int) : Bool {" << endl; indent_up(); if (fields.size() > 0) { indent(out) << "switch (fieldID) {" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; indent(out) << "case " << upcase_string(field->get_name()) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "return " << generate_isset_check(field) << ";" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; indent(out) << "}" << endl; } else { indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; } indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a set of property setters/getters for the given struct. * * @param tstruct The struct definition */ void t_haxe_generator::generate_property_getters_setters(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; t_type* type = get_true_type(field->get_type()); std::string field_name = field->get_name(); std::string cap_name = get_cap_name(field_name); // Simple getter generate_haxe_doc(out, field); indent(out) << "public function get_" << field_name << "() : " << get_cap_name(type_name(type)) << " {" << endl; indent_up(); indent(out) << "return this." << field_name << ";" << endl; indent_down(); indent(out) << "}" << endl << endl; // Simple setter generate_haxe_doc(out, field); indent(out) << "public function set_" << field_name << "(" << field_name << ":" << get_cap_name(type_name(type)) << ") : " << get_cap_name(type_name(type)) << " {" << endl; indent_up(); indent(out) << "this." << field_name << " = " << field_name << ";" << endl; generate_isset_set(out, field); indent(out) << "return this." << field_name << ";" << endl; indent_down(); indent(out) << "}" << endl << endl; // Unsetter indent(out) << "public function unset" << cap_name << "() : Void {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "this." << field_name << " = null;" << endl; } else { indent(out) << "this.__isset_" << field_name << " = false;" << endl; } indent_down(); indent(out) << "}" << endl << endl; // isSet method indent(out) << "// Returns true if field " << field_name << " is set (has been assigned a value) and false otherwise" << endl; indent(out) << "public function is" << get_cap_name("set") << cap_name << "() : Bool {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "return this." << field_name << " != null;" << endl; } else { indent(out) << "return this.__isset_" << field_name << ";" << endl; } indent_down(); indent(out) << "}" << endl << endl; } } /** * Generates a toString() method for the given struct * * @param tstruct The struct definition */ void t_haxe_generator::generate_haxe_struct_tostring(ostream& out, t_struct* tstruct, bool is_override) { out << indent() << "public "; if( is_override) { out << "override "; } out << "function toString() : String {" << endl; indent_up(); out << indent() << "var ret : String = \"" << tstruct->get_name() << "(\";" << endl; out << indent() << "var first : Bool = true;" << endl << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; if (could_be_unset) { indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; indent_up(); } t_field* field = (*f_iter); if (!first) { indent(out) << "if (!first) ret += \", \";" << endl; } indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl; bool can_be_null = type_can_be_null(field->get_type()); if (can_be_null) { indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; indent(out) << " ret += \"null\";" << endl; indent(out) << "} else {" << endl; indent_up(); } if (field->get_type()->is_binary()) { indent(out) << " ret += \"BINARY\";" << endl; } else if (field->get_type()->is_enum()) { indent(out) << "var " << field->get_name() << "_name : String = " << get_cap_name(get_enum_class_name(field->get_type())) << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];" << endl; indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; indent(out) << " ret += " << field->get_name() << "_name;" << endl; indent(out) << " ret += \" (\";" << endl; indent(out) << "}" << endl; indent(out) << "ret += this." << field->get_name() << ";" << endl; indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; indent(out) << " ret += \")\";" << endl; indent(out) << "}" << endl; } else { indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl; } if (can_be_null) { indent_down(); indent(out) << "}" << endl; } indent(out) << "first = false;" << endl; if (could_be_unset) { indent_down(); indent(out) << "}" << endl; } first = false; } out << indent() << "ret += \")\";" << endl << indent() << "return ret;" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a static map with meta data to store information such as fieldID to * fieldName mapping * * @param tstruct The struct definition */ void t_haxe_generator::generate_haxe_meta_data_map(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // Static Map with fieldID -> FieldMetaData mappings indent(out) << "inline static var metaDataMap : IntMap = new IntMap();" << endl; if (fields.size() > 0) { // Populate map scope_up(out); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; std::string field_name = field->get_name(); indent(out) << "metaDataMap[" << upcase_string(field_name) << "_FIELD_ID] = new FieldMetaData(\"" << field_name << "\", "; // Set field requirement type (required, optional, etc.) if (field->get_req() == t_field::T_REQUIRED) { out << "TFieldRequirementType.REQUIRED, "; } else if (field->get_req() == t_field::T_OPTIONAL) { out << "TFieldRequirementType.OPTIONAL, "; } else { out << "TFieldRequirementType.DEFAULT, "; } // Create value meta data generate_field_value_meta_data(out, field->get_type()); out << ");" << endl; } scope_down(out); } } /** * Returns a string with the haxe representation of the given thrift type * (e.g. for the type struct it returns "TType.STRUCT") */ std::string t_haxe_generator::get_haxe_type_string(t_type* type) { if (type->is_list()) { return "TType.LIST"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_typedef()) { return get_haxe_type_string(((t_typedef*)type)->get_type()); } else if (type->is_base_type()) { switch (((t_base_type*)type)->get_base()) { case t_base_type::TYPE_VOID: return "TType.VOID_"; break; case t_base_type::TYPE_STRING: return "TType.STRING"; break; case t_base_type::TYPE_BOOL: return "TType.BOOL"; break; case t_base_type::TYPE_I8: return "TType.BYTE"; break; case t_base_type::TYPE_I16: return "TType.I16"; break; case t_base_type::TYPE_I32: return "TType.I32"; break; case t_base_type::TYPE_I64: return "TType.I64"; break; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; break; default: throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_haxe_generator::get_haxe_type_string!"); break; // This should never happen! } } else { throw std::runtime_error( "Unknown thrift type \"" + type->get_name() + "\" passed to t_haxe_generator::get_haxe_type_string!"); // This should never happen! } } void t_haxe_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) { out << endl; indent_up(); indent_up(); if (type->is_struct()) { indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type); } else if (type->is_container()) { if (type->is_list()) { indent(out) << "new ListMetaData(TType.LIST, "; t_type* elem_type = ((t_list*)type)->get_elem_type(); generate_field_value_meta_data(out, elem_type); } else if (type->is_set()) { indent(out) << "new SetMetaData(TType.SET, "; t_type* elem_type = ((t_list*)type)->get_elem_type(); generate_field_value_meta_data(out, elem_type); } else { // map indent(out) << "new MapMetaData(TType.MAP, "; t_type* key_type = ((t_map*)type)->get_key_type(); t_type* val_type = ((t_map*)type)->get_val_type(); generate_field_value_meta_data(out, key_type); out << ", "; generate_field_value_meta_data(out, val_type); } } else { indent(out) << "new FieldValueMetaData(" << get_haxe_type_string(type); } out << ")"; indent_down(); indent_down(); } /** * Generates a thrift service. In C++, this comprises an entirely separate * header and source file. The header file defines the methods and includes * the data types defined in the main header file, and the implementation * file contains implementations of the basic printer and default interfaces. * * @param tservice The service definition */ void t_haxe_generator::generate_service(t_service* tservice) { // Make service interface file with only "normal" calls string f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "_service.hx"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << haxe_package() << ";" << endl; f_service_ << endl << haxe_type_imports() << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice); if (tservice->get_extends() != nullptr) { t_type* parent = tservice->get_extends(); string parent_namespace = make_package_name( parent->get_program()->get_namespace("haxe")); if (!parent_namespace.empty() && parent_namespace != package_name_) { f_service_ << "import " << type_name(parent) << "_service;" << endl; } } f_service_ << endl; generate_service_interface(tservice,false); f_service_.close(); // Client interface file with dual suppport ("normal" and "callback" style) f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + ".hx"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << haxe_package() << ";" << endl; f_service_ << endl << haxe_type_imports() << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice); if (tservice->get_extends() != nullptr) { t_type* parent = tservice->get_extends(); string parent_namespace = make_package_name( parent->get_program()->get_namespace("haxe")); if (!parent_namespace.empty() && parent_namespace != package_name_) { f_service_ << "import " << type_name(parent) << ";" << endl; } } f_service_ << endl; generate_service_interface(tservice,true); f_service_.close(); // Now make the implementation/client file f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Impl.hx"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports() << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl; if (tservice->get_extends() != nullptr) { t_type* parent = tservice->get_extends(); string parent_namespace = make_package_name( parent->get_program()->get_namespace("haxe")); if (!parent_namespace.empty() && parent_namespace != package_name_) { f_service_ << "import " << type_name(parent) << "Impl;" << endl; } } f_service_ << endl; generate_service_client(tservice); f_service_.close(); // Now make the helper class files generate_service_helpers(tservice); // Now make the processor/server file f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Processor.hx"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports() << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl; if (!package_name_.empty()) { f_service_ << "import " << package_name_ << ".*;" << endl; f_service_ << "import " << package_name_ << "." << get_cap_name(service_name_).c_str() << "Impl;" << endl; f_service_ << endl; } generate_service_server(tservice); f_service_.close(); } /** * Generates the code snippet for the onSuccess callbacks * * @param tfunction The service function to generate code for. */ string t_haxe_generator::generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name) { if (tfunction->is_oneway()) { return ""; } string name = ""; if (!omit_name) { name = "onSuccess"; if (as_type) { name += " : "; } } if (tfunction->get_returntype()->is_void()) { if (as_type) { return name + "Void->Void = null"; } else { return name + "() : Void"; } } if (as_type) { return name + type_name(tfunction->get_returntype()) + "->Void = null"; } else { return name + "( retval : " + type_name(tfunction->get_returntype()) + ")"; } } /** * Generates a service method header * * @param tfunction The service function to generate code for. */ void t_haxe_generator::generate_service_method_signature(t_function* tfunction, bool is_interface, bool combined) { if( combined) { generate_service_method_signature_combined(tfunction, is_interface); } else { generate_service_method_signature_normal(tfunction, is_interface); } } /** * Generates a service method header in "normal" style * * @param tfunction The service function to generate code for. */ void t_haxe_generator::generate_service_method_signature_normal(t_function* tfunction, bool is_interface) { if (is_interface) { indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl; } else { indent(f_service_) << "public " << function_signature_normal(tfunction) << " {" << endl; } } /** * Generates a service method header in "callback" style * * @param tfunction The service function to generate code for. */ void t_haxe_generator::generate_service_method_signature_combined(t_function* tfunction, bool is_interface) { if (!tfunction->is_oneway()) { std::string on_success_impl = generate_service_method_onsuccess(tfunction, false, false); indent(f_service_) << "// function onError(Dynamic) : Void;" << endl; indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl; } if (is_interface) { indent(f_service_) << function_signature_combined(tfunction) << ";" << endl << endl; } else { indent(f_service_) << "public " << function_signature_combined(tfunction) << " {" << endl; } } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_haxe_generator::generate_service_interface(t_service* tservice, bool combined) { string cbk_postfix = combined ? "" : "_service"; string extends_iface = ""; if (tservice->get_extends() != nullptr) { extends_iface = " extends " + tservice->get_extends()->get_name() + cbk_postfix; } vector functions = tservice->get_functions(); vector::iterator f_iter; generate_haxe_doc(f_service_, tservice); generate_rtti_decoration(f_service_); generate_macro_decoration(f_service_); f_service_ << indent() << "interface " << get_cap_name(service_name_) << cbk_postfix << extends_iface << " {" << endl << endl; indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_haxe_doc(f_service_, *f_iter); generate_service_method_signature(*f_iter, true, combined); } indent_down(); f_service_ << indent() << "}" << endl << endl; } /** * Generates structs for all the service args and return types * * @param tservice The service */ void t_haxe_generator::generate_service_helpers(t_service* tservice) { f_service_ << endl << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_haxe_struct(ts, false); generate_function_helpers(*f_iter); } } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_haxe_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = get_cap_name(tservice->get_extends()->get_name()); extends_client = " extends " + extends + "Impl"; } generate_rtti_decoration(f_service_); // build macro is inherited from interface indent(f_service_) << "class " << get_cap_name(service_name_) << "Impl" << extends_client << " implements " << get_cap_name(service_name_) << " {" << endl << endl; indent_up(); indent(f_service_) << "public function new( iprot : TProtocol, oprot : TProtocol = null)" << endl; scope_up(f_service_); if (extends.empty()) { f_service_ << indent() << "iprot_ = iprot;" << endl; f_service_ << indent() << "if (oprot == null) {" << endl; indent_up(); f_service_ << indent() << "oprot_ = iprot;" << endl; indent_down(); f_service_ << indent() << "} else {" << endl; indent_up(); f_service_ << indent() << "oprot_ = oprot;" << endl; indent_down(); f_service_ << indent() << "}" << endl; } else { f_service_ << indent() << "super(iprot, oprot);" << endl; } scope_down(f_service_); f_service_ << endl; if (extends.empty()) { f_service_ << indent() << "private var iprot_ : TProtocol;" << endl << indent() << "private var oprot_ : TProtocol;" << endl << indent() << "private var seqid_ : Int;" << endl << endl; indent(f_service_) << "public function getInputProtocol() : TProtocol" << endl; scope_up(f_service_); indent(f_service_) << "return this.iprot_;" << endl; scope_down(f_service_); f_service_ << endl; indent(f_service_) << "public function getOutputProtocol() : TProtocol" << endl; scope_up(f_service_); indent(f_service_) << "return this.oprot_;" << endl; scope_down(f_service_); f_service_ << endl; } // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); // Open function generate_service_method_signature(*f_iter, false, true); indent_up(); // Get the struct of function call params t_struct* arg_struct = (*f_iter)->get_arglist(); string argsname = get_cap_name((*f_iter)->get_name() + "_args"); vector::const_iterator fld_iter; const vector& fields = arg_struct->get_members(); // Serialize the request string args = tmp("args"); string calltype = (*f_iter)->is_oneway() ? "ONEWAY" : "CALL"; f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType." << calltype << ", seqid_));" << endl << indent() << "var " << args << " : " << argsname << " = new " << argsname << "();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << indent() << args << "." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl; } f_service_ << indent() << args << ".write(oprot_);" << endl << indent() << "oprot_.writeMessageEnd();" << endl; string retval = tmp("retval"); if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { f_service_ << indent() << "var " << retval << " : " << type_name((*f_iter)->get_returntype()) << ";" << endl; } if ((*f_iter)->is_oneway()) { f_service_ << indent() << "oprot_.getTransport().flush();" << endl; } else { indent(f_service_) << "oprot_.getTransport().flush(function(error:Dynamic) : Void {" << endl; indent_up(); indent(f_service_) << "try {" << endl; indent_up(); string appex = tmp("appex"); indent(f_service_) << "var " << appex << " : TApplicationException;" << endl; string resultname = get_cap_name((*f_iter)->get_name() + "_result"); indent(f_service_) << "if (error != null) {" << endl; indent_up(); indent(f_service_) << "if (onError == null)" << endl; indent_up(); indent(f_service_) << "throw error;" << endl; indent_down(); indent(f_service_) << "onError(error);" << endl; indent(f_service_) << "return;" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; string msg = tmp("msg"); indent(f_service_) << "var " << msg << " : TMessage = iprot_.readMessageBegin();" << endl; indent(f_service_) << "if (" << msg << ".type == TMessageType.EXCEPTION) {" << endl; indent_up(); indent(f_service_) << appex << " = TApplicationException.read(iprot_);" << endl; indent(f_service_) << "iprot_.readMessageEnd();" << endl; indent(f_service_) << "if (onError == null)" << endl; indent_up(); indent(f_service_) << "throw " << appex << ";" << endl; indent_down(); indent(f_service_) << "onError(" << appex << ");" << endl; indent(f_service_) << "return;" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; string result = tmp("result"); indent(f_service_) << "var " << result << " : " << resultname << " = new " << resultname << "();" << endl; indent(f_service_) << "" << result << ".read(iprot_);" << endl; indent(f_service_) << "iprot_.readMessageEnd();" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "if (" << result << "." << generate_isset_check("success") << ") {" << endl; indent_up(); indent(f_service_) << "if (onSuccess != null)" << endl; indent_up(); indent(f_service_) << "onSuccess(" << result << ".success);" << endl; indent_down(); indent(f_service_) << retval << " = " << result << ".success;" << endl; indent(f_service_) << "return;" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { indent(f_service_) << "if (" << result << "." << (*x_iter)->get_name() << " != null) {" << endl; indent_up(); indent(f_service_) << "if (onError == null)" << endl; indent_up(); indent(f_service_) << "throw " << result << "." << (*x_iter)->get_name() << ";" << endl; indent_down(); indent(f_service_) << "onError(" << result << "." << (*x_iter)->get_name() << ");" << endl; indent(f_service_) << "return;" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; } // If you get here it's an exception, unless a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "if (onSuccess != null)" << endl; indent_up(); indent(f_service_) << "onSuccess();" << endl; indent_down(); indent(f_service_) << "return;" << endl; } else { indent(f_service_) << appex << " = new TApplicationException(" << "TApplicationException.MISSING_RESULT," << "\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; indent(f_service_) << "if (onError == null)" << endl; indent_up(); indent(f_service_) << "throw " << appex << ";" << endl; indent_down(); indent(f_service_) << "onError(" << appex << ");" << endl; indent(f_service_) << "return;" << endl; } indent_down(); indent(f_service_) << endl; indent(f_service_) << "} catch( e : TException) {" << endl; indent_up(); indent(f_service_) << "if (onError == null)" << endl; indent_up(); indent(f_service_) << "throw e;" << endl; indent_down(); indent(f_service_) << "onError(e);" << endl; indent(f_service_) << "return;" << endl; indent_down(); indent(f_service_) << "}" << endl; indent_down(); indent(f_service_) << "});" << endl << endl; } if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { f_service_ << indent() << "return " << retval << ";" << endl; } // Close function scope_down(f_service_); f_service_ << endl; } indent_down(); indent(f_service_) << "}" << endl; } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_haxe_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; // Extends stuff string extends = ""; string extends_processor = ""; if (tservice->get_extends() != nullptr) { extends = get_cap_name(type_name(tservice->get_extends())); extends_processor = " extends " + extends + "Processor"; } // Generate the header portion generate_rtti_decoration(f_service_); generate_macro_decoration(f_service_); indent(f_service_) << "class " << get_cap_name(service_name_) << "Processor" << extends_processor << " implements TProcessor {" << endl << endl; indent_up(); f_service_ << indent() << "private var " << get_cap_name(service_name_) << "_iface_ : " << get_cap_name(service_name_) << "_service;" << endl; if (extends.empty()) { f_service_ << indent() << "private var PROCESS_MAP = new StringMap< Int->TProtocol->TProtocol->Void >();" << endl; } f_service_ << endl; indent(f_service_) << "public function new( iface : " << get_cap_name(service_name_) << "_service)" << endl; scope_up(f_service_); if (!extends.empty()) { f_service_ << indent() << "super(iface);" << endl; } f_service_ << indent() << get_cap_name(service_name_) << "_iface_ = iface;" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << indent() << "PROCESS_MAP.set(\"" << (*f_iter)->get_name() << "\", " << (*f_iter)->get_name() << "());" << endl; } scope_down(f_service_); f_service_ << endl; // Generate the server implementation string override = ""; if (tservice->get_extends() != nullptr) { override = "override "; } indent(f_service_) << override << "public function process( iprot : TProtocol, oprot : TProtocol) : Bool" << endl; scope_up(f_service_); f_service_ << indent() << "var msg : TMessage = iprot.readMessageBegin();" << endl; // TODO(mcslee): validate message, was the seqid etc. legit? f_service_ << indent() << "var fn = PROCESS_MAP.get(msg.name);" << endl << indent() << "if (fn == null) {" << endl << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl << indent() << " iprot.readMessageEnd();" << endl << indent() << " var appex = new TApplicationException(TApplicationException.UNKNOWN_METHOD, " << "\"Invalid method name: '\"+msg.name+\"'\");" << endl << indent() << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl << indent() << " appex.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" << endl << indent() << " oprot.getTransport().flush();" << endl << indent() << " return true;" << endl << indent() << "}" << endl << indent() << "fn( msg.seqid, iprot, oprot);" << endl ; f_service_ << indent() << "return true;" << endl; scope_down(f_service_); f_service_ << endl; // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } indent_down(); indent(f_service_) << "}" << endl << endl; } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_haxe_generator::generate_function_helpers(t_function* tfunction) { if (tfunction->is_oneway()) { return; } string resultname = get_cap_name(tfunction->get_name() + "_result"); t_struct result(program_, resultname); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_haxe_struct(&result, false, true); } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_haxe_generator::generate_process_function(t_service* tservice, t_function* tfunction) { (void)tservice; // Open class indent(f_service_) << "private function " << tfunction->get_name() << "() : Int->TProtocol->TProtocol->Void {" << endl; indent_up(); // Open function indent(f_service_) << "return function( seqid : Int, iprot : TProtocol, oprot : TProtocol) : Void" << endl; scope_up(f_service_); string argsname = get_cap_name(tfunction->get_name() + "_args"); string resultname = get_cap_name(tfunction->get_name() + "_result"); f_service_ << indent() << "var args : " << argsname << " = new " << argsname << "();" << endl << indent() << "args.read(iprot);" << endl << indent() << "iprot.readMessageEnd();" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Declare result for non oneway function if (!tfunction->is_oneway()) { f_service_ << indent() << "var result : " << resultname << " = new " << resultname << "();" << endl; } // Try block for any function to catch (defined or undefined) exceptions f_service_ << indent() << "try {" << endl; indent_up(); // normal function():result style // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent(); if (!(tfunction->is_oneway() || tfunction->get_returntype()->is_void())) { f_service_ << "result.success = "; } f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ");" << endl; indent_down(); f_service_ << indent() << "}"; if (!tfunction->is_oneway()) { // catch exceptions defined in the IDL for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << " catch (" << (*x_iter)->get_name() << ":" << get_cap_name(type_name((*x_iter)->get_type(), false, false)) << ") {" << endl; if (!tfunction->is_oneway()) { indent_up(); f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl; indent_down(); f_service_ << indent() << "}"; } else { f_service_ << "}"; } } } // always catch all exceptions to prevent from service denial string appex = tmp("appex"); f_service_ << " catch (th : Dynamic) {" << endl; indent_up(); indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl; if (!tfunction->is_oneway()) { indent(f_service_) << "var appex = new TApplicationException(TApplicationException.INTERNAL_ERROR, " "\"Internal error processing " << tfunction->get_name() << "\");" << endl; indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl; indent(f_service_) << "appex.write(oprot);" << endl; indent(f_service_) << "oprot.writeMessageEnd();" << endl; indent(f_service_) << "oprot.getTransport().flush();" << endl; } indent(f_service_) << "return;" << endl; indent_down(); f_service_ << indent() << "}" << endl; // Shortcut out here for oneway functions if (tfunction->is_oneway()) { f_service_ << indent() << "return;" << endl; scope_down(f_service_); // Close class indent_down(); f_service_ << indent() << "}" << endl << endl; return; } f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() << "oprot.getTransport().flush();" << endl; // Close function scope_down(f_service_); f_service_ << endl; // Close class indent_down(); f_service_ << indent() << "}" << endl << endl; } /** * Deserializes a field of any type. * * @param tfield The field * @param prefix The variable name or container for this field */ void t_haxe_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + tfield->get_name(); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << name << " = iprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "readBinary();"; } else { out << "readString();"; } break; case t_base_type::TYPE_BOOL: out << "readBool();"; break; case t_base_type::TYPE_I8: out << "readByte();"; break; case t_base_type::TYPE_I16: out << "readI16();"; break; case t_base_type::TYPE_I32: out << "readI32();"; break; case t_base_type::TYPE_I64: out << "readI64();"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble();"; break; default: throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "readI32();"; } out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str()); } } /** * Generates an unserializer for a struct, invokes read() */ void t_haxe_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { out << indent() << prefix << " = new " << get_cap_name(type_name(tstruct)) << "();" << endl << indent() << prefix << ".read(iprot);" << endl; } /** * Deserializes a container by reading its size and then iterating */ void t_haxe_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); string obj; if (ttype->is_map()) { obj = tmp("_map"); } else if (ttype->is_set()) { obj = tmp("_set"); } else if (ttype->is_list()) { obj = tmp("_list"); } // Declare variables, read header if (ttype->is_map()) { indent(out) << "var " << obj << " = iprot.readMapBegin();" << endl; } else if (ttype->is_set()) { indent(out) << "var " << obj << " = iprot.readSetBegin();" << endl; } else if (ttype->is_list()) { indent(out) << "var " << obj << " = iprot.readListBegin();" << endl; } indent(out) << prefix << " = new " << type_name(ttype, false, true) // size the collection correctly << "(" << ");" << endl; // For loop iterates over elements string i = tmp("_i"); indent(out) << "for( " << i << " in 0 ... " << obj << ".size)" << endl; scope_up(out); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } scope_down(out); // Read container end if (ttype->is_map()) { indent(out) << "iprot.readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "iprot.readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "iprot.readListEnd();" << endl; } scope_down(out); } /** * Generates code to deserialize a map */ void t_haxe_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); indent(out) << declare_field(&fkey) << endl; indent(out) << declare_field(&fval) << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); indent(out) << prefix << ".set( " << key << ", " << val << ");" << endl; } /** * Deserializes a set element */ void t_haxe_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".add(" << elem << ");" << endl; } /** * Deserializes a list element */ void t_haxe_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".add(" << elem << ");" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_haxe_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + tfield->get_name()); } else if (type->is_base_type() || type->is_enum()) { string name = prefix + tfield->get_name(); indent(out) << "oprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "writeBinary(" << name << ");"; } else { out << "writeString(" << name << ");"; } break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ");"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ");"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ");"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ");"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ");"; break; default: throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32(" << name << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_haxe_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; out << indent() << prefix << ".write(oprot);" << endl; } /** * Serializes a container by writing its size then the elements. * * @param ttype The type of container * @param prefix String prefix for fields */ void t_haxe_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); if (ttype->is_map()) { string iter = tmp("_key"); string counter = tmp("_sizeCounter"); indent(out) << "var " << counter << " : Int = 0;" << endl; indent(out) << "for( " << iter << " in " << prefix << ") {" << endl; indent(out) << " " << counter << +"++;" << endl; indent(out) << "}" << endl; indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << counter << "));" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix << ".size));" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListBegin(new TList(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));" << endl; } string iter = tmp("elem"); if (ttype->is_map()) { indent(out) << "for( " << iter << " in " << prefix << ".keys())" << endl; } else if (ttype->is_set()) { indent(out) << "for( " << iter << " in " << prefix << ".toArray())" << endl; } else if (ttype->is_list()) { indent(out) << "for( " << iter << " in " << prefix << ")" << endl; } scope_up(out); if (ttype->is_map()) { generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); } else if (ttype->is_set()) { generate_serialize_set_element(out, (t_set*)ttype, iter); } else if (ttype->is_list()) { generate_serialize_list_element(out, (t_list*)ttype, iter); } scope_down(out); if (ttype->is_map()) { indent(out) << "oprot.writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListEnd();" << endl; } scope_down(out); } /** * Serializes the members of a map. */ void t_haxe_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map) { t_field kfield(tmap->get_key_type(), iter); generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")"); generate_serialize_field(out, &vfield, ""); } /** * Serializes the members of a set. */ void t_haxe_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Serializes the members of a list. */ void t_haxe_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Returns a haxe type name * * @param ttype The type * @param container Is the type going inside a container? * @return haxe type name, i.e. HashMap */ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_init) { (void)in_init; // typedefs are just resolved to their real type ttype = get_true_type(ttype); string prefix; if (ttype->is_base_type()) { return base_type_name((t_base_type*)ttype, in_container); } if (ttype->is_enum()) { return "Int"; } if (ttype->is_map()) { t_type* tkey = get_true_type(((t_map*)ttype)->get_key_type()); t_type* tval = get_true_type(((t_map*)ttype)->get_val_type()); if (tkey->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: if (!(tkey->is_binary())) { return "StringMap< " + type_name(tval) + ">"; } break; // default to ObjectMap<> case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: return "IntMap< " + type_name(tval) + ">"; case t_base_type::TYPE_I64: return "Int64Map< " + type_name(tval) + ">"; default: break; // default to ObjectMap<> } } if (tkey->is_enum()) { return "IntMap< " + type_name(tval) + ">"; } return "ObjectMap< " + type_name(tkey) + ", " + type_name(tval) + ">"; } if (ttype->is_set()) { t_type* tkey = get_true_type(((t_set*)ttype)->get_elem_type()); if (tkey->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: if (!(tkey->is_binary())) { return "StringSet"; } break; // default to ObjectSet case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: return "IntSet"; case t_base_type::TYPE_I64: return "Int64Set"; default: break; // default to ObjectSet } } if (tkey->is_enum()) { return "IntSet"; } return "ObjectSet< " + type_name(tkey) + ">"; } if (ttype->is_list()) { t_type* telm = ((t_list*)ttype)->get_elem_type(); return "List< " + type_name(telm) + ">"; } // Check for namespacing t_program* program = ttype->get_program(); if (program != nullptr && program != program_) { string package = make_package_name( program->get_namespace("haxe")); if (!package.empty()) { return package + "." + ttype->get_name(); } } return ttype->get_name(); } /** * Returns the haxe type that corresponds to the thrift type. * * @param tbase The base type * @param container Is it going in a haxe container? */ string t_haxe_generator::base_type_name(t_base_type* type, bool in_container) { (void)in_container; t_base_type::t_base tbase = type->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "Void"; case t_base_type::TYPE_STRING: if (type->is_binary()) { return "haxe.io.Bytes"; } else { return "String"; } case t_base_type::TYPE_BOOL: return "Bool"; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: return "haxe.Int32"; case t_base_type::TYPE_I64: return "haxe.Int64"; case t_base_type::TYPE_DOUBLE: return "Float"; default: throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); } } /** * Declares a field, which may include initialization as necessary. * * @param ttype The type */ string t_haxe_generator::declare_field(t_field* tfield, bool init) { // TODO(mcslee): do we ever need to initialize the field? string result = "var " + tfield->get_name() + " : " + type_name(tfield->get_type()); if (init) { t_type* ttype = get_true_type(tfield->get_type()); if (ttype->is_base_type() && tfield->get_value() != nullptr) { std::ofstream dummy; result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); } else if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: result += " = null"; break; case t_base_type::TYPE_BOOL: result += " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = (double)0"; break; } } else if (ttype->is_enum()) { result += " = 0"; } else if (ttype->is_container()) { result += " = new " + type_name(ttype, false, true) + "()"; } else { result += " = new " + type_name(ttype, false, true) + "()"; } } return result + ";"; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_haxe_generator::function_signature_combined(t_function* tfunction) { std::string on_error_success = "onError : Dynamic->Void = null, " + generate_service_method_onsuccess(tfunction, true, false); std::string arguments = argument_list(tfunction->get_arglist()); if (!tfunction->is_oneway()) { if (arguments != "") { arguments += ", "; } arguments += on_error_success; //"onError : Function, onSuccess : Function"; } std::string resulttype; if (tfunction->is_oneway() || tfunction->get_returntype()->is_void()) { resulttype = "Void"; } else { resulttype = type_name(tfunction->get_returntype()); } std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : "+resulttype; return result; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_haxe_generator::function_signature_normal(t_function* tfunction) { std::string arguments = argument_list(tfunction->get_arglist()); std::string resulttype; if (tfunction->is_oneway() || tfunction->get_returntype()->is_void()) { resulttype = "Void"; } else { resulttype = type_name(tfunction->get_returntype()); } std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : " + resulttype; return result; } /** * Renders a comma separated field list, with type names */ string t_haxe_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += (*f_iter)->get_name() + " : " + type_name((*f_iter)->get_type()); } return result; } /** * Converts the parse type to a C++ enum string for the given type. */ string t_haxe_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.STRING"; case t_base_type::TYPE_BOOL: return "TType.BOOL"; case t_base_type::TYPE_I8: return "TType.BYTE"; case t_base_type::TYPE_I16: return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; } } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_list()) { return "TType.LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Haxe class names must start with uppercase letter, but Haxe namespaces must not. */ std::string t_haxe_generator::get_cap_name(std::string name) { if (name.length() == 0) { return name; } // test.for.Generic< data.Type, or.the.Like> and handle it recursively size_t generic_first = name.find('<'); size_t generic_last = name.rfind('>'); if ((generic_first != std::string::npos) && (generic_last != std::string::npos)) { string outer_type = name.substr(0, generic_first); string inner_types = name.substr(generic_first + 1, generic_last - generic_first - 1); string new_inner = ""; size_t comma_start = 0; while (comma_start < inner_types.length()) { size_t comma_pos = comma_start; int nested = 0; while (comma_pos < inner_types.length()) { bool found = false; switch (inner_types[comma_pos]) { case '<': ++nested; break; case '>': --nested; break; case ',': found = (nested == 0); break; } if (found) { break; } ++comma_pos; } if (new_inner.length() > 0) { new_inner += ","; } string inner = inner_types.substr(comma_start, comma_pos - comma_start); new_inner += get_cap_name(inner); comma_start = ++comma_pos; } return get_cap_name(outer_type) + "<" + new_inner + ">"; } // package name size_t index = name.find_first_not_of(" \n\r\t"); if (index < name.length()) { name[index] = tolower(name[index]); index = name.find('.'); while (index != std::string::npos) { if (++index < name.length()) { name[index] = tolower(name[index]); } index = name.find('.', index); } } // class name index = name.rfind('.'); if (index != std::string::npos) { ++index; } else { index = name.find_first_not_of(" \n\r\t"); } if (index < name.length()) { name[index] = toupper(name[index]); } return name; } string t_haxe_generator::constant_name(string name) { string constant_name; bool is_first = true; bool was_previous_char_upper = false; for (char character : name) { bool is_upper = isupper(character); if (is_upper && !is_first && !was_previous_char_upper) { constant_name += '_'; } constant_name += toupper(character); is_first = false; was_previous_char_upper = is_upper; } return constant_name; } /** * Enables RTTI for a class or interface */ void t_haxe_generator::generate_rtti_decoration(ostream& out) { if (rtti_) { out << "@:rtti" << endl; } } /** * Adds build macros to a class or interface */ void t_haxe_generator::generate_macro_decoration(ostream& out) { if (!buildmacro_.empty()) { out << "#if ! macro" << endl; out << "@:build( " << buildmacro_ << ")" << endl; // current class/interface out << "@:autoBuild( " << buildmacro_ << ")" << endl; // inherited classes/interfaces out << "#end" << endl; } } /** * Emits a haxeDoc comment if the provided object has a doc in Thrift */ void t_haxe_generator::generate_haxe_doc(ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_docstring_comment(out, "/**\n", " * ", tdoc->get_doc(), " */\n"); } } /** * Emits a haxeDoc comment if the provided function object has a doc in Thrift */ void t_haxe_generator::generate_haxe_doc(ostream& out, t_function* tfunction) { if (tfunction->has_doc()) { stringstream ss; ss << tfunction->get_doc(); const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; ss << "\n@param " << p->get_name(); if (p->has_doc()) { ss << " " << p->get_doc(); } } generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); } } std::string t_haxe_generator::generate_isset_check(t_field* field) { return generate_isset_check(field->get_name()); } std::string t_haxe_generator::generate_isset_check(std::string field_name) { return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; } void t_haxe_generator::generate_isset_set(ostream& out, t_field* field) { if (!type_can_be_null(field->get_type())) { indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl; } } std::string t_haxe_generator::get_enum_class_name(t_type* type) { string package = ""; t_program* program = type->get_program(); if (program != nullptr /*&& program != program_*/) { package = make_package_name( program->get_namespace("haxe")) + "."; } return package + type->get_name(); } THRIFT_REGISTER_GENERATOR( haxe, "Haxe", " rtti Enable @:rtti for generated classes and interfaces\n" " buildmacro=my.macros.Class.method(args)\n" " Add @:build macro calls to generated classes and interfaces\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_html_generator.cc000066400000000000000000001055471420101504100252170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_generator.h" #include "thrift/generate/t_html_generator.h" using std::map; using std::ofstream; using std::ostringstream; using std::pair; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes enum input_type { INPUT_UNKNOWN, INPUT_UTF8, INPUT_PLAIN }; /** * HTML code generator * * mostly copy/pasting/tweaking from mcslee's work. */ class t_html_generator : public t_generator { public: t_html_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; standalone_ = false; unsafe_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("standalone") == 0) { standalone_ = true; } else if( iter->first.compare("noescape") == 0) { unsafe_ = true; } else { throw "unknown option html:" + iter->first; } } out_dir_base_ = "gen-html"; input_type_ = INPUT_UNKNOWN; escape_.clear(); escape_['&'] = "&"; escape_['<'] = "<"; escape_['>'] = ">"; escape_['"'] = """; escape_['\''] = "'"; init_allowed__markup(); } void generate_program() override; void generate_program_toc(); void generate_program_toc_row(t_program* tprog); void generate_program_toc_rows(t_program* tprog, std::vector& finished); void generate_index(); std::string escape_html(std::string const& str); std::string escape_html_tags(std::string const& str); void generate_css(); void generate_css_content(std::ostream& f_target); void generate_style_tag(); std::string make_file_link(std::string name); bool is_utf8_sequence(std::string const& str, size_t firstpos); void detect_input_encoding(std::string const& str, size_t firstpos); void init_allowed__markup(); /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_service(t_service* tservice) override; void generate_xception(t_struct* txception) override; void print_doc(t_doc* tdoc); int print_type(t_type* ttype); void print_const_value(t_type* type, t_const_value* tvalue); void print_fn_args_doc(t_function* tfunction); private: ofstream_with_content_based_conditional_update f_out_; std::string current_file_; input_type input_type_; std::map allowed_markup; bool standalone_; bool unsafe_; }; /** * Emits the Table of Contents links at the top of the module's page */ void t_html_generator::generate_program_toc() { f_out_ << "
Language Since Build Systems Lang/Lib Levels (Tested) Low-Level Transports Transport Wrappers Protocols Servers Open Issues
autoconfcmake MinMax Domain File Memory Pipe Socket TLS  FramedHeader http  zlib  BinaryCompact JSON Multiplex ForkingNonblockingSimpleThreadedThreadPool
C (glib) 0.6.0 YesYes 2.48.22.56.4 YesYesYesYesYes Yes YesYesYes Yes C (glib)
C++ 0.2.0 YesYes C++11 YesYesYesYesYesYes YesYesYesYes YesYesYesYes YesYesYesYes C++
Common LISP 0.12.0 Yes SBCL 1.4.xSBCL 1.5.3 YesYes Yes YesYesYes Yes Common LISP
Dlang 0.9.0 Yes 2.087.02.087.0 YesYesYesYesYes YesYesYes YesYesYes YesYesYesYes D
Dart 0.10.0 Yes 2.0.02.4.0 Yes YesYes YesYesYesYes Dart
Delphi 0.8.0 2010Sydney 10.4.1 Yes YesYes YesYesYesYes Yes Delphi
.NET Standard 0.13.0 Yes .NET 4.5+, .NET Standard 2.x, .NET 5.0 YesYesYesYes YesYes YesYesYesYes Yes .NET Standard
Erlang 0.3.0 Yes 18.322.0 YesYesYesYes YesYes YesYesYesYes Yes Erlang
Go 0.7.0 Yes 1.16.131.17.6 YesYesYes YesYesYesYes YesYesYesYes Yes Go
Haxe 0.9.3 Yes 4.1.54.2.1 YesYes YesYes YesYesYesYes Yes Haxe
Java (SE) 0.2.0 YesYes 1.8.0_15111.0.3 YesYesYesYes YesYesYes YesYesYesYes YesYesYesYes Java SE
Java (ME) 0.5.0 unknown YesYesYes Yes YesYes Java ME
Javascript 0.3.0 Yes ES5ES6 YesYes Yes YesYes Javascript
Lua 0.9.2 Yes 5.1.55.2.4 YesYes YesYes YesYesYes Yes Lua
node.js 0.6.0 Yes 10.x10.x YesYesYes YesYesYes YesYesYesYes Yes node.js
node.ts 0.12.0 Yes 3.1.6 YesYes Yes Yes node.ts
OCaml 0.2.0 4.04.0 Yes Yes Yes YesYes OCaml
Perl 0.2.0 Yes 5.22.15.26.1 YesYesYesYes YesYes YesYesYes YesYes Perl
PHP 0.2.0 Yes 7.0.227.2.19 YesYesYes YesYes YesYesYesYes YesYes PHP
Python 0.2.0 YesYes 2.7.12, 3.5.22.7.15, 3.6.8 YesYesYes YesYesYes YesYesYesYes YesYesYes Python
Ruby 0.2.0 Yes 2.3.1p1122.5.1p57 YesYesYesYes YesYes YesYesYesYes YesYesYesYes Ruby
Rust 0.11.0 Yes 1.40.01.xx.x YesYes Yes YesYesYes Yes Rust
Smalltalk 0.2.0 unknown Yes Yes Smalltalk
Swift 0.12.0 Yes 4.2.1 YesYesYesYes YesYes YesYesYes Yes Swift
Language Since autoconfcmake MinMax Domain File Memory Pipe Socket TLS  FramedHeader http  zlib  BinaryCompact JSON Multiplex ForkingNonblockingSimpleThreadedThreadPool Open Issues
Build Systems Lang/Lib Levels (Tested) Low-Level Transports Transport Wrappers Protocols Servers
" << "" << endl; generate_program_toc_row(program_); f_out_ << "
ModuleServicesData typesConstants
" << endl; } /** * Recurses through from the provided program and generates a ToC row * for each discovered program exactly once by maintaining the list of * completed rows in 'finished' */ void t_html_generator::generate_program_toc_rows(t_program* tprog, std::vector& finished) { for (auto & iter : finished) { if (tprog->get_path() == iter->get_path()) { return; } } finished.push_back(tprog); generate_program_toc_row(tprog); vector includes = tprog->get_includes(); for (auto & include : includes) { generate_program_toc_rows(include, finished); } } /** * Emits the Table of Contents links at the top of the module's page */ void t_html_generator::generate_program_toc_row(t_program* tprog) { string fname = tprog->get_name() + ".html"; f_out_ << "" << endl << "" << tprog->get_name() << ""; if (!tprog->get_services().empty()) { vector services = tprog->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { string name = get_service_name(*sv_iter); f_out_ << "" << name << "
" << endl; f_out_ << "
    " << endl; map fn_html; vector functions = (*sv_iter)->get_functions(); vector::iterator fn_iter; for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { string fn_name = (*fn_iter)->get_name(); string html = "
  • " + fn_name + "
  • "; fn_html.insert(pair(fn_name, html)); } for (auto & html_iter : fn_html) { f_out_ << html_iter.second << endl; } f_out_ << "
" << endl; } } f_out_ << "" << endl << ""; map data_types; if (!tprog->get_enums().empty()) { vector enums = tprog->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { string name = (*en_iter)->get_name(); // f_out_ << "" << name // << "
" << endl; string html = "" + name + ""; data_types.insert(pair(name, html)); } } if (!tprog->get_typedefs().empty()) { vector typedefs = tprog->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { string name = (*td_iter)->get_symbolic(); // f_out_ << "" << name // << "
" << endl; string html = "" + name + ""; data_types.insert(pair(name, html)); } } if (!tprog->get_objects().empty()) { vector objects = tprog->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { string name = (*o_iter)->get_name(); // f_out_ << "" << name //<< "
" << endl; string html = "" + name + ""; data_types.insert(pair(name, html)); } } for (auto & data_type : data_types) { f_out_ << data_type.second << "
" << endl; } f_out_ << "" << endl << ""; if (!tprog->get_consts().empty()) { map const_html; vector consts = tprog->get_consts(); vector::iterator con_iter; for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) { string name = (*con_iter)->get_name(); string html = "" + name + ""; const_html.insert(pair(name, html)); } for (auto & con_iter : const_html) { f_out_ << con_iter.second << "
" << endl; } } f_out_ << "" << endl << ""; } /** * Prepares for file generation by opening up the necessary file output * stream. */ void t_html_generator::generate_program() { // Make output directory MKDIR(get_out_dir().c_str()); current_file_ = program_->get_name() + ".html"; string fname = get_out_dir() + current_file_; f_out_.open(fname.c_str()); f_out_ << "" << endl; f_out_ << "" << endl; f_out_ << "" << endl; f_out_ << "" << endl; generate_style_tag(); f_out_ << "Thrift module: " << program_->get_name() << "" << endl << "
" << endl << "

Thrift module: " << program_->get_name() << "

" << endl; print_doc(program_); generate_program_toc(); if (!program_->get_consts().empty()) { f_out_ << "

Constants

" << endl; vector consts = program_->get_consts(); f_out_ << ""; f_out_ << "" << endl; generate_consts(consts); f_out_ << "
ConstantTypeValue
"; } if (!program_->get_enums().empty()) { f_out_ << "

Enumerations

" << endl; // Generate enums vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } } if (!program_->get_typedefs().empty()) { f_out_ << "

Type declarations

" << endl; // Generate typedefs vector typedefs = program_->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { generate_typedef(*td_iter); } } if (!program_->get_objects().empty()) { f_out_ << "

Data structures

" << endl; // Generate structs and exceptions in declared order vector objects = program_->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { if ((*o_iter)->is_xception()) { generate_xception(*o_iter); } else { generate_struct(*o_iter); } } } if (!program_->get_services().empty()) { f_out_ << "

Services

" << endl; // Generate services vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { service_name_ = get_service_name(*sv_iter); generate_service(*sv_iter); } } f_out_ << "
" << endl; f_out_.close(); generate_index(); generate_css(); } /** * Emits the index.html file for the recursive set of Thrift programs */ void t_html_generator::generate_index() { current_file_ = "index.html"; string index_fname = get_out_dir() + current_file_; f_out_.open(index_fname.c_str()); f_out_ << "" << endl << "" << endl; generate_style_tag(); f_out_ << "All Thrift declarations" << endl << "
" << endl << "

All Thrift declarations

" << endl; f_out_ << "" << "" << endl; vector programs; generate_program_toc_rows(program_, programs); f_out_ << "
ModuleServicesData typesConstants
" << endl; f_out_ << "
" << endl; f_out_.close(); } void t_html_generator::generate_css() { if (!standalone_) { current_file_ = "style.css"; string css_fname = get_out_dir() + current_file_; f_out_.open(css_fname.c_str()); generate_css_content(f_out_); f_out_.close(); } } void t_html_generator::generate_css_content(std::ostream& f_target) { f_target << BOOTSTRAP_CSS() << endl; f_target << "/* Auto-generated CSS for generated Thrift docs */" << endl; f_target << "h3, h4 { margin-bottom: 6px; }" << endl; f_target << "div.definition { border: 1px solid #CCC; margin-bottom: 10px; padding: 10px; }" << endl; f_target << "div.extends { margin: -0.5em 0 1em 5em }" << endl; f_target << "td { vertical-align: top; }" << endl; f_target << "table { empty-cells: show; }" << endl; f_target << "code { line-height: 20px; }" << endl; f_target << ".table-bordered th, .table-bordered td { border-bottom: 1px solid #DDDDDD; }" << endl; } /** * Generates the CSS tag. * Depending on "standalone", either a CSS file link (default), or the entire CSS is embedded * inline. */ void t_html_generator::generate_style_tag() { if (!standalone_) { f_out_ << "" << endl; } else { f_out_ << "" << endl; } } /** * Returns the target file for a link * The returned string is empty, whenever filename refers to the current file. */ std::string t_html_generator::make_file_link(std::string filename) { return (current_file_.compare(filename) != 0) ? filename : ""; } /** * If the provided documentable object has documentation attached, this * will emit it to the output stream in HTML format. */ void t_html_generator::print_doc(t_doc* tdoc) { if (tdoc->has_doc()) { if (unsafe_) { f_out_ << tdoc->get_doc() << "
"; } else { f_out_ << "
" << escape_html(tdoc->get_doc()) << "

"; } } } bool t_html_generator::is_utf8_sequence(std::string const& str, size_t firstpos) { // leading char determines the length of the sequence unsigned char c = str.at(firstpos); int count = 0; if ((c & 0xE0) == 0xC0) { count = 1; } else if ((c & 0xF0) == 0xE0) { count = 2; } else if ((c & 0xF8) == 0xF0) { count = 3; } else if ((c & 0xFC) == 0xF8) { count = 4; } else if ((c & 0xFE) == 0xFC) { count = 5; } else { // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 leading byte", c, int(c)); return false; // no UTF-8 } // following chars size_t pos = firstpos + 1; while ((pos < str.length()) && (0 < count)) { c = str.at(pos); if ((c & 0xC0) != 0x80) { // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 following byte", c, int(c)); return false; // no UTF-8 } --count; ++pos; } // true if the sequence is complete return (0 == count); } void t_html_generator::detect_input_encoding(std::string const& str, size_t firstpos) { if (is_utf8_sequence(str, firstpos)) { pdebug("Input seems to be already UTF-8 encoded"); input_type_ = INPUT_UTF8; return; } // fallback pwarning(1, "Input is not UTF-8, treating as plain ANSI"); input_type_ = INPUT_PLAIN; } void t_html_generator::init_allowed__markup() { allowed_markup.clear(); // standalone tags allowed_markup["br"] = 1; allowed_markup["br/"] = 1; allowed_markup["img"] = 1; // paired tags allowed_markup["b"] = 1; allowed_markup["/b"] = 1; allowed_markup["u"] = 1; allowed_markup["/u"] = 1; allowed_markup["i"] = 1; allowed_markup["/i"] = 1; allowed_markup["s"] = 1; allowed_markup["/s"] = 1; allowed_markup["big"] = 1; allowed_markup["/big"] = 1; allowed_markup["small"] = 1; allowed_markup["/small"] = 1; allowed_markup["sup"] = 1; allowed_markup["/sup"] = 1; allowed_markup["sub"] = 1; allowed_markup["/sub"] = 1; allowed_markup["pre"] = 1; allowed_markup["/pre"] = 1; allowed_markup["tt"] = 1; allowed_markup["/tt"] = 1; allowed_markup["ul"] = 1; allowed_markup["/ul"] = 1; allowed_markup["ol"] = 1; allowed_markup["/ol"] = 1; allowed_markup["li"] = 1; allowed_markup["/li"] = 1; allowed_markup["a"] = 1; allowed_markup["/a"] = 1; allowed_markup["p"] = 1; allowed_markup["/p"] = 1; allowed_markup["code"] = 1; allowed_markup["/code"] = 1; allowed_markup["dl"] = 1; allowed_markup["/dl"] = 1; allowed_markup["dt"] = 1; allowed_markup["/dt"] = 1; allowed_markup["dd"] = 1; allowed_markup["/dd"] = 1; allowed_markup["h1"] = 1; allowed_markup["/h1"] = 1; allowed_markup["h2"] = 1; allowed_markup["/h2"] = 1; allowed_markup["h3"] = 1; allowed_markup["/h3"] = 1; allowed_markup["h4"] = 1; allowed_markup["/h4"] = 1; allowed_markup["h5"] = 1; allowed_markup["/h5"] = 1; allowed_markup["h6"] = 1; allowed_markup["/h6"] = 1; } std::string t_html_generator::escape_html_tags(std::string const& str) { std::ostringstream result; unsigned char c = '?'; size_t lastpos; size_t firstpos = 0; while (firstpos < str.length()) { // look for non-ASCII char lastpos = firstpos; while (lastpos < str.length()) { c = str.at(lastpos); if (('<' == c) || ('>' == c)) { break; } ++lastpos; } // copy what we got so far if (lastpos > firstpos) { result << str.substr(firstpos, lastpos - firstpos); firstpos = lastpos; } // reached the end? if (firstpos >= str.length()) { break; } // tag end without corresponding begin ++firstpos; if ('>' == c) { result << ">"; continue; } // extract the tag std::ostringstream tagstream; while (firstpos < str.length()) { c = str.at(firstpos); ++firstpos; if ('<' == c) { tagstream << "<"; // nested begin? } else if ('>' == c) { break; } else { tagstream << c; // not very efficient, but tags should be quite short } } // we allow for several markup in docstrings, all else will become escaped string tag_content = tagstream.str(); string tag_key = tag_content; size_t first_white = tag_key.find_first_of(" \t\f\v\n\r"); if (first_white != string::npos) { tag_key.erase(first_white); } for (char & i : tag_key) { i = tolower(i); } if (allowed_markup.find(tag_key) != allowed_markup.end()) { result << "<" << tag_content << ">"; } else { result << "<" << tagstream.str() << ">"; pverbose("illegal markup <%s> in doc-comment\n", tag_key.c_str()); } } return result.str(); } std::string t_html_generator::escape_html(std::string const& str) { // the generated HTML header says it is UTF-8 encoded // if UTF-8 input has been detected before, we don't need to change anything if (input_type_ == INPUT_UTF8) { return escape_html_tags(str); } // convert unsafe chars to their &#; equivalent std::ostringstream result; unsigned char c = '?'; unsigned int ic = 0; size_t lastpos; size_t firstpos = 0; while (firstpos < str.length()) { // look for non-ASCII char lastpos = firstpos; while (lastpos < str.length()) { c = str.at(lastpos); ic = c; if ((32 > ic) || (127 < ic)) { break; } ++lastpos; } // copy what we got so far if (lastpos > firstpos) { result << str.substr(firstpos, lastpos - firstpos); firstpos = lastpos; } // reached the end? if (firstpos >= str.length()) { break; } // some control code? if (ic <= 31) { switch (c) { case '\r': case '\n': case '\t': result << c; break; default: // silently consume all other ctrl chars break; } ++firstpos; continue; } // reached the end? if (firstpos >= str.length()) { break; } // try to detect input encoding if (input_type_ == INPUT_UNKNOWN) { detect_input_encoding(str, firstpos); if (input_type_ == INPUT_UTF8) { lastpos = str.length(); result << str.substr(firstpos, lastpos - firstpos); break; } } // convert the character to something useful based on the detected encoding switch (input_type_) { case INPUT_PLAIN: result << "&#" << ic << ";"; ++firstpos; break; default: throw "Unexpected or unrecognized input encoding"; } } return escape_html_tags(result.str()); } /** * Prints out the provided type in HTML */ int t_html_generator::print_type(t_type* ttype) { std::string::size_type len = 0; f_out_ << ""; if (ttype->is_container()) { if (ttype->is_list()) { f_out_ << "list<"; len = 6 + print_type(((t_list*)ttype)->get_elem_type()); f_out_ << ">"; } else if (ttype->is_set()) { f_out_ << "set<"; len = 5 + print_type(((t_set*)ttype)->get_elem_type()); f_out_ << ">"; } else if (ttype->is_map()) { f_out_ << "map<"; len = 5 + print_type(((t_map*)ttype)->get_key_type()); f_out_ << ", "; len += print_type(((t_map*)ttype)->get_val_type()); f_out_ << ">"; } } else if (ttype->is_base_type()) { f_out_ << (ttype->is_binary() ? "binary" : ttype->get_name()); len = ttype->get_name().size(); } else { string prog_name = ttype->get_program()->get_name(); string type_name = ttype->get_name(); f_out_ << "
is_typedef()) { f_out_ << "Struct_"; } else if (ttype->is_struct() || ttype->is_xception()) { f_out_ << "Struct_"; } else if (ttype->is_enum()) { f_out_ << "Enum_"; } else if (ttype->is_service()) { f_out_ << "Svc_"; } f_out_ << type_name << "\">"; len = type_name.size(); if (ttype->get_program() != program_) { f_out_ << prog_name << "."; len += prog_name.size() + 1; } f_out_ << type_name << ""; } f_out_ << ""; return (int)len; } /** * Prints out an HTML representation of the provided constant value */ void t_html_generator::print_const_value(t_type* type, t_const_value* tvalue) { // if tvalue is an identifier, the constant content is already shown elsewhere if (tvalue->get_type() == t_const_value::CV_IDENTIFIER) { string fname = program_->get_name() + ".html"; string name = escape_html(tvalue->get_identifier()); f_out_ << "" + name + ""; return; } t_type* truetype = type; while (truetype->is_typedef()) { truetype = ((t_typedef*)truetype)->get_type(); } bool first = true; if (truetype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: f_out_ << '"' << escape_html(get_escaped_string(tvalue)) << '"'; break; case t_base_type::TYPE_BOOL: f_out_ << ((tvalue->get_integer() != 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I16: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I32: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I64: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (tvalue->get_type() == t_const_value::CV_INTEGER) { f_out_ << tvalue->get_integer(); } else { f_out_ << tvalue->get_double(); } break; default: f_out_ << "UNKNOWN BASE TYPE"; break; } } else if (truetype->is_enum()) { f_out_ << escape_html(truetype->get_name()) << "." << escape_html(tvalue->get_identifier_name()); } else if (truetype->is_struct() || truetype->is_xception()) { f_out_ << "{ "; const vector& fields = ((t_struct*)truetype)->get_members(); vector::const_iterator f_iter; const map& val = tvalue->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + truetype->get_name() + " has no field " + v_iter->first->get_string(); } if (!first) { f_out_ << ", "; } first = false; f_out_ << escape_html(v_iter->first->get_string()) << " = "; print_const_value(field_type, v_iter->second); } f_out_ << " }"; } else if (truetype->is_map()) { f_out_ << "{ "; map map_elems = tvalue->get_map(); map::iterator map_iter; for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_map*)truetype)->get_key_type(), map_iter->first); f_out_ << " = "; print_const_value(((t_map*)truetype)->get_val_type(), map_iter->second); } f_out_ << " }"; } else if (truetype->is_list()) { f_out_ << "{ "; vector list_elems = tvalue->get_list(); ; vector::iterator list_iter; for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_list*)truetype)->get_elem_type(), *list_iter); } f_out_ << " }"; } else if (truetype->is_set()) { f_out_ << "{ "; vector list_elems = tvalue->get_list(); ; vector::iterator list_iter; for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_set*)truetype)->get_elem_type(), *list_iter); } f_out_ << " }"; } else { f_out_ << "UNKNOWN TYPE"; } } /** * Prints out documentation for arguments/exceptions of a function, if any documentation has been * supplied. */ void t_html_generator::print_fn_args_doc(t_function* tfunction) { bool has_docs = false; vector args = tfunction->get_arglist()->get_members(); vector::iterator arg_iter = args.begin(); if (arg_iter != args.end()) { for (; arg_iter != args.end(); arg_iter++) { if ((*arg_iter)->has_doc() && !(*arg_iter)->get_doc().empty()) has_docs = true; } if (has_docs) { arg_iter = args.begin(); f_out_ << "

get_name() << "\">Parameters

" << endl; f_out_ << ""; f_out_ << ""; for (; arg_iter != args.end(); arg_iter++) { f_out_ << "" << endl; } f_out_ << "
NameDescription
" << (*arg_iter)->get_name(); f_out_ << ""; f_out_ << escape_html((*arg_iter)->get_doc()); f_out_ << "
"; } } has_docs = false; vector excepts = tfunction->get_xceptions()->get_members(); vector::iterator ex_iter = excepts.begin(); if (ex_iter != excepts.end()) { for (; ex_iter != excepts.end(); ex_iter++) { if ((*ex_iter)->has_doc() && !(*ex_iter)->get_doc().empty()) has_docs = true; } if (has_docs) { ex_iter = excepts.begin(); f_out_ << "

get_name() << "\">Exceptions

" << endl; f_out_ << ""; f_out_ << ""; for (; ex_iter != excepts.end(); ex_iter++) { f_out_ << "" << endl; } f_out_ << "
TypeDescription
" << (*ex_iter)->get_type()->get_name(); f_out_ << ""; f_out_ << escape_html((*ex_iter)->get_doc()); f_out_ << "
"; } } } /** * Generates a typedef. * * @param ttypedef The type definition */ void t_html_generator::generate_typedef(t_typedef* ttypedef) { string name = ttypedef->get_name(); f_out_ << "
"; f_out_ << "

Typedef: " << name << "

" << endl; f_out_ << "

Base type: "; print_type(ttypedef->get_type()); f_out_ << "

" << endl; print_doc(ttypedef); f_out_ << "
" << endl; } /** * Generates code for an enumerated type. * * @param tenum The enumeration */ void t_html_generator::generate_enum(t_enum* tenum) { string name = tenum->get_name(); f_out_ << "
"; f_out_ << "

Enumeration: " << name << "

" << endl; print_doc(tenum); vector values = tenum->get_constants(); vector::iterator val_iter; f_out_ << "
" << endl; for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { f_out_ << "" << endl; } f_out_ << "
"; f_out_ << (*val_iter)->get_name(); f_out_ << ""; f_out_ << (*val_iter)->get_value(); f_out_ << "" << endl; print_doc((*val_iter)); f_out_ << "
" << endl; } /** * Generates a constant value */ void t_html_generator::generate_const(t_const* tconst) { string name = tconst->get_name(); f_out_ << "" << name << ""; print_type(tconst->get_type()); f_out_ << ""; print_const_value(tconst->get_type(), tconst->get_value()); f_out_ << ""; if (tconst->has_doc()) { f_out_ << "
"; print_doc(tconst); f_out_ << "
"; } } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_html_generator::generate_struct(t_struct* tstruct) { string name = tstruct->get_name(); f_out_ << "
"; f_out_ << "

"; if (tstruct->is_xception()) { f_out_ << "Exception: "; } else if (tstruct->is_union()) { f_out_ << "Union: "; } else { f_out_ << "Struct: "; } f_out_ << name << "

" << endl; vector members = tstruct->get_members(); vector::iterator mem_iter = members.begin(); f_out_ << ""; f_out_ << "" << endl; for (; mem_iter != members.end(); mem_iter++) { f_out_ << "" << endl; } f_out_ << "
KeyFieldTypeDescriptionRequirednessDefault value
" << (*mem_iter)->get_key() << ""; f_out_ << (*mem_iter)->get_name(); f_out_ << ""; print_type((*mem_iter)->get_type()); f_out_ << ""; f_out_ << escape_html((*mem_iter)->get_doc()); f_out_ << ""; if ((*mem_iter)->get_req() == t_field::T_OPTIONAL) { f_out_ << "optional"; } else if ((*mem_iter)->get_req() == t_field::T_REQUIRED) { f_out_ << "required"; } else { f_out_ << "default"; } f_out_ << ""; t_const_value* default_val = (*mem_iter)->get_value(); if (default_val != nullptr) { f_out_ << ""; print_const_value((*mem_iter)->get_type(), default_val); f_out_ << ""; } f_out_ << "

"; print_doc(tstruct); f_out_ << "
"; } /** * Exceptions are special structs * * @param tstruct The struct definition */ void t_html_generator::generate_xception(t_struct* txception) { generate_struct(txception); } /** * Generates the HTML block for a Thrift service. * * @param tservice The service definition */ void t_html_generator::generate_service(t_service* tservice) { f_out_ << "

Service: " << service_name_ << "

" << endl; if (tservice->get_extends()) { f_out_ << "
extends "; print_type(tservice->get_extends()); f_out_ << "
\n"; } print_doc(tservice); vector functions = tservice->get_functions(); vector::iterator fn_iter = functions.begin(); for (; fn_iter != functions.end(); fn_iter++) { string fn_name = (*fn_iter)->get_name(); f_out_ << "
"; f_out_ << "

Function: " << service_name_ << "." << fn_name << "

" << endl; f_out_ << "
";
    std::string::size_type offset = print_type((*fn_iter)->get_returntype());
    bool first = true;
    f_out_ << " " << fn_name << "(";
    offset += fn_name.size() + 2;
    vector args = (*fn_iter)->get_arglist()->get_members();
    vector::iterator arg_iter = args.begin();
    for (; arg_iter != args.end(); arg_iter++) {
      if (!first) {
        f_out_ << "," << endl;
        for (std::string::size_type i = 0; i < offset; ++i) {
          f_out_ << " ";
        }
      }
      first = false;
      print_type((*arg_iter)->get_type());
      f_out_ << " " << (*arg_iter)->get_name();
      if ((*arg_iter)->get_value() != nullptr) {
        f_out_ << " = ";
        print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value());
      }
    }
    f_out_ << ")" << endl;
    first = true;
    vector excepts = (*fn_iter)->get_xceptions()->get_members();
    vector::iterator ex_iter = excepts.begin();
    if (ex_iter != excepts.end()) {
      f_out_ << "    throws ";
      for (; ex_iter != excepts.end(); ex_iter++) {
        if (!first) {
          f_out_ << ", ";
        }
        first = false;
        print_type((*ex_iter)->get_type());
      }
      f_out_ << endl;
    }
    f_out_ << "
"; print_doc(*fn_iter); print_fn_args_doc(*fn_iter); f_out_ << "
"; } } THRIFT_REGISTER_GENERATOR( html, "HTML", " standalone: Self-contained mode, includes all CSS in the HTML files.\n" " Generates no style.css file, but HTML files will be larger.\n" " noescape: Do not escape html in doc text.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_html_generator.h000066400000000000000000000572051420101504100250560ustar00rootroot00000000000000#define BOOTSTRAP_CSS() \ "/*!\n" \ " * Bootstrap v2.0.3\n" \ " *\n" \ " * Copyright 2012 Twitter, Inc\n" \ " * Licensed under the Apache License v2.0\n" \ " * http://www.apache.org/licenses/LICENSE-2.0\n" \ " *\n" \ " * Designed and built with all the love in the world @twitter by @mdo and @fat.\n" \ " */\n" \ ".clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:\"\";}\n" \ ".clearfix:after{clear:both;}\n" \ ".hide-text{font:0/0 " \ "a;color:transparent;text-shadow:none;background-color:transparent;border:0;}\n" \ ".input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-" \ "moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}\n" \ "article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}\n" \ "audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}\n" \ "audio:not([controls]){display:none;}\n" \ "html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}\n" \ "a:focus{outline:thin dotted #333;outline:5px auto " \ "-webkit-focus-ring-color;outline-offset:-2px;}\n" \ "a:hover,a:active{outline:0;}\n" \ "sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}\n" \ "sup{top:-0.5em;}\n" \ "sub{bottom:-0.25em;}\n" \ "img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}\n" \ "button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}\n" \ "button,input{*overflow:visible;line-height:normal;}\n" \ "button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}\n" \ "button,input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{cursor:pointer;-" \ "webkit-appearance:button;}\n" \ "input[type=\"search\"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:" \ "content-box;-webkit-appearance:textfield;}\n" \ "input[type=\"search\"]::-webkit-search-decoration,input[type=\"search\"]::-webkit-search-" \ "cancel-button{-webkit-appearance:none;}\n" \ "textarea{overflow:auto;vertical-align:top;}\n" \ "body{margin:0;font-family:\"Helvetica " \ "Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-" \ "color:#ffffff;}\n" \ "a{color:#0088cc;text-decoration:none;}\n" \ "a:hover{color:#005580;text-decoration:underline;}\n" \ ".row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:\"\";}\n" \ ".row:after{clear:both;}\n" \ "[class*=\"span\"]{float:left;margin-left:20px;}\n" \ ".container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}\n" \ ".span12{width:940px;}\n" \ ".span11{width:860px;}\n" \ ".span10{width:780px;}\n" \ ".span9{width:700px;}\n" \ ".span8{width:620px;}\n" \ ".span7{width:540px;}\n" \ ".span6{width:460px;}\n" \ ".span5{width:380px;}\n" \ ".span4{width:300px;}\n" \ ".span3{width:220px;}\n" \ ".span2{width:140px;}\n" \ ".span1{width:60px;}\n" \ ".offset12{margin-left:980px;}\n" \ ".offset11{margin-left:900px;}\n" \ ".offset10{margin-left:820px;}\n" \ ".offset9{margin-left:740px;}\n" \ ".offset8{margin-left:660px;}\n" \ ".offset7{margin-left:580px;}\n" \ ".offset6{margin-left:500px;}\n" \ ".offset5{margin-left:420px;}\n" \ ".offset4{margin-left:340px;}\n" \ ".offset3{margin-left:260px;}\n" \ ".offset2{margin-left:180px;}\n" \ ".offset1{margin-left:100px;}\n" \ ".row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:\"\";}" \ "\n" \ ".row-fluid:after{clear:both;}\n" \ ".row-fluid " \ "[class*=\"span\"]{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-" \ "box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:" \ "2.127659574%;*margin-left:2.0744680846382977%;}\n" \ ".row-fluid [class*=\"span\"]:first-child{margin-left:0;}\n" \ ".row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%;}\n" \ ".row-fluid .span11{width:91.489361693%;*width:91.4361702036383%;}\n" \ ".row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%;}\n" \ ".row-fluid .span9{width:74.468085099%;*width:74.4148936096383%;}\n" \ ".row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%;}\n" \ ".row-fluid .span7{width:57.446808505%;*width:57.3936170156383%;}\n" \ ".row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%;}\n" \ ".row-fluid .span5{width:40.425531911%;*width:40.3723404216383%;}\n" \ ".row-fluid .span4{width:31.914893614%;*width:31.8617021246383%;}\n" \ ".row-fluid .span3{width:23.404255317%;*width:23.3510638276383%;}\n" \ ".row-fluid .span2{width:14.89361702%;*width:14.8404255306383%;}\n" \ ".row-fluid .span1{width:6.382978723%;*width:6.329787233638298%;}\n" \ ".container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{" \ "display:table;content:\"\";}\n" \ ".container:after{clear:both;}\n" \ ".container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,." \ "container-fluid:after{display:table;content:\"\";}\n" \ ".container-fluid:after{clear:both;}\n" \ "p{margin:0 0 9px;font-family:\"Helvetica " \ "Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p " \ "small{font-size:11px;color:#999999;}\n" \ ".lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}\n" \ "h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:" \ "optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 " \ "small{font-weight:normal;color:#999999;}\n" \ "h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}\n" \ "h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}\n" \ "h3{font-size:18px;line-height:27px;}h3 small{font-size:14px;}\n" \ "h4,h5,h6{line-height:18px;}\n" \ "h4{font-size:14px;}h4 small{font-size:12px;}\n" \ "h5{font-size:12px;}\n" \ "h6{font-size:11px;color:#999999;text-transform:uppercase;}\n" \ ".page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}\n" \ ".page-header h1{line-height:1;}\n" \ "ul,ol{padding:0;margin:0 0 9px 25px;}\n" \ "ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}\n" \ "ul{list-style:disc;}\n" \ "ol{list-style:decimal;}\n" \ "li{line-height:18px;}\n" \ "ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}\n" \ "dl{margin-bottom:18px;}\n" \ "dt,dd{line-height:18px;}\n" \ "dt{font-weight:bold;line-height:17px;}\n" \ "dd{margin-left:9px;}\n" \ ".dl-horizontal " \ "dt{float:left;width:120px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;" \ "white-space:nowrap;}\n" \ ".dl-horizontal dd{margin-left:130px;}\n" \ "hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}\n" \ "strong{font-weight:bold;}\n" \ "em{font-style:italic;}\n" \ ".muted{color:#999999;}\n" \ "abbr[title]{cursor:help;border-bottom:1px dotted #ddd;}\n" \ "abbr.initialism{font-size:90%;text-transform:uppercase;}\n" \ "blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote " \ "p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}\n" \ "blockquote small{display:block;line-height:18px;color:#999999;}blockquote " \ "small:before{content:'\\2014 \\00A0';}\n" \ "blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid " \ "#eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right " \ "small{text-align:right;}\n" \ "q:before,q:after,blockquote:before,blockquote:after{content:\"\";}\n" \ "address{display:block;margin-bottom:18px;font-style:normal;line-height:18px;}\n" \ "small{font-size:100%;}\n" \ "cite{font-style:normal;}\n" \ "code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,\"Courier " \ "New\",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;" \ "border-radius:3px;}\n" \ "code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}\n" \ "pre{display:block;padding:8.5px;margin:0 0 " \ "9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:" \ "pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid " \ "rgba(0, 0, 0, " \ "0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{" \ "margin-bottom:18px;}\n" \ "pre code{padding:0;color:inherit;background-color:transparent;border:0;}\n" \ ".pre-scrollable{max-height:340px;overflow-y:scroll;}\n" \ ".label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#ffffff;vertical-" \ "align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, " \ "0.25);background-color:#999999;}\n" \ ".label{padding:1px 4px " \ "2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n" \ ".badge{padding:1px 9px " \ "2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}\n" \ "a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}\n" \ ".label-important,.badge-important{background-color:#b94a48;}\n" \ ".label-important[href],.badge-important[href]{background-color:#953b39;}\n" \ ".label-warning,.badge-warning{background-color:#f89406;}\n" \ ".label-warning[href],.badge-warning[href]{background-color:#c67605;}\n" \ ".label-success,.badge-success{background-color:#468847;}\n" \ ".label-success[href],.badge-success[href]{background-color:#356635;}\n" \ ".label-info,.badge-info{background-color:#3a87ad;}\n" \ ".label-info[href],.badge-info[href]{background-color:#2d6987;}\n" \ ".label-inverse,.badge-inverse{background-color:#333333;}\n" \ ".label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}\n" \ "table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}" \ "\n" \ ".table{width:100%;margin-bottom:18px;}.table th,.table " \ "td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid " \ "#dddddd;}\n" \ ".table th{font-weight:bold;}\n" \ ".table thead th{vertical-align:bottom;}\n" \ ".table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table " \ "colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table " \ "thead:first-child tr:first-child th,.table thead:first-child tr:first-child " \ "td{border-top:0;}\n" \ ".table tbody+tbody{border-top:2px solid #dddddd;}\n" \ ".table-condensed th,.table-condensed td{padding:4px 5px;}\n" \ ".table-bordered{border:1px solid " \ "#dddddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-" \ "radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered " \ "td{border-left:1px solid #dddddd;}\n" \ ".table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child " \ "th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead " \ "tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered " \ "colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child " \ "th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child " \ "tr:first-child td{border-top:0;}\n" \ ".table-bordered thead:first-child tr:first-child th:first-child,.table-bordered " \ "tbody:first-child tr:first-child " \ "td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-" \ "radius-topleft:4px;}\n" \ ".table-bordered thead:first-child tr:first-child th:last-child,.table-bordered " \ "tbody:first-child tr:first-child " \ "td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-" \ "radius-topright:4px;}\n" \ ".table-bordered thead:last-child tr:last-child th:first-child,.table-bordered " \ "tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 " \ "4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 " \ "4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-" \ "bottomleft:4px;}\n" \ ".table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child " \ "tr:last-child " \ "td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-" \ "border-radius-bottomright:4px;}\n" \ ".table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) " \ "th{background-color:#f9f9f9;}\n" \ ".table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}\n" \ "table .span1{float:none;width:44px;margin-left:0;}\n" \ "table .span2{float:none;width:124px;margin-left:0;}\n" \ "table .span3{float:none;width:204px;margin-left:0;}\n" \ "table .span4{float:none;width:284px;margin-left:0;}\n" \ "table .span5{float:none;width:364px;margin-left:0;}\n" \ "table .span6{float:none;width:444px;margin-left:0;}\n" \ "table .span7{float:none;width:524px;margin-left:0;}\n" \ "table .span8{float:none;width:604px;margin-left:0;}\n" \ "table .span9{float:none;width:684px;margin-left:0;}\n" \ "table .span10{float:none;width:764px;margin-left:0;}\n" \ "table .span11{float:none;width:844px;margin-left:0;}\n" \ "table .span12{float:none;width:924px;margin-left:0;}\n" \ "table .span13{float:none;width:1004px;margin-left:0;}\n" \ "table .span14{float:none;width:1084px;margin-left:0;}\n" \ "table .span15{float:none;width:1164px;margin-left:0;}\n" \ "table .span16{float:none;width:1244px;margin-left:0;}\n" \ "table .span17{float:none;width:1324px;margin-left:0;}\n" \ "table .span18{float:none;width:1404px;margin-left:0;}\n" \ "table .span19{float:none;width:1484px;margin-left:0;}\n" \ "table .span20{float:none;width:1564px;margin-left:0;}\n" \ "table .span21{float:none;width:1644px;margin-left:0;}\n" \ "table .span22{float:none;width:1724px;margin-left:0;}\n" \ "table .span23{float:none;width:1804px;margin-left:0;}\n" \ "table .span24{float:none;width:1884px;margin-left:0;}" thrift-0.16.0/compiler/cpp/src/thrift/generate/t_java_generator.cc000066400000000000000000006163521420101504100251750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::setfill; using std::setw; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * Java code generator. * */ class t_java_generator : public t_oop_generator { public: t_java_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; bean_style_ = false; android_style_ = false; private_members_ = false; nocamel_style_ = false; fullcamel_style_ = false; android_legacy_ = false; sorted_containers_ = false; java5_ = false; reuse_objects_ = false; use_option_type_ = false; undated_generated_annotations_ = false; suppress_generated_annotations_ = false; rethrow_unhandled_exceptions_ = false; unsafe_binaries_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("beans") == 0) { bean_style_ = true; } else if( iter->first.compare("android") == 0) { android_style_ = true; } else if( iter->first.compare("private-members") == 0) { private_members_ = true; } else if( iter->first.compare("nocamel") == 0) { nocamel_style_ = true; } else if( iter->first.compare("fullcamel") == 0) { fullcamel_style_ = true; } else if( iter->first.compare("android_legacy") == 0) { android_legacy_ = true; } else if( iter->first.compare("sorted_containers") == 0) { sorted_containers_ = true; } else if( iter->first.compare("java5") == 0) { java5_ = true; } else if( iter->first.compare("reuse-objects") == 0) { reuse_objects_ = true; } else if( iter->first.compare("option_type") == 0) { use_option_type_ = true; } else if( iter->first.compare("rethrow_unhandled_exceptions") == 0) { rethrow_unhandled_exceptions_ = true; } else if( iter->first.compare("generated_annotations") == 0) { if( iter->second.compare("undated") == 0) { undated_generated_annotations_ = true; } else if(iter->second.compare("suppress") == 0) { suppress_generated_annotations_ = true; } else { throw "unknown option java:" + iter->first + "=" + iter->second; } } else if( iter->first.compare("unsafe_binaries") == 0) { unsafe_binaries_ = true; } else { throw "unknown option java:" + iter->first; } } if (java5_) { android_legacy_ = true; } out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java"); } /** * Init and close methods */ void init_generator() override; void close_generator() override; void generate_consts(std::vector consts) override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_struct(t_struct* tstruct) override; void generate_union(t_struct* tunion); void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void print_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval = false); std::string render_const_value(std::ostream& out, t_type* type, t_const_value* value); /** * Service-level generation functions */ void generate_java_struct(t_struct* tstruct, bool is_exception); void generate_java_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool in_class = false, bool is_result = false); void generate_java_struct_parcelable(std::ostream& out, t_struct* tstruct); void generate_java_struct_equality(std::ostream& out, t_struct* tstruct); void generate_java_struct_compare_to(std::ostream& out, t_struct* tstruct); void generate_java_struct_reader(std::ostream& out, t_struct* tstruct); void generate_java_validator(std::ostream& out, t_struct* tstruct); void generate_java_struct_result_writer(std::ostream& out, t_struct* tstruct); void generate_java_struct_writer(std::ostream& out, t_struct* tstruct); void generate_java_struct_tostring(std::ostream& out, t_struct* tstruct); void generate_java_struct_clear(std::ostream& out, t_struct* tstruct); void generate_java_struct_write_object(std::ostream& out, t_struct* tstruct); void generate_java_struct_read_object(std::ostream& out, t_struct* tstruct); void generate_java_meta_data_map(std::ostream& out, t_struct* tstruct); void generate_field_value_meta_data(std::ostream& out, t_type* type); std::string get_java_type_string(t_type* type); void generate_java_struct_field_by_id(ostream& out, t_struct* tstruct); void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name); void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name); void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct); void generate_generic_isset_method(std::ostream& out, t_struct* tstruct); void generate_java_bean_boilerplate(std::ostream& out, t_struct* tstruct); void generate_function_helpers(t_function* tfunction); std::string as_camel_case(std::string name, bool ucfirst = true); std::string get_rpc_method_name(std::string name); std::string get_cap_name(std::string name); std::string generate_isset_check(t_field* field); std::string generate_isset_check(std::string field); void generate_isset_set(ostream& out, t_field* field, std::string prefix); std::string isset_field_id(t_field* field); void generate_service_interface(t_service* tservice); void generate_service_async_interface(t_service* tservice); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_async_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_service_async_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); void generate_process_async_function(t_service* tservice, t_function* tfunction); void generate_java_union(t_struct* tstruct); void generate_union_constructor(ostream& out, t_struct* tstruct); void generate_union_getters_and_setters(ostream& out, t_struct* tstruct); void generate_union_is_set_methods(ostream& out, t_struct* tstruct); void generate_union_abstract_methods(ostream& out, t_struct* tstruct); void generate_check_type(ostream& out, t_struct* tstruct); void generate_standard_scheme_read_value(ostream& out, t_struct* tstruct); void generate_standard_scheme_write_value(ostream& out, t_struct* tstruct); void generate_tuple_scheme_read_value(ostream& out, t_struct* tstruct); void generate_tuple_scheme_write_value(ostream& out, t_struct* tstruct); void generate_get_field_desc(ostream& out, t_struct* tstruct); void generate_get_struct_desc(ostream& out, t_struct* tstruct); void generate_get_field_name(ostream& out, t_struct* tstruct); void generate_union_comparisons(ostream& out, t_struct* tstruct); void generate_union_hashcode(ostream& out, t_struct* tstruct); void generate_scheme_map(ostream& out, t_struct* tstruct); void generate_standard_writer(ostream& out, t_struct* tstruct, bool is_result); void generate_standard_reader(ostream& out, t_struct* tstruct); void generate_java_struct_standard_scheme(ostream& out, t_struct* tstruct, bool is_result); void generate_java_struct_tuple_scheme(ostream& out, t_struct* tstruct); void generate_java_struct_tuple_reader(ostream& out, t_struct* tstruct); void generate_java_struct_tuple_writer(ostream& out, t_struct* tstruct); void generate_java_scheme_lookup(ostream& out); void generate_javax_generated_annotation(ostream& out); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", bool has_metadata = true); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "", bool has_metadata = true); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "", std::string obj = "", bool has_metadata = true); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "", std::string obj = "", bool has_metadata = true); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = "", std::string obj = "", bool has_metadata = true); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", bool has_metadata = true); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "", bool has_metadata = true); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string iter, std::string map, bool has_metadata = true); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter, bool has_metadata = true); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter, bool has_metadata = true); void generate_deep_copy_container(std::ostream& out, std::string source_name_p1, std::string source_name_p2, std::string result_name, t_type* type); void generate_deep_copy_non_container(std::ostream& out, std::string source_name, std::string dest_name, t_type* type); enum isset_type { ISSET_NONE, ISSET_PRIMITIVE, ISSET_BITSET }; isset_type needs_isset(t_struct* tstruct, std::string* outPrimitiveType = nullptr); /** * Helper rendering functions */ std::string java_package(); std::string java_suppressions(); std::string java_nullable_annotation(); std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false, bool skip_generic = false, bool force_namespace = false); std::string base_type_name(t_base_type* tbase, bool in_container = false); std::string declare_field(t_field* tfield, bool init = false, bool comment = false); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string function_signature_async(t_function* tfunction, bool use_base_method = false, std::string prefix = ""); std::string argument_list(t_struct* tstruct, bool include_types = true); std::string async_function_call_arglist(t_function* tfunc, bool use_base_method = true, bool include_types = true); std::string async_argument_list(t_function* tfunct, t_struct* tstruct, t_type* ttype, bool include_types = false); std::string type_to_enum(t_type* ttype); void generate_struct_desc(ostream& out, t_struct* tstruct); void generate_field_descs(ostream& out, t_struct* tstruct); void generate_field_name_constants(ostream& out, t_struct* tstruct); std::string make_valid_java_filename(std::string const& fromName); std::string make_valid_java_identifier(std::string const& fromName); bool type_can_be_null(t_type* ttype) { ttype = get_true_type(ttype); return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string() || ttype->is_enum(); } bool is_deprecated(const std::map& annotations) { return annotations.find("deprecated") != annotations.end(); } bool is_enum_set(t_type* ttype) { if (!sorted_containers_) { ttype = get_true_type(ttype); if (ttype->is_set()) { t_set* tset = (t_set*)ttype; t_type* elem_type = get_true_type(tset->get_elem_type()); return elem_type->is_enum(); } } return false; } bool is_enum_map(t_type* ttype) { if (!sorted_containers_) { ttype = get_true_type(ttype); if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; t_type* key_type = get_true_type(tmap->get_key_type()); return key_type->is_enum(); } } return false; } std::string inner_enum_type_name(t_type* ttype) { ttype = get_true_type(ttype); if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; t_type* key_type = get_true_type(tmap->get_key_type()); return type_name(key_type, true) + ".class"; } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; t_type* elem_type = get_true_type(tset->get_elem_type()); return type_name(elem_type, true) + ".class"; } return ""; } std::string constant_name(std::string name); private: /** * File streams */ std::string package_name_; ofstream_with_content_based_conditional_update f_service_; std::string package_dir_; bool bean_style_; bool android_style_; bool private_members_; bool nocamel_style_; bool fullcamel_style_; bool android_legacy_; bool java5_; bool sorted_containers_; bool reuse_objects_; bool use_option_type_; bool undated_generated_annotations_; bool suppress_generated_annotations_; bool rethrow_unhandled_exceptions_; bool unsafe_binaries_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_java_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); package_name_ = program_->get_namespace("java"); string dir = package_name_; string subdir = get_out_dir(); string::size_type loc; while ((loc = dir.find(".")) != string::npos) { subdir = subdir + "/" + dir.substr(0, loc); MKDIR(subdir.c_str()); dir = dir.substr(loc + 1); } if (dir.size() > 0) { subdir = subdir + "/" + dir; MKDIR(subdir.c_str()); } package_dir_ = subdir; } /** * Packages the generated file * * @return String of the package, i.e. "package org.apache.thriftdemo;" */ string t_java_generator::java_package() { if (!package_name_.empty()) { return string("package ") + package_name_ + ";\n\n"; } return ""; } string t_java_generator::java_suppressions() { return "@SuppressWarnings({\"cast\", \"rawtypes\", \"serial\", \"unchecked\", \"unused\"})\n"; } string t_java_generator::java_nullable_annotation() { return "@org.apache.thrift.annotation.Nullable"; } /** * Nothing in Java */ void t_java_generator::close_generator() { } /** * Generates a typedef. This is not done in Java, since it does * not support arbitrary name replacements, and it'd be a wacky waste * of overhead to make wrapper classes. * * @param ttypedef The type definition */ void t_java_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Enums are a class with a set of static constants. * * @param tenum The enumeration */ void t_java_generator::generate_enum(t_enum* tenum) { bool is_deprecated = this->is_deprecated(tenum->annotations_); // Make output file string f_enum_name = package_dir_ + "/" + make_valid_java_filename(tenum->get_name()) + ".java"; ofstream_with_content_based_conditional_update f_enum; f_enum.open(f_enum_name.c_str()); // Comment and package it f_enum << autogen_comment() << java_package() << endl; generate_java_doc(f_enum, tenum); if (!suppress_generated_annotations_) { generate_javax_generated_annotation(f_enum); } if (is_deprecated) { indent(f_enum) << "@Deprecated" << endl; } indent(f_enum) << "public enum " << tenum->get_name() << " implements org.apache.thrift.TEnum "; scope_up(f_enum); vector constants = tenum->get_constants(); vector::iterator c_iter; bool first = true; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); if (first) { first = false; } else { f_enum << "," << endl; } generate_java_doc(f_enum, *c_iter); if (this->is_deprecated((*c_iter)->annotations_)) { indent(f_enum) << "@Deprecated" << endl; } indent(f_enum) << (*c_iter)->get_name() << "(" << value << ")"; } f_enum << ";" << endl << endl; // Field for thriftCode indent(f_enum) << "private final int value;" << endl << endl; indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl; indent(f_enum) << " this.value = value;" << endl; indent(f_enum) << "}" << endl << endl; indent(f_enum) << "/**" << endl; indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL." << endl; indent(f_enum) << " */" << endl; indent(f_enum) << "public int getValue() {" << endl; indent(f_enum) << " return value;" << endl; indent(f_enum) << "}" << endl << endl; indent(f_enum) << "/**" << endl; indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL." << endl; indent(f_enum) << " * @return null if the value is not found." << endl; indent(f_enum) << " */" << endl; indent(f_enum) << java_nullable_annotation() << endl; indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl; indent_up(); indent(f_enum) << "switch (value) {" << endl; indent_up(); for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); indent(f_enum) << "case " << value << ":" << endl; indent(f_enum) << " return " << (*c_iter)->get_name() << ";" << endl; } indent(f_enum) << "default:" << endl; indent(f_enum) << " return null;" << endl; indent_down(); indent(f_enum) << "}" << endl; indent_down(); indent(f_enum) << "}" << endl; scope_down(f_enum); f_enum.close(); } /** * Generates a class that holds all the constants. */ void t_java_generator::generate_consts(std::vector consts) { if (consts.empty()) { return; } string f_consts_name = package_dir_ + '/' + make_valid_java_filename(program_name_) + "Constants.java"; ofstream_with_content_based_conditional_update f_consts; f_consts.open(f_consts_name.c_str()); // Print header f_consts << autogen_comment() << java_package() << java_suppressions(); f_consts << "public class " << make_valid_java_identifier(program_name_) << "Constants {" << endl << endl; indent_up(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { generate_java_doc(f_consts, (*c_iter)); print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false); } indent_down(); indent(f_consts) << "}" << endl; f_consts.close(); } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ void t_java_generator::print_const_value(std::ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) { type = get_true_type(type); indent(out); if (!defval) { out << (in_static ? "" : "public static final ") << type_name(type) << " "; } if (type->is_base_type()) { string v2 = render_const_value(out, type, value); out << name << " = " << v2 << ";" << endl << endl; } else if (type->is_enum()) { out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl; } else if (type->is_struct() || type->is_xception()) { const vector& unsorted_fields = ((t_struct*)type)->get_members(); vector fields = unsorted_fields; std::sort(fields.begin(), fields.end(), t_field::key_compare()); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; out << name << " = new " << type_name(type, false, true) << "();" << endl; if (!in_static) { indent(out) << "static {" << endl; indent_up(); } for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string val = render_const_value(out, field_type, v_iter->second); indent(out) << name << "."; std::string cap_name = get_cap_name(v_iter->first->get_string()); out << "set" << cap_name << "(" << val << ");" << endl; } if (!in_static) { indent_down(); indent(out) << "}" << endl; } out << endl; } else if (type->is_map()) { std::string constructor_args; if (is_enum_map(type)) { constructor_args = inner_enum_type_name(type); } out << name << " = new " << type_name(type, false, true) << "(" << constructor_args << ");" << endl; if (!in_static) { indent(out) << "static {" << endl; indent_up(); } t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(out, ktype, v_iter->first); string val = render_const_value(out, vtype, v_iter->second); indent(out) << name << ".put(" << key << ", " << val << ");" << endl; } if (!in_static) { indent_down(); indent(out) << "}" << endl; } out << endl; } else if (type->is_list() || type->is_set()) { if (is_enum_set(type)) { out << name << " = " << type_name(type, false, true, true) << ".noneOf(" << inner_enum_type_name(type) << ");" << endl; } else { out << name << " = new " << type_name(type, false, true) << "();" << endl; } if (!in_static) { indent(out) << "static {" << endl; indent_up(); } t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(out, etype, *v_iter); indent(out) << name << ".add(" << val << ");" << endl; } if (!in_static) { indent_down(); indent(out) << "}" << endl; } out << endl; } else { throw "compiler error: no const of type " + type->get_name(); } } string t_java_generator::render_const_value(ostream& out, t_type* type, t_const_value* value) { type = get_true_type(type); std::ostringstream render; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: if (((t_base_type*)type)->is_binary()) { render << "java.nio.ByteBuffer.wrap(\"" << get_escaped_string(value) << "\".getBytes())"; } else { render << '"' << get_escaped_string(value) << '"'; } break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: render << "(byte)" << value->get_integer(); break; case t_base_type::TYPE_I16: render << "(short)" << value->get_integer(); break; case t_base_type::TYPE_I32: render << value->get_integer(); break; case t_base_type::TYPE_I64: render << value->get_integer() << "L"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << value->get_integer() << "d"; } else { render << emit_double_as_string(value->get_double()); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { std::string namespace_prefix = type->get_program()->get_namespace("java"); if (namespace_prefix.length() > 0) { namespace_prefix += "."; } render << namespace_prefix << value->get_identifier_with_parent(); } else { string t = tmp("tmp"); print_const_value(out, t, type, value, true); render << t; } return render.str(); } /** * Generates a struct definition for a thrift data type. This will be a org.apache.thrift.TBase * implementor. * * @param tstruct The struct definition */ void t_java_generator::generate_struct(t_struct* tstruct) { if (tstruct->is_union()) { generate_java_union(tstruct); } else { generate_java_struct(tstruct, false); } } /** * Exceptions are structs, but they inherit from Exception * * @param tstruct The struct definition */ void t_java_generator::generate_xception(t_struct* txception) { generate_java_struct(txception, true); } /** * Java struct definition. * * @param tstruct The struct definition */ void t_java_generator::generate_java_struct(t_struct* tstruct, bool is_exception) { // Make output file string f_struct_name = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name()) + ".java"; ofstream_with_content_based_conditional_update f_struct; f_struct.open(f_struct_name.c_str()); f_struct << autogen_comment() << java_package() << java_suppressions(); generate_java_struct_definition(f_struct, tstruct, is_exception); f_struct.close(); } /** * Java union definition. * * @param tstruct The struct definition */ void t_java_generator::generate_java_union(t_struct* tstruct) { // Make output file string f_struct_name = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name()) + ".java"; ofstream_with_content_based_conditional_update f_struct; f_struct.open(f_struct_name.c_str()); f_struct << autogen_comment() << java_package() << java_suppressions(); generate_java_doc(f_struct, tstruct); bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); bool is_deprecated = this->is_deprecated(tstruct->annotations_); if (!suppress_generated_annotations_) { generate_javax_generated_annotation(f_struct); } if (is_deprecated) { indent(f_struct) << "@Deprecated" << endl; } indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << tstruct->get_name() << " extends org.apache.thrift.TUnion<" << tstruct->get_name() << ", " << tstruct->get_name() << "._Fields> "; scope_up(f_struct); generate_struct_desc(f_struct, tstruct); generate_field_descs(f_struct, tstruct); f_struct << endl; generate_field_name_constants(f_struct, tstruct); f_struct << endl; generate_java_meta_data_map(f_struct, tstruct); generate_union_constructor(f_struct, tstruct); f_struct << endl; generate_union_abstract_methods(f_struct, tstruct); f_struct << endl; generate_java_struct_field_by_id(f_struct, tstruct); f_struct << endl; generate_union_getters_and_setters(f_struct, tstruct); f_struct << endl; generate_union_is_set_methods(f_struct, tstruct); f_struct << endl; generate_union_comparisons(f_struct, tstruct); f_struct << endl; generate_union_hashcode(f_struct, tstruct); f_struct << endl; generate_java_struct_write_object(f_struct, tstruct); f_struct << endl; generate_java_struct_read_object(f_struct, tstruct); f_struct << endl; scope_down(f_struct); f_struct.close(); } void t_java_generator::generate_union_constructor(ostream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; indent(out) << "public " << type_name(tstruct) << "() {" << endl; indent_up(); bool default_value = false; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* type = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr) { indent(out) << "super(_Fields." << constant_name((*m_iter)->get_name()) << ", " << render_const_value(out, type, (*m_iter)->get_value()) << ");" << endl; default_value = true; break; } } if (default_value == false) { indent(out) << "super();" << endl; } indent_down(); indent(out) << "}" << endl << endl; indent(out) << "public " << type_name(tstruct) << "(_Fields setField, java.lang.Object value) {" << endl; indent(out) << " super(setField, value);" << endl; indent(out) << "}" << endl << endl; indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {" << endl; indent(out) << " super(other);" << endl; indent(out) << "}" << endl; indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; indent(out) << "}" << endl << endl; // generate "constructors" for each field for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* type = (*m_iter)->get_type(); indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(" << type_name(type) << " value) {" << endl; indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl; indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl; indent(out) << " return x;" << endl; indent(out) << "}" << endl << endl; if (type->is_binary()) { indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(byte[] value) {" << endl; indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl; indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()); if(unsafe_binaries_) { indent(out) << "(java.nio.ByteBuffer.wrap(value));" << endl; }else{ indent(out) << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl; } indent(out) << " return x;" << endl; indent(out) << "}" << endl << endl; } } } void t_java_generator::generate_union_getters_and_setters(ostream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; bool first = true; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (first) { first = false; } else { out << endl; } t_field* field = (*m_iter); t_type* type = field->get_type(); std::string cap_name = get_cap_name(field->get_name()); bool is_deprecated = this->is_deprecated(field->annotations_); generate_java_doc(out, field); if (type->is_binary()) { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public byte[] get" << cap_name << "() {" << endl; indent(out) << " set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(buffer" << get_cap_name("for") << cap_name << "()));" << endl; indent(out) << " java.nio.ByteBuffer b = buffer" << get_cap_name("for") << cap_name << "();" << endl; indent(out) << " return b == null ? null : b.array();" << endl; indent(out) << "}" << endl; out << endl; indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for") << get_cap_name(field->get_name()) << "() {" << endl; indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" << endl; if(unsafe_binaries_){ indent(out) << " return (java.nio.ByteBuffer)getFieldValue();" << endl; }else{ indent(out) << " return org.apache.thrift.TBaseHelper.copyBinary((java.nio.ByteBuffer)getFieldValue());" << endl; } indent(out) << " } else {" << endl; indent(out) << " throw new java.lang.RuntimeException(\"Cannot get field '" << field->get_name() << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl; } else { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public " << type_name(field->get_type()) << " get" << get_cap_name(field->get_name()) << "() {" << endl; indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" << endl; indent(out) << " return (" << type_name(field->get_type(), true) << ")getFieldValue();" << endl; indent(out) << " } else {" << endl; indent(out) << " throw new java.lang.RuntimeException(\"Cannot get field '" << field->get_name() << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl; } out << endl; generate_java_doc(out, field); if (type->is_binary()) { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public void set" << get_cap_name(field->get_name()) << "(byte[] value) {" << endl; indent(out) << " set" << get_cap_name(field->get_name()); if(unsafe_binaries_){ indent(out) << "(java.nio.ByteBuffer.wrap(value));" << endl; }else{ indent(out) << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl; } indent(out) << "}" << endl; out << endl; } if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" << type_name(field->get_type()) << " value) {" << endl; indent(out) << " setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl; if (type_can_be_null(field->get_type())) { indent(out) << " value_ = java.util.Objects.requireNonNull(value,\"" << "_Fields." << constant_name(field->get_name()) << "\");" << endl; } else { indent(out) << " value_ = value;" << endl; } indent(out) << "}" << endl; } } void t_java_generator::generate_union_is_set_methods(ostream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; bool first = true; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (first) { first = false; } else { out << endl; } std::string field_name = (*m_iter)->get_name(); indent(out) << "public boolean is" << get_cap_name("set") << get_cap_name(field_name) << "() {" << endl; indent_up(); indent(out) << "return setField_ == _Fields." << constant_name(field_name) << ";" << endl; indent_down(); indent(out) << "}" << endl << endl; } } void t_java_generator::generate_union_abstract_methods(ostream& out, t_struct* tstruct) { generate_check_type(out, tstruct); out << endl; generate_standard_scheme_read_value(out, tstruct); out << endl; generate_standard_scheme_write_value(out, tstruct); out << endl; generate_tuple_scheme_read_value(out, tstruct); out << endl; generate_tuple_scheme_write_value(out, tstruct); out << endl; generate_get_field_desc(out, tstruct); out << endl; generate_get_struct_desc(out, tstruct); out << endl; indent(out) << "@Override" << endl; indent(out) << "protected _Fields enumForId(short id) {" << endl; indent(out) << " return _Fields.findByThriftIdOrThrow(id);" << endl; indent(out) << "}" << endl; } void t_java_generator::generate_check_type(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "protected void checkType(_Fields setField, java.lang.Object value) throws java.lang.ClassCastException {" << endl; indent_up(); indent(out) << "switch (setField) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent(out) << " if (value instanceof " << type_name(field->get_type(), true, false, true) << ") {" << endl; indent(out) << " break;" << endl; indent(out) << " }" << endl; indent(out) << " throw new java.lang.ClassCastException(\"Was expecting value of type " << type_name(field->get_type(), true, false) << " for field '" << field->get_name() << "', but got \" + value.getClass().getSimpleName());" << endl; // do the real check here } indent(out) << "default:" << endl; indent(out) << " throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_standard_scheme_read_value(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "protected java.lang.Object standardSchemeReadValue(org.apache.thrift.protocol.TProtocol " "iprot, org.apache.thrift.protocol.TField field) throws " "org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl; indent(out) << "if (setField != null) {" << endl; indent_up(); indent(out) << "switch (setField) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent_up(); indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {" << endl; indent_up(); indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl; generate_deserialize_field(out, field, ""); indent(out) << "return " << field->get_name() << ";" << endl; indent_down(); indent(out) << "} else {" << endl; indent(out) << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl; indent(out) << " return null;" << endl; indent(out) << "}" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any " "of the case statements!\");" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "} else {" << endl; indent_up(); indent(out) << "org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl; indent(out) << "return null;" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_standard_scheme_write_value(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol " "oprot) throws org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "switch (setField_) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent_up(); indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = (" << type_name(field->get_type(), true, false) << ")value_;" << endl; generate_serialize_field(out, field, ""); indent(out) << "return;" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + " "setField_);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_tuple_scheme_read_value(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "protected java.lang.Object tupleSchemeReadValue(org.apache.thrift.protocol.TProtocol " "iprot, short fieldID) throws org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "_Fields setField = _Fields.findByThriftId(fieldID);" << endl; indent(out) << "if (setField != null) {" << endl; indent_up(); indent(out) << "switch (setField) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent_up(); indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl; generate_deserialize_field(out, field, ""); indent(out) << "return " << field->get_name() << ";" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any " "of the case statements!\");" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "} else {" << endl; indent_up(); indent(out) << "throw new org.apache.thrift.protocol.TProtocolException(\"Couldn't find a field with field id \" + fieldID);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_tuple_scheme_write_value(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) " "throws org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "switch (setField_) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent_up(); indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = (" << type_name(field->get_type(), true, false) << ")value_;" << endl; generate_serialize_field(out, field, ""); indent(out) << "return;" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + " "setField_);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_get_field_desc(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; indent(out) << "switch (setField) {" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent(out) << " return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl; } indent(out) << "default:" << endl; indent(out) << " throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_get_struct_desc(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "@Override" << endl; indent(out) << "protected org.apache.thrift.protocol.TStruct getStructDesc() {" << endl; indent(out) << " return STRUCT_DESC;" << endl; indent(out) << "}" << endl; } void t_java_generator::generate_union_comparisons(ostream& out, t_struct* tstruct) { // equality indent(out) << "public boolean equals(java.lang.Object other) {" << endl; indent(out) << " if (other instanceof " << tstruct->get_name() << ") {" << endl; indent(out) << " return equals((" << tstruct->get_name() << ")other);" << endl; indent(out) << " } else {" << endl; indent(out) << " return false;" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl; out << endl; indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl; indent(out) << " return other != null && getSetField() == other.getSetField() && " "getFieldValue().equals(other.getFieldValue());" << endl; indent(out) << "}" << endl; out << endl; indent(out) << "@Override" << endl; indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; indent(out) << " int lastComparison = org.apache.thrift.TBaseHelper.compareTo(getSetField(), " "other.getSetField());" << endl; indent(out) << " if (lastComparison == 0) {" << endl; indent(out) << " return org.apache.thrift.TBaseHelper.compareTo(getFieldValue(), " "other.getFieldValue());" << endl; indent(out) << " }" << endl; indent(out) << " return lastComparison;" << endl; indent(out) << "}" << endl; out << endl; } void t_java_generator::generate_union_hashcode(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "@Override" << endl; indent(out) << "public int hashCode() {" << endl; indent(out) << " java.util.List list = new java.util.ArrayList();" << endl; indent(out) << " list.add(this.getClass().getName());" << endl; indent(out) << " org.apache.thrift.TFieldIdEnum setField = getSetField();" << endl; indent(out) << " if (setField != null) {" << endl; indent(out) << " list.add(setField.getThriftFieldId());" << endl; indent(out) << " java.lang.Object value = getFieldValue();" << endl; indent(out) << " if (value instanceof org.apache.thrift.TEnum) {" << endl; indent(out) << " list.add(((org.apache.thrift.TEnum)getFieldValue()).getValue());" << endl; indent(out) << " } else {" << endl; indent(out) << " list.add(value);" << endl; indent(out) << " }" << endl; indent(out) << " }" << endl; indent(out) << " return list.hashCode();" << endl; indent(out) << "}"; } /** * Java struct definition. This has various parameters, as it could be * generated standalone or inside another class as a helper. If it * is a helper than it is a static class. * * @param tstruct The struct definition * @param is_exception Is this an exception? * @param in_class If inside a class, needs to be static class * @param is_result If this is a result it needs a different writer */ void t_java_generator::generate_java_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result) { generate_java_doc(out, tstruct); bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); bool is_deprecated = this->is_deprecated(tstruct->annotations_); if (!in_class && !suppress_generated_annotations_) { generate_javax_generated_annotation(out); } if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class " << tstruct->get_name() << " "; if (is_exception) { out << "extends org.apache.thrift.TException "; } out << "implements org.apache.thrift.TBase<" << tstruct->get_name() << ", " << tstruct->get_name() << "._Fields>, java.io.Serializable, Cloneable, Comparable<" << tstruct->get_name() << ">"; if (android_style_) { out << ", android.os.Parcelable"; } out << " "; scope_up(out); generate_struct_desc(out, tstruct); // Members are public for -java, private for -javabean const vector& members = tstruct->get_members(); vector::const_iterator m_iter; out << endl; generate_field_descs(out, tstruct); out << endl; generate_scheme_map(out, tstruct); out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (bean_style_ || private_members_) { indent(out) << "private "; } else { generate_java_doc(out, *m_iter); indent(out) << "public "; } out << declare_field(*m_iter, false, true) << endl; } out << endl; if (android_style_) { generate_java_struct_parcelable(out, tstruct); } generate_field_name_constants(out, tstruct); // isset data if (members.size() > 0) { out << endl; indent(out) << "// isset id assignments" << endl; int i = 0; int optionals = 0; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() == t_field::T_OPTIONAL) { optionals++; } if (!type_can_be_null((*m_iter)->get_type())) { indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";" << endl; i++; } } std::string primitiveType; switch (needs_isset(tstruct, &primitiveType)) { case ISSET_NONE: break; case ISSET_PRIMITIVE: indent(out) << "private " << primitiveType << " __isset_bitfield = 0;" << endl; break; case ISSET_BITSET: indent(out) << "private java.util.BitSet __isset_bit_vector = new java.util.BitSet(" << i << ");" << endl; break; } if (optionals > 0) { std::string output_string = "private static final _Fields optionals[] = {"; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() == t_field::T_OPTIONAL) { output_string = output_string + "_Fields." + constant_name((*m_iter)->get_name()) + ","; } } indent(out) << output_string.substr(0, output_string.length() - 1) << "};" << endl; } } generate_java_meta_data_map(out, tstruct); bool all_optional_members = true; // Default constructor indent(out) << "public " << tstruct->get_name() << "() {" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr) { print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true); } if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { all_optional_members = false; } } indent_down(); indent(out) << "}" << endl << endl; if (!members.empty() && !all_optional_members) { // Full constructor for all fields indent(out) << "public " << tstruct->get_name() << "(" << endl; indent_up(); bool first = true; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { if (!first) { out << "," << endl; } first = false; indent(out) << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name(); } } out << ")" << endl; indent_down(); indent(out) << "{" << endl; indent_up(); indent(out) << "this();" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { t_type* type = get_true_type((*m_iter)->get_type()); if (type->is_binary()) { if(unsafe_binaries_){ indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";" << endl; }else{ indent(out) << "this." << (*m_iter)->get_name() << " = org.apache.thrift.TBaseHelper.copyBinary(" << (*m_iter)->get_name() << ");" << endl; } } else { indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";" << endl; } generate_isset_set(out, (*m_iter), ""); } } indent_down(); indent(out) << "}" << endl << endl; } // copy constructor indent(out) << "/**" << endl; indent(out) << " * Performs a deep copy on other." << endl; indent(out) << " */" << endl; indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {" << endl; indent_up(); switch (needs_isset(tstruct)) { case ISSET_NONE: break; case ISSET_PRIMITIVE: indent(out) << "__isset_bitfield = other.__isset_bitfield;" << endl; break; case ISSET_BITSET: indent(out) << "__isset_bit_vector.clear();" << endl; indent(out) << "__isset_bit_vector.or(other.__isset_bit_vector);" << endl; break; } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); std::string field_name = field->get_name(); t_type* type = field->get_type()->get_true_type(); bool can_be_null = type_can_be_null(type); if (can_be_null) { indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl; indent_up(); } if (type->is_container()) { generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type); indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl; } else { indent(out) << "this." << field_name << " = "; generate_deep_copy_non_container(out, "other." + field_name, field_name, type); out << ";" << endl; } if (can_be_null) { indent_down(); indent(out) << "}" << endl; } } indent_down(); indent(out) << "}" << endl << endl; // clone method, so that you can deep copy an object when you don't know its class. indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; indent(out) << "}" << endl << endl; generate_java_struct_clear(out, tstruct); generate_java_bean_boilerplate(out, tstruct); generate_generic_field_getters_setters(out, tstruct); generate_generic_isset_method(out, tstruct); generate_java_struct_equality(out, tstruct); generate_java_struct_compare_to(out, tstruct); generate_java_struct_field_by_id(out, tstruct); generate_java_struct_reader(out, tstruct); if (is_result) { generate_java_struct_result_writer(out, tstruct); } else { generate_java_struct_writer(out, tstruct); } generate_java_struct_tostring(out, tstruct); generate_java_validator(out, tstruct); generate_java_struct_write_object(out, tstruct); generate_java_struct_read_object(out, tstruct); generate_java_struct_standard_scheme(out, tstruct, is_result); generate_java_struct_tuple_scheme(out, tstruct); generate_java_scheme_lookup(out); scope_down(out); out << endl; } /** * generates parcelable interface implementation */ void t_java_generator::generate_java_struct_parcelable(ostream& out, t_struct* tstruct) { string tname = tstruct->get_name(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; out << indent() << "@Override" << endl << indent() << "public void writeToParcel(android.os.Parcel out, int flags) {" << endl; indent_up(); string bitsetPrimitiveType = ""; switch (needs_isset(tstruct, &bitsetPrimitiveType)) { case ISSET_NONE: break; case ISSET_PRIMITIVE: indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl; if (bitsetPrimitiveType == "byte") { indent(out) << "out.writeByte(__isset_bitfield);" << endl; } else if (bitsetPrimitiveType == "short") { indent(out) << "out.writeInt(new Short(__isset_bitfield).intValue());" << endl; } else if (bitsetPrimitiveType == "int") { indent(out) << "out.writeInt(__isset_bitfield);" << endl; } else if (bitsetPrimitiveType == "long") { indent(out) << "out.writeLong(__isset_bitfield);" << endl; } out << endl; break; case ISSET_BITSET: indent(out) << "//BitSet" << endl; indent(out) << "out.writeSerializable(__isset_bit_vector);" << endl; out << endl; break; } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); string name = (*m_iter)->get_name(); if (t->is_struct()) { indent(out) << "out.writeParcelable(" << name << ", flags);" << endl; } else if (type_name(t) == "float") { indent(out) << "out.writeFloat(" << name << ");" << endl; } else if (t->is_enum()) { indent(out) << "out.writeInt(" << name << " != null ? " << name << ".getValue() : -1);" << endl; } else if (t->is_list()) { if (((t_list*)t)->get_elem_type()->get_true_type()->is_struct()) { indent(out) << "out.writeTypedList(" << name << ");" << endl; } else { indent(out) << "out.writeList(" << name << ");" << endl; } } else if (t->is_map()) { indent(out) << "out.writeMap(" << name << ");" << endl; } else if (t->is_base_type()) { if (t->is_binary()) { indent(out) << "out.writeInt(" << name << "!=null ? 1 : 0);" << endl; indent(out) << "if(" << name << " != null) { " << endl; indent_up(); indent(out) << "out.writeByteArray(" << name << ".array(), " << name << ".position() + " << name << ".arrayOffset(), " << name << ".limit() - " << name << ".position() );" << endl; scope_down(out); } else { switch (((t_base_type*)t)->get_base()) { case t_base_type::TYPE_I16: indent(out) << "out.writeInt(new Short(" << name << ").intValue());" << endl; break; case t_base_type::TYPE_I32: indent(out) << "out.writeInt(" << name << ");" << endl; break; case t_base_type::TYPE_I64: indent(out) << "out.writeLong(" << name << ");" << endl; break; case t_base_type::TYPE_BOOL: indent(out) << "out.writeInt(" << name << " ? 1 : 0);" << endl; break; case t_base_type::TYPE_I8: indent(out) << "out.writeByte(" << name << ");" << endl; break; case t_base_type::TYPE_DOUBLE: indent(out) << "out.writeDouble(" << name << ");" << endl; break; case t_base_type::TYPE_STRING: indent(out) << "out.writeString(" << name << ");" << endl; break; case t_base_type::TYPE_VOID: break; } } } } scope_down(out); out << endl; out << indent() << "@Override" << endl << indent() << "public int describeContents() {" << endl; indent_up(); out << indent() << "return 0;" << endl; scope_down(out); out << endl; indent(out) << "public " << tname << "(android.os.Parcel in) {" << endl; indent_up(); // read in the required bitfield switch (needs_isset(tstruct, &bitsetPrimitiveType)) { case ISSET_NONE: break; case ISSET_PRIMITIVE: indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl; if (bitsetPrimitiveType == "byte") { indent(out) << "__isset_bitfield = in.readByte();" << endl; } else if (bitsetPrimitiveType == "short") { indent(out) << "__isset_bitfield = (short) in.readInt();" << endl; } else if (bitsetPrimitiveType == "int") { indent(out) << "__isset_bitfield = in.readInt();" << endl; } else if (bitsetPrimitiveType == "long") { indent(out) << "__isset_bitfield = in.readLong();" << endl; } out << endl; break; case ISSET_BITSET: indent(out) << "//BitSet" << endl; indent(out) << "__isset_bit_vector = (java.util.BitSet) in.readSerializable();" << endl; out << endl; break; } // read all the fields for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); string name = (*m_iter)->get_name(); string prefix = "this." + name; if (t->is_struct()) { indent(out) << prefix << "= in.readParcelable(" << tname << ".class.getClassLoader());" << endl; } else if (t->is_enum()) { indent(out) << prefix << " = " << type_name(t) << ".findByValue(in.readInt());" << endl; } else if (t->is_list()) { t_list* list = (t_list*)t; indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl; if (list->get_elem_type()->get_true_type()->is_struct()) { indent(out) << "in.readTypedList(" << prefix << ", " << type_name(list->get_elem_type()) << ".CREATOR);" << endl; } else { indent(out) << "in.readList(" << prefix << ", " << tname << ".class.getClassLoader());" << endl; } } else if (t->is_map()) { indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl; indent(out) << " in.readMap(" << prefix << ", " << tname << ".class.getClassLoader());" << endl; } else if (type_name(t) == "float") { indent(out) << prefix << " = in.readFloat();" << endl; } else if (t->is_base_type()) { t_base_type* bt = (t_base_type*)t; if (bt->is_binary()) { indent(out) << "if(in.readInt()==1) {" << endl; indent_up(); indent(out) << prefix << " = java.nio.ByteBuffer.wrap(in.createByteArray());" << endl; scope_down(out); } else { switch (bt->get_base()) { case t_base_type::TYPE_I16: indent(out) << prefix << " = (short) in.readInt();" << endl; break; case t_base_type::TYPE_I32: indent(out) << prefix << " = in.readInt();" << endl; break; case t_base_type::TYPE_I64: indent(out) << prefix << " = in.readLong();" << endl; break; case t_base_type::TYPE_BOOL: indent(out) << prefix << " = (in.readInt()==1);" << endl; break; case t_base_type::TYPE_I8: indent(out) << prefix << " = in.readByte();" << endl; break; case t_base_type::TYPE_DOUBLE: indent(out) << prefix << " = in.readDouble();" << endl; break; case t_base_type::TYPE_STRING: indent(out) << prefix << "= in.readString();" << endl; break; case t_base_type::TYPE_VOID: break; } } } } scope_down(out); out << endl; indent(out) << "public static final android.os.Parcelable.Creator<" << tname << "> CREATOR = new android.os.Parcelable.Creator<" << tname << ">() {" << endl; indent_up(); indent(out) << "@Override" << endl << indent() << "public " << tname << "[] newArray(int size) {" << endl; indent_up(); indent(out) << "return new " << tname << "[size];" << endl; scope_down(out); out << endl; indent(out) << "@Override" << endl << indent() << "public " << tname << " createFromParcel(android.os.Parcel in) {" << endl; indent_up(); indent(out) << "return new " << tname << "(in);" << endl; scope_down(out); indent_down(); indent(out) << "};" << endl; out << endl; } /** * Generates equals methods and a hashCode method for a structure. * * @param tstruct The struct definition */ void t_java_generator::generate_java_struct_equality(ostream& out, t_struct* tstruct) { out << indent() << "@Override" << endl << indent() << "public boolean equals(java.lang.Object that) {" << endl; indent_up(); out << indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl << indent() << " return this.equals((" << tstruct->get_name() << ")that);" << endl << indent() << "return false;" << endl; scope_down(out); out << endl; out << indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl; indent_up(); out << indent() << "if (that == null)" << endl << indent() << " return false;" << endl << indent() << "if (this == that)" << endl << indent() << " return true;" << endl; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << endl; t_type* t = get_true_type((*m_iter)->get_type()); // Most existing Thrift code does not use isset or optional/required, // so we treat "default" fields as required. bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; bool can_be_null = type_can_be_null(t); string name = (*m_iter)->get_name(); string this_present = "true"; string that_present = "true"; string unequal; if (is_optional || can_be_null) { this_present += " && this." + generate_isset_check(*m_iter); that_present += " && that." + generate_isset_check(*m_iter); } out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl << indent() << "if (" << "this_present_" << name << " || that_present_" << name << ") {" << endl; indent_up(); out << indent() << "if (!(" << "this_present_" << name << " && that_present_" << name << "))" << endl << indent() << " return false;" << endl; if (t->is_binary()) { unequal = "!this." + name + ".equals(that." + name + ")"; } else if (can_be_null) { unequal = "!this." + name + ".equals(that." + name + ")"; } else { unequal = "this." + name + " != that." + name; } out << indent() << "if (" << unequal << ")" << endl << indent() << " return false;" << endl; scope_down(out); } out << endl; indent(out) << "return true;" << endl; scope_down(out); out << endl; const int MUL = 8191; // HashCode multiplier const int B_YES = 131071; const int B_NO = 524287; out << indent() << "@Override" << endl << indent() << "public int hashCode() {" << endl; indent_up(); indent(out) << "int hashCode = 1;" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << endl; t_type* t = get_true_type((*m_iter)->get_type()); bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; bool can_be_null = type_can_be_null(t); string name = (*m_iter)->get_name(); if (is_optional || can_be_null) { indent(out) << "hashCode = hashCode * " << MUL << " + ((" << generate_isset_check(*m_iter) << ") ? " << B_YES << " : " << B_NO << ");" << endl; } if (is_optional || can_be_null) { indent(out) << "if (" + generate_isset_check(*m_iter) + ")" << endl; indent_up(); } if (t->is_enum()) { indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".getValue();" << endl; } else if (t->is_base_type()) { switch(((t_base_type*)t)->get_base()) { case t_base_type::TYPE_STRING: indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl; break; case t_base_type::TYPE_BOOL: indent(out) << "hashCode = hashCode * " << MUL << " + ((" << name << ") ? " << B_YES << " : " << B_NO << ");" << endl; break; case t_base_type::TYPE_I8: indent(out) << "hashCode = hashCode * " << MUL << " + (int) (" << name << ");" << endl; break; case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ";" << endl; break; case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: indent(out) << "hashCode = hashCode * " << MUL << " + org.apache.thrift.TBaseHelper.hashCode(" << name << ");" << endl; break; case t_base_type::TYPE_VOID: throw std::logic_error("compiler error: a struct field cannot be void"); default: throw std::logic_error("compiler error: the following base type has no hashcode generator: " + t_base_type::t_base_name(((t_base_type*)t)->get_base())); } } else { indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl; } if (is_optional || can_be_null) { indent_down(); } } out << endl; indent(out) << "return hashCode;" << endl; indent_down(); indent(out) << "}" << endl << endl; } void t_java_generator::generate_java_struct_compare_to(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; indent_up(); indent(out) << "if (!getClass().equals(other.getClass())) {" << endl; indent(out) << " return getClass().getName().compareTo(other.getClass().getName());" << endl; indent(out) << "}" << endl; out << endl; indent(out) << "int lastComparison = 0;" << endl; out << endl; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = *m_iter; indent(out) << "lastComparison = java.lang.Boolean.compare(" << generate_isset_check(field) << ", other." << generate_isset_check(field) << ");" << endl; indent(out) << "if (lastComparison != 0) {" << endl; indent(out) << " return lastComparison;" << endl; indent(out) << "}" << endl; indent(out) << "if (" << generate_isset_check(field) << ") {" << endl; indent(out) << " lastComparison = org.apache.thrift.TBaseHelper.compareTo(this." << field->get_name() << ", other." << field->get_name() << ");" << endl; indent(out) << " if (lastComparison != 0) {" << endl; indent(out) << " return lastComparison;" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl; } indent(out) << "return 0;" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a function to read all the fields of the struct. * * @param tstruct The struct definition */ void t_java_generator::generate_java_struct_reader(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "public void read(org.apache.thrift.protocol.TProtocol iprot) throws " "org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "scheme(iprot).read(iprot, this);" << endl; indent_down(); indent(out) << "}" << endl << endl; } // generates java method to perform various checks // (e.g. check that all required fields are set) void t_java_generator::generate_java_validator(ostream& out, t_struct* tstruct) { indent(out) << "public void validate() throws org.apache.thrift.TException {" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; out << indent() << "// check for required fields" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { if (bean_style_) { out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl << indent() << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl << indent() << "}" << endl << endl; } else { if (type_can_be_null((*f_iter)->get_type())) { indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl; indent(out) << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl; indent(out) << "}" << endl; } else { indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() << "' because it's a primitive and you chose the non-beans generator." << endl; } } } } out << indent() << "// check for sub-struct validity" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_type* type = (*f_iter)->get_type(); if (type->is_struct() && !((t_struct*)type)->is_union()) { out << indent() << "if (" << (*f_iter)->get_name() << " != null) {" << endl; out << indent() << " " << (*f_iter)->get_name() << ".validate();" << endl; out << indent() << "}" << endl; } } indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a function to write all the fields of the struct * * @param tstruct The struct definition */ void t_java_generator::generate_java_struct_writer(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws " "org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "scheme(oprot).write(oprot, this);" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a function to write all the fields of the struct, * which is a function result. These fields are only written * if they are set in the Isset array, and only one of them * can be set at a time. * * @param tstruct The struct definition */ void t_java_generator::generate_java_struct_result_writer(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws " "org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "scheme(oprot).write(oprot, this);" << endl; indent_down(); indent(out) << " }" << endl << endl; } void t_java_generator::generate_java_struct_field_by_id(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << java_nullable_annotation() << endl; indent(out) << "public _Fields fieldForId(int fieldId) {" << endl; indent(out) << " return _Fields.findByThriftId(fieldId);" << endl; indent(out) << "}" << endl << endl; } void t_java_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) { indent(out) << "case " << constant_name(field_name) << ":" << endl; indent_up(); indent(out) << "return " << (type->is_bool() ? "is" : "get") << cap_name << "();" << endl << endl; indent_down(); } void t_java_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) { const bool is_binary = type->is_binary(); indent(out) << "case " << constant_name(field_name) << ":" << endl; indent_up(); indent(out) << "if (value == null) {" << endl; indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; indent(out) << "} else {" << endl; if (is_binary) { indent_up(); indent(out) << "if (value instanceof byte[]) {" << endl; indent(out) << " set" << cap_name << "((byte[])value);" << endl; indent(out) << "} else {" << endl; } indent(out) << " set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl; if (is_binary) { indent(out) << "}" << endl; indent_down(); } indent(out) << "}" << endl; indent(out) << "break;" << endl << endl; indent_down(); } void t_java_generator::generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct) { std::ostringstream getter_stream; std::ostringstream setter_stream; // build up the bodies of both the getter and setter at once const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; t_type* type = get_true_type(field->get_type()); std::string field_name = field->get_name(); std::string cap_name = get_cap_name(field_name); indent_up(); generate_reflection_setters(setter_stream, type, field_name, cap_name); generate_reflection_getters(getter_stream, type, field_name, cap_name); indent_down(); } // create the setter indent(out) << "public void setFieldValue(_Fields field, " << java_nullable_annotation() << " java.lang.Object value) {" << endl; indent(out) << " switch (field) {" << endl; out << setter_stream.str(); indent(out) << " }" << endl; indent(out) << "}" << endl << endl; // create the getter indent(out) << java_nullable_annotation() << endl; indent(out) << "public java.lang.Object getFieldValue(_Fields field) {" << endl; indent_up(); indent(out) << "switch (field) {" << endl; out << getter_stream.str(); indent(out) << "}" << endl; indent(out) << "throw new java.lang.IllegalStateException();" << endl; indent_down(); indent(out) << "}" << endl << endl; } // Creates a generic isSet method that takes the field number as argument void t_java_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // create the isSet method indent(out) << "/** Returns true if field corresponding to fieldID is set (has been assigned a " "value) and false otherwise */" << endl; indent(out) << "public boolean isSet(_Fields field) {" << endl; indent_up(); indent(out) << "if (field == null) {" << endl; indent(out) << " throw new java.lang.IllegalArgumentException();" << endl; indent(out) << "}" << endl << endl; indent(out) << "switch (field) {" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent_up(); indent(out) << "return " << generate_isset_check(field) << ";" << endl; indent_down(); } indent(out) << "}" << endl; indent(out) << "throw new java.lang.IllegalStateException();" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a set of Java Bean boilerplate functions (setters, getters, etc.) * for the given struct. * * @param tstruct The struct definition */ void t_java_generator::generate_java_bean_boilerplate(ostream& out, t_struct* tstruct) { isset_type issetType = needs_isset(tstruct); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; t_type* type = get_true_type(field->get_type()); std::string field_name = field->get_name(); std::string cap_name = get_cap_name(field_name); bool optional = use_option_type_ && field->get_req() == t_field::T_OPTIONAL; bool is_deprecated = this->is_deprecated(field->annotations_); if (type->is_container()) { // Method to return the size of the collection if (optional) { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public org.apache.thrift.Option get" << cap_name; out << get_cap_name("size() {") << endl; indent_up(); indent(out) << "if (this." << field_name << " == null) {" << endl; indent_up(); indent(out) << "return org.apache.thrift.Option.none();" << endl; indent_down(); indent(out) << "} else {" << endl; indent_up(); indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ".size());" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl << endl; } else { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public int get" << cap_name; out << get_cap_name("size() {") << endl; indent_up(); indent(out) << "return (this." << field_name << " == null) ? 0 : " << "this." << field_name << ".size();" << endl; indent_down(); indent(out) << "}" << endl << endl; } } if (type->is_set() || type->is_list()) { t_type* element_type; if (type->is_set()) { element_type = ((t_set*)type)->get_elem_type(); } else { element_type = ((t_list*)type)->get_elem_type(); } // Iterator getter for sets and lists if (optional) { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public org.apache.thrift.Option> get" << cap_name; out << get_cap_name("iterator() {") << endl; indent_up(); indent(out) << "if (this." << field_name << " == null) {" << endl; indent_up(); indent(out) << "return org.apache.thrift.Option.none();" << endl; indent_down(); indent(out) << "} else {" << endl; indent_up(); indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ".iterator());" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl << endl; } else { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << java_nullable_annotation() << endl; indent(out) << "public java.util.Iterator<" << type_name(element_type, true, false) << "> get" << cap_name; out << get_cap_name("iterator() {") << endl; indent_up(); indent(out) << "return (this." << field_name << " == null) ? null : " << "this." << field_name << ".iterator();" << endl; indent_down(); indent(out) << "}" << endl << endl; } // Add to set or list, create if the set/list is null if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public void add" << get_cap_name("to"); out << cap_name << "(" << type_name(element_type) << " elem) {" << endl; indent_up(); indent(out) << "if (this." << field_name << " == null) {" << endl; indent_up(); indent(out) << "this." << field_name; if (is_enum_set(type)) { out << " = " << type_name(type, false, true, true) << ".noneOf(" << inner_enum_type_name(type) << ");" << endl; } else { out << " = new " << type_name(type, false, true) << "();" << endl; } indent_down(); indent(out) << "}" << endl; indent(out) << "this." << field_name << ".add(elem);" << endl; indent_down(); indent(out) << "}" << endl << endl; } else if (type->is_map()) { // Put to map t_type* key_type = ((t_map*)type)->get_key_type(); t_type* val_type = ((t_map*)type)->get_val_type(); if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public void put" << get_cap_name("to"); out << cap_name << "(" << type_name(key_type) << " key, " << type_name(val_type) << " val) {" << endl; indent_up(); indent(out) << "if (this." << field_name << " == null) {" << endl; indent_up(); std::string constructor_args; if (is_enum_map(type)) { constructor_args = inner_enum_type_name(type); } indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "(" << constructor_args << ");" << endl; indent_down(); indent(out) << "}" << endl; indent(out) << "this." << field_name << ".put(key, val);" << endl; indent_down(); indent(out) << "}" << endl << endl; } // Simple getter generate_java_doc(out, field); if (type->is_binary()) { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public byte[] get" << cap_name << "() {" << endl; indent(out) << " set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(" << field_name << "));" << endl; indent(out) << " return " << field_name << " == null ? null : " << field_name << ".array();" << endl; indent(out) << "}" << endl << endl; indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for") << cap_name << "() {" << endl; if(unsafe_binaries_){ indent(out) << " return " << field_name << ";" << endl; }else { indent(out) << " return org.apache.thrift.TBaseHelper.copyBinary(" << field_name << ");" << endl; } indent(out) << "}" << endl << endl; } else { if (optional) { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public org.apache.thrift.Option<" << type_name(type, true) << ">"; if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) { out << " is"; } else { out << " get"; } out << cap_name << "() {" << endl; indent_up(); indent(out) << "if (this.isSet" << cap_name << "()) {" << endl; indent_up(); indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ");" << endl; indent_down(); indent(out) << "} else {" << endl; indent_up(); indent(out) << "return org.apache.thrift.Option.none();" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl << endl; } else { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } if (type_can_be_null(type)) { indent(out) << java_nullable_annotation() << endl; } indent(out) << "public " << type_name(type); if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) { out << " is"; } else { out << " get"; } out << cap_name << "() {" << endl; indent_up(); indent(out) << "return this." << field_name << ";" << endl; indent_down(); indent(out) << "}" << endl << endl; } } // Simple setter generate_java_doc(out, field); if (type->is_binary()) { if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public "; if (bean_style_) { out << "void"; } else { out << type_name(tstruct); } out << " set" << cap_name << "(byte[] " << field_name << ") {" << endl; indent(out) << " this." << field_name << " = " << field_name << " == null ? (java.nio.ByteBuffer)null"; if(unsafe_binaries_){ indent(out) << " : java.nio.ByteBuffer.wrap(" << field_name << ");" << endl; }else{ indent(out) << " : java.nio.ByteBuffer.wrap(" << field_name << ".clone());" << endl; } if (!bean_style_) { indent(out) << " return this;" << endl; } indent(out) << "}" << endl << endl; } if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public "; if (bean_style_) { out << "void"; } else { out << type_name(tstruct); } out << " set" << cap_name << "(" << (type_can_be_null(type) ? (java_nullable_annotation() + " ") : "") << type_name(type) << " " << field_name << ") {" << endl; indent_up(); indent(out) << "this." << field_name << " = "; if (type->is_binary() && !unsafe_binaries_) { out << "org.apache.thrift.TBaseHelper.copyBinary(" << field_name << ")"; } else { out << field_name; } out << ";" << endl; generate_isset_set(out, field, ""); if (!bean_style_) { indent(out) << "return this;" << endl; } indent_down(); indent(out) << "}" << endl << endl; // Unsetter if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public void unset" << cap_name << "() {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "this." << field_name << " = null;" << endl; } else if (issetType == ISSET_PRIMITIVE) { indent(out) << "__isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, " << isset_field_id(field) << ");" << endl; } else { indent(out) << "__isset_bit_vector.clear(" << isset_field_id(field) << ");" << endl; } indent_down(); indent(out) << "}" << endl << endl; // isSet method indent(out) << "/** Returns true if field " << field_name << " is set (has been assigned a value) and false otherwise */" << endl; if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "return this." << field_name << " != null;" << endl; } else if (issetType == ISSET_PRIMITIVE) { indent(out) << "return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, " << isset_field_id(field) << ");" << endl; } else { indent(out) << "return __isset_bit_vector.get(" << isset_field_id(field) << ");" << endl; } indent_down(); indent(out) << "}" << endl << endl; if (is_deprecated) { indent(out) << "@Deprecated" << endl; } indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "if (!value) {" << endl; indent(out) << " this." << field_name << " = null;" << endl; indent(out) << "}" << endl; } else if (issetType == ISSET_PRIMITIVE) { indent(out) << "__isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, " << isset_field_id(field) << ", value);" << endl; } else { indent(out) << "__isset_bit_vector.set(" << isset_field_id(field) << ", value);" << endl; } indent_down(); indent(out) << "}" << endl << endl; } } /** * Generates a toString() method for the given struct * * @param tstruct The struct definition */ void t_java_generator::generate_java_struct_tostring(ostream& out, t_struct* tstruct) { out << indent() << "@Override" << endl << indent() << "public java.lang.String toString() {" << endl; indent_up(); out << indent() << "java.lang.StringBuilder sb = new java.lang.StringBuilder(\"" << tstruct->get_name() << "(\");" << endl; out << indent() << "boolean first = true;" << endl << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; if (could_be_unset) { indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; indent_up(); } t_field* field = (*f_iter); if (!first) { indent(out) << "if (!first) sb.append(\", \");" << endl; } indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl; bool can_be_null = type_can_be_null(field->get_type()); if (can_be_null) { indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; indent(out) << " sb.append(\"null\");" << endl; indent(out) << "} else {" << endl; indent_up(); } if (get_true_type(field->get_type())->is_binary()) { indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl; } else if ((field->get_type()->is_set()) && (get_true_type(((t_set*)field->get_type())->get_elem_type())->is_binary())) { indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl; } else if ((field->get_type()->is_list()) && (get_true_type(((t_list*)field->get_type())->get_elem_type())->is_binary())) { indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl; } else { indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl; } if (can_be_null) { indent_down(); indent(out) << "}" << endl; } indent(out) << "first = false;" << endl; if (could_be_unset) { indent_down(); indent(out) << "}" << endl; } first = false; } out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a static map with meta data to store information such as fieldID to * fieldName mapping * * @param tstruct The struct definition */ void t_java_generator::generate_java_meta_data_map(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // Static Map with fieldID -> org.apache.thrift.meta_data.FieldMetaData mappings indent(out) << "public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;" << endl; indent(out) << "static {" << endl; indent_up(); indent(out) << "java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new " "java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);" << endl; // Populate map for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; std::string field_name = field->get_name(); indent(out) << "tmpMap.put(_Fields." << constant_name(field_name) << ", new org.apache.thrift.meta_data.FieldMetaData(\"" << field_name << "\", "; // Set field requirement type (required, optional, etc.) if (field->get_req() == t_field::T_REQUIRED) { out << "org.apache.thrift.TFieldRequirementType.REQUIRED, "; } else if (field->get_req() == t_field::T_OPTIONAL) { out << "org.apache.thrift.TFieldRequirementType.OPTIONAL, "; } else { out << "org.apache.thrift.TFieldRequirementType.DEFAULT, "; } // Create value meta data generate_field_value_meta_data(out, field->get_type()); out << "));" << endl; } indent(out) << "metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);" << endl; indent(out) << "org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ".class, metaDataMap);" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Returns a string with the java representation of the given thrift type * (e.g. for the type struct it returns "org.apache.thrift.protocol.TType.STRUCT") */ std::string t_java_generator::get_java_type_string(t_type* type) { if (type->is_list()) { return "org.apache.thrift.protocol.TType.LIST"; } else if (type->is_map()) { return "org.apache.thrift.protocol.TType.MAP"; } else if (type->is_set()) { return "org.apache.thrift.protocol.TType.SET"; } else if (type->is_struct() || type->is_xception()) { return "org.apache.thrift.protocol.TType.STRUCT"; } else if (type->is_enum()) { return "org.apache.thrift.protocol.TType.ENUM"; } else if (type->is_typedef()) { return get_java_type_string(((t_typedef*)type)->get_type()); } else if (type->is_base_type()) { switch (((t_base_type*)type)->get_base()) { case t_base_type::TYPE_VOID: return "org.apache.thrift.protocol.TType.VOID"; break; case t_base_type::TYPE_STRING: return "org.apache.thrift.protocol.TType.STRING"; break; case t_base_type::TYPE_BOOL: return "org.apache.thrift.protocol.TType.BOOL"; break; case t_base_type::TYPE_I8: return "org.apache.thrift.protocol.TType.BYTE"; break; case t_base_type::TYPE_I16: return "org.apache.thrift.protocol.TType.I16"; break; case t_base_type::TYPE_I32: return "org.apache.thrift.protocol.TType.I32"; break; case t_base_type::TYPE_I64: return "org.apache.thrift.protocol.TType.I64"; break; case t_base_type::TYPE_DOUBLE: return "org.apache.thrift.protocol.TType.DOUBLE"; break; default: throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_java_generator::get_java_type_string!"); return "Unknown thrift type \"" + type->get_name() + "\" passed to t_java_generator::get_java_type_string!"; break; // This should never happen! } } else { throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_java_generator::get_java_type_string!"); // This should never happen! } } void t_java_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) { out << endl; indent_up(); indent_up(); if (type->is_struct() || type->is_xception()) { indent(out) << "new " "org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType." "STRUCT, " << type_name(type) << ".class"; } else if (type->is_container()) { if (type->is_list()) { indent(out) << "new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, "; t_type* elem_type = ((t_list*)type)->get_elem_type(); generate_field_value_meta_data(out, elem_type); } else if (type->is_set()) { indent(out) << "new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, "; t_type* elem_type = ((t_set*)type)->get_elem_type(); generate_field_value_meta_data(out, elem_type); } else { // map indent(out) << "new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, "; t_type* key_type = ((t_map*)type)->get_key_type(); t_type* val_type = ((t_map*)type)->get_val_type(); generate_field_value_meta_data(out, key_type); out << ", "; generate_field_value_meta_data(out, val_type); } } else if (type->is_enum()) { indent(out) << "new org.apache.thrift.meta_data.EnumMetaData(org.apache.thrift.protocol.TType.ENUM, " << type_name(type) << ".class"; } else { indent(out) << "new org.apache.thrift.meta_data.FieldValueMetaData(" << get_java_type_string(type); if (type->is_typedef()) { indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\""; } else if (type->is_binary()) { indent(out) << ", true"; } } out << ")"; indent_down(); indent_down(); } /** * Generates a thrift service. In C++, this comprises an entirely separate * header and source file. The header file defines the methods and includes * the data types defined in the main header file, and the implementation * file contains implementations of the basic printer and default interfaces. * * @param tservice The service definition */ void t_java_generator::generate_service(t_service* tservice) { // Make output file string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + ".java"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << java_package() << java_suppressions(); if (!suppress_generated_annotations_) { generate_javax_generated_annotation(f_service_); } f_service_ << "public class " << service_name_ << " {" << endl << endl; indent_up(); // Generate the three main parts of the service generate_service_interface(tservice); generate_service_async_interface(tservice); generate_service_client(tservice); generate_service_async_client(tservice); generate_service_server(tservice); generate_service_async_server(tservice); generate_service_helpers(tservice); indent_down(); f_service_ << "}" << endl; f_service_.close(); } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_java_generator::generate_service_interface(t_service* tservice) { string extends = ""; string extends_iface = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_iface = " extends " + extends + ".Iface"; } generate_java_doc(f_service_, tservice); f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_java_doc(f_service_, *f_iter); indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl; } indent_down(); f_service_ << indent() << "}" << endl << endl; } void t_java_generator::generate_service_async_interface(t_service* tservice) { string extends = ""; string extends_iface = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_iface = " extends " + extends + " .AsyncIface"; } f_service_ << indent() << "public interface AsyncIface" << extends_iface << " {" << endl << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_service_) << "public " << function_signature_async(*f_iter, true) << " throws org.apache.thrift.TException;" << endl << endl; } indent_down(); f_service_ << indent() << "}" << endl << endl; } /** * Generates structs for all the service args and return types * * @param tservice The service */ void t_java_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_java_struct_definition(f_service_, ts, false, true); generate_function_helpers(*f_iter); } } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_java_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = ""; if (tservice->get_extends() == nullptr) { extends_client = "org.apache.thrift.TServiceClient"; } else { extends = type_name(tservice->get_extends()); extends_client = extends + ".Client"; } indent(f_service_) << "public static class Client extends " << extends_client << " implements Iface {" << endl; indent_up(); indent(f_service_) << "public static class Factory implements org.apache.thrift.TServiceClientFactory {" << endl; indent_up(); indent(f_service_) << "public Factory() {}" << endl; indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol prot) {" << endl; indent_up(); indent(f_service_) << "return new Client(prot);" << endl; indent_down(); indent(f_service_) << "}" << endl; indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol iprot, " "org.apache.thrift.protocol.TProtocol oprot) {" << endl; indent_up(); indent(f_service_) << "return new Client(iprot, oprot);" << endl; indent_down(); indent(f_service_) << "}" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol prot)" << endl; scope_up(f_service_); indent(f_service_) << "super(prot, prot);" << endl; scope_down(f_service_); f_service_ << endl; indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol iprot, " "org.apache.thrift.protocol.TProtocol oprot) {" << endl; indent(f_service_) << " super(iprot, oprot);" << endl; indent(f_service_) << "}" << endl << endl; // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); string sep = "_"; string javaname = funname; if (fullcamel_style_) { sep = ""; javaname = as_camel_case(funname); } // Open function indent(f_service_) << "public " << function_signature(*f_iter) << endl; scope_up(f_service_); indent(f_service_) << "send" << sep << javaname << "("; // Get the struct of function call params t_struct* arg_struct = (*f_iter)->get_arglist(); // Declare the function arguments const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; bool first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << (*fld_iter)->get_name(); } f_service_ << ");" << endl; if (!(*f_iter)->is_oneway()) { f_service_ << indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << "return "; } f_service_ << "recv" << sep << javaname << "();" << endl; } scope_down(f_service_); f_service_ << endl; t_function send_function(g_type_void, string("send") + sep + javaname, (*f_iter)->get_arglist()); string argsname = (*f_iter)->get_name() + "_args"; // Open function indent(f_service_) << "public " << function_signature(&send_function) << endl; scope_up(f_service_); // Serialize the request indent(f_service_) << argsname << " args = new " << argsname << "();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { indent(f_service_) << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" << (*fld_iter)->get_name() << ");" << endl; } const string sendBaseName = (*f_iter)->is_oneway() ? "sendBaseOneway" : "sendBase"; indent(f_service_) << sendBaseName << "(\"" << funname << "\", args);" << endl; scope_down(f_service_); f_service_ << endl; if (!(*f_iter)->is_oneway()) { string resultname = (*f_iter)->get_name() + "_result"; t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv") + sep + javaname, &noargs, (*f_iter)->get_xceptions()); // Open function indent(f_service_) << "public " << function_signature(&recv_function) << endl; scope_up(f_service_); f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl << indent() << "receiveBase(result, \"" << funname << "\");" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl << indent() << " return result.success;" << endl << indent() << "}" << endl; } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl << indent() << " throw result." << (*x_iter)->get_name() << ";" << endl << indent() << "}" << endl; } // If you get here it's an exception, unless a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "return;" << endl; } else { f_service_ << indent() << "throw new " "org.apache.thrift.TApplicationException(org.apache.thrift." "TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; } // Close function scope_down(f_service_); f_service_ << endl; } } indent_down(); indent(f_service_) << "}" << endl; } void t_java_generator::generate_service_async_client(t_service* tservice) { string extends = "org.apache.thrift.async.TAsyncClient"; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()) + ".AsyncClient"; } indent(f_service_) << "public static class AsyncClient extends " << extends << " implements AsyncIface {" << endl; indent_up(); // Factory method indent(f_service_) << "public static class Factory implements " "org.apache.thrift.async.TAsyncClientFactory {" << endl; indent(f_service_) << " private org.apache.thrift.async.TAsyncClientManager clientManager;" << endl; indent(f_service_) << " private org.apache.thrift.protocol.TProtocolFactory protocolFactory;" << endl; indent(f_service_) << " public Factory(org.apache.thrift.async.TAsyncClientManager " "clientManager, org.apache.thrift.protocol.TProtocolFactory " "protocolFactory) {" << endl; indent(f_service_) << " this.clientManager = clientManager;" << endl; indent(f_service_) << " this.protocolFactory = protocolFactory;" << endl; indent(f_service_) << " }" << endl; indent(f_service_) << " public AsyncClient " "getAsyncClient(org.apache.thrift.transport.TNonblockingTransport " "transport) {" << endl; indent(f_service_) << " return new AsyncClient(protocolFactory, clientManager, transport);" << endl; indent(f_service_) << " }" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public AsyncClient(org.apache.thrift.protocol.TProtocolFactory " "protocolFactory, org.apache.thrift.async.TAsyncClientManager " "clientManager, org.apache.thrift.transport.TNonblockingTransport " "transport) {" << endl; indent(f_service_) << " super(protocolFactory, clientManager, transport);" << endl; indent(f_service_) << "}" << endl << endl; // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); string sep = "_"; string javaname = funname; if (fullcamel_style_) { sep = ""; javaname = as_camel_case(javaname); } t_type* ret_type = (*f_iter)->get_returntype(); t_struct* arg_struct = (*f_iter)->get_arglist(); string funclassname = funname + "_call"; const vector& fields = arg_struct->get_members(); const std::vector& xceptions = (*f_iter)->get_xceptions()->get_members(); vector::const_iterator fld_iter; string args_name = (*f_iter)->get_name() + "_args"; string result_name = (*f_iter)->get_name() + "_result"; // Main method body indent(f_service_) << "public " << function_signature_async(*f_iter, false) << " throws org.apache.thrift.TException {" << endl; indent(f_service_) << " checkReady();" << endl; indent(f_service_) << " " << funclassname << " method_call = new " + funclassname + "(" << async_argument_list(*f_iter, arg_struct, ret_type) << ", this, ___protocolFactory, ___transport);" << endl; indent(f_service_) << " this.___currentMethod = method_call;" << endl; indent(f_service_) << " ___manager.call(method_call);" << endl; indent(f_service_) << "}" << endl; f_service_ << endl; // TAsyncMethod object for this function call indent(f_service_) << "public static class " + funclassname + " extends org.apache.thrift.async.TAsyncMethodCall<" + type_name((*f_iter)->get_returntype(), true) + "> {" << endl; indent_up(); // Member variables for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { indent(f_service_) << "private " + type_name((*fld_iter)->get_type()) + " " + (*fld_iter)->get_name() + ";" << endl; } // NOTE since we use a new Client instance to deserialize, let's keep seqid to 0 for now // indent(f_service_) << "private int seqid;" << endl << endl; // Constructor indent(f_service_) << "public " + funclassname + "(" + async_argument_list(*f_iter, arg_struct, ret_type, true) << ", org.apache.thrift.async.TAsyncClient client, " "org.apache.thrift.protocol.TProtocolFactory protocolFactory, " "org.apache.thrift.transport.TNonblockingTransport transport) throws " "org.apache.thrift.TException {" << endl; indent(f_service_) << " super(client, protocolFactory, transport, resultHandler, " << ((*f_iter)->is_oneway() ? "true" : "false") << ");" << endl; // Assign member variables for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { indent(f_service_) << " this." + (*fld_iter)->get_name() + " = " + (*fld_iter)->get_name() + ";" << endl; } indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public void write_args(org.apache.thrift.protocol.TProtocol prot) " "throws org.apache.thrift.TException {" << endl; indent_up(); // Serialize request // NOTE we are leaving seqid as 0, for now (see above) f_service_ << indent() << "prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage(\"" << funname << "\", org.apache.thrift.protocol." << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") << ", 0));" << endl << indent() << args_name << " args = new " << args_name << "();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" << (*fld_iter)->get_name() << ");" << endl; } f_service_ << indent() << "args.write(prot);" << endl << indent() << "prot.writeMessageEnd();" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; // Return method indent(f_service_) << "public " + type_name(ret_type, true) + " getResult() throws "; vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << type_name((*x_iter)->get_type(), false, false) + ", "; } f_service_ << "org.apache.thrift.TException {" << endl; indent_up(); f_service_ << indent() << "if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {" << endl << indent() << " throw new java.lang.IllegalStateException(\"Method call not finished!\");" << endl << indent() << "}" << endl << indent() << "org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new " "org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());" << endl << indent() << "org.apache.thrift.protocol.TProtocol prot = " "client.getProtocolFactory().getProtocol(memoryTransport);" << endl; indent(f_service_); if (ret_type->is_void()) { // NB: Includes oneways which always return void. f_service_ << "return null;" << endl; } else { f_service_ << "return (new Client(prot)).recv" + sep + javaname + "();" << endl; } // Close function indent_down(); indent(f_service_) << "}" << endl; // Close class indent_down(); indent(f_service_) << "}" << endl << endl; } // Close AsyncClient scope_down(f_service_); f_service_ << endl; } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_java_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; // Extends stuff string extends = ""; string extends_processor = ""; if (tservice->get_extends() == nullptr) { extends_processor = "org.apache.thrift.TBaseProcessor"; } else { extends = type_name(tservice->get_extends()); extends_processor = extends + ".Processor"; } // Generate the header portion indent(f_service_) << "public static class Processor extends " << extends_processor << " implements org.apache.thrift.TProcessor {" << endl; indent_up(); indent(f_service_) << "private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(Processor.class.getName());" << endl; indent(f_service_) << "public Processor(I iface) {" << endl; indent(f_service_) << " super(iface, getProcessMap(new java.util.HashMap>()));" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "protected Processor(I iface, java.util.Map> " "processMap) {" << endl; indent(f_service_) << " super(iface, getProcessMap(processMap));" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "private static java.util.Map> " "getProcessMap(java.util.Map> processMap) {" << endl; indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl; } indent(f_service_) << "return processMap;" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } indent_down(); indent(f_service_) << "}" << endl << endl; } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_java_generator::generate_service_async_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; // Extends stuff string extends = ""; string extends_processor = ""; if (tservice->get_extends() == nullptr) { extends_processor = "org.apache.thrift.TBaseAsyncProcessor"; } else { extends = type_name(tservice->get_extends()); extends_processor = extends + ".AsyncProcessor"; } // Generate the header portion indent(f_service_) << "public static class AsyncProcessor extends " << extends_processor << " {" << endl; indent_up(); indent(f_service_) << "private static final org.slf4j.Logger _LOGGER = " "org.slf4j.LoggerFactory.getLogger(AsyncProcessor.class.getName());" << endl; indent(f_service_) << "public AsyncProcessor(I iface) {" << endl; indent(f_service_) << " super(iface, getProcessMap(new java.util.HashMap>()));" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "protected AsyncProcessor(I iface, java.util.Map> processMap) {" << endl; indent(f_service_) << " super(iface, getProcessMap(processMap));" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "private static java.util.Map> getProcessMap(java.util.Map> processMap) {" << endl; indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl; } indent(f_service_) << "return processMap;" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_async_function(tservice, *f_iter); } indent_down(); indent(f_service_) << "}" << endl << endl; } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_java_generator::generate_function_helpers(t_function* tfunction) { if (tfunction->is_oneway()) { return; } t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_java_struct_definition(f_service_, &result, false, true, true); } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_java_generator::generate_process_async_function(t_service* tservice, t_function* tfunction) { string argsname = tfunction->get_name() + "_args"; string resultname = tfunction->get_name() + "_result"; if (tfunction->is_oneway()) { resultname = "org.apache.thrift.TBase"; } string resulttype = type_name(tfunction->get_returntype(), true); (void)tservice; // Open class indent(f_service_) << "public static class " << tfunction->get_name() << " extends org.apache.thrift.AsyncProcessFunction {" << endl; indent_up(); indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl; indent(f_service_) << " super(\"" << tfunction->get_name() << "\");" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl; indent(f_service_) << " return new " << argsname << "();" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public org.apache.thrift.async.AsyncMethodCallback<" << resulttype << "> getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) {" << endl; indent_up(); indent(f_service_) << "final org.apache.thrift.AsyncProcessFunction fcall = this;" << endl; indent(f_service_) << "return new org.apache.thrift.async.AsyncMethodCallback<" << resulttype << ">() { " << endl; indent_up(); indent(f_service_) << "public void onComplete(" << resulttype << " o) {" << endl; indent_up(); if (!tfunction->is_oneway()) { indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; if (!tfunction->get_returntype()->is_void()) { indent(f_service_) << "result.success = o;" << endl; // Set isset on success field if (!type_can_be_null(tfunction->get_returntype())) { indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl; } } indent(f_service_) << "try {" << endl; indent(f_service_) << " fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);" << endl; indent(f_service_) << "} catch (org.apache.thrift.transport.TTransportException e) {" << endl; indent_up(); f_service_ << indent() << "_LOGGER.error(\"TTransportException writing to internal frame buffer\", e);" << endl << indent() << "fb.close();" << endl; indent_down(); indent(f_service_) << "} catch (java.lang.Exception e) {" << endl; indent_up(); f_service_ << indent() << "_LOGGER.error(\"Exception writing to internal frame buffer\", e);" << endl << indent() << "onError(e);" << endl; indent_down(); indent(f_service_) << "}" << endl; } indent_down(); indent(f_service_) << "}" << endl; indent(f_service_) << "public void onError(java.lang.Exception e) {" << endl; indent_up(); if (tfunction->is_oneway()) { indent(f_service_) << "if (e instanceof org.apache.thrift.transport.TTransportException) {" << endl; indent_up(); f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl << indent() << "fb.close();" << endl; indent_down(); indent(f_service_) << "} else {" << endl; indent_up(); f_service_ << indent() << "_LOGGER.error(\"Exception inside oneway handler\", e);" << endl; indent_down(); indent(f_service_) << "}" << endl; } else { indent(f_service_) << "byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;" << endl; indent(f_service_) << "org.apache.thrift.TSerializable msg;" << endl; indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; if (xceptions.size() > 0) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { if (x_iter == xceptions.begin()) f_service_ << indent(); string type = type_name((*x_iter)->get_type(), false, false); string name = (*x_iter)->get_name(); f_service_ << "if (e instanceof " << type << ") {" << endl; indent_up(); f_service_ << indent() << "result." << name << " = (" << type << ") e;" << endl << indent() << "result.set" << get_cap_name(name) << get_cap_name("isSet") << "(true);" << endl << indent() << "msg = result;" << endl; indent_down(); indent(f_service_) << "} else "; } } else { indent(f_service_); } f_service_ << "if (e instanceof org.apache.thrift.transport.TTransportException) {" << endl; indent_up(); f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl << indent() << "fb.close();" << endl << indent() << "return;" << endl; indent_down(); indent(f_service_) << "} else if (e instanceof org.apache.thrift.TApplicationException) {" << endl; indent_up(); f_service_ << indent() << "_LOGGER.error(\"TApplicationException inside handler\", e);" << endl << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl << indent() << "msg = (org.apache.thrift.TApplicationException)e;" << endl; indent_down(); indent(f_service_) << "} else {" << endl; indent_up(); f_service_ << indent() << "_LOGGER.error(\"Exception inside handler\", e);" << endl << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl << indent() << "msg = new " "org.apache.thrift.TApplicationException(org.apache.thrift." "TApplicationException.INTERNAL_ERROR, e.getMessage());" << endl; indent_down(); f_service_ << indent() << "}" << endl << indent() << "try {" << endl << indent() << " fcall.sendResponse(fb,msg,msgType,seqid);" << endl << indent() << "} catch (java.lang.Exception ex) {" << endl << indent() << " _LOGGER.error(\"Exception writing to internal frame buffer\", ex);" << endl << indent() << " fb.close();" << endl << indent() << "}" << endl; } indent_down(); indent(f_service_) << "}" << endl; indent_down(); indent(f_service_) << "};" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; indent(f_service_) << "protected boolean isOneway() {" << endl; indent(f_service_) << " return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public void start(I iface, " << argsname << " args, org.apache.thrift.async.AsyncMethodCallback<" << resulttype << "> resultHandler) throws org.apache.thrift.TException {" << endl; indent_up(); // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent(); f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } if (!first) f_service_ << ","; f_service_ << "resultHandler"; f_service_ << ");" << endl; indent_down(); indent(f_service_) << "}"; // Close function f_service_ << endl; // Close class indent_down(); f_service_ << indent() << "}" << endl << endl; } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_java_generator::generate_process_function(t_service* tservice, t_function* tfunction) { string argsname = tfunction->get_name() + "_args"; string resultname = tfunction->get_name() + "_result"; if (tfunction->is_oneway()) { resultname = "org.apache.thrift.TBase"; } (void)tservice; // Open class indent(f_service_) << "public static class " << tfunction->get_name() << " extends org.apache.thrift.ProcessFunction {" << endl; indent_up(); indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl; indent(f_service_) << " super(\"" << tfunction->get_name() << "\");" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl; indent(f_service_) << " return new " << argsname << "();" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "protected boolean isOneway() {" << endl; indent(f_service_) << " return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "@Override" << endl; indent(f_service_) << "protected boolean rethrowUnhandledExceptions() {" << endl; indent(f_service_) << " return " << ((rethrow_unhandled_exceptions_) ? "true" : "false") << ";" << endl; indent(f_service_) << "}" << endl << endl; indent(f_service_) << "public " << resultname << " getResult(I iface, " << argsname << " args) throws org.apache.thrift.TException {" << endl; indent_up(); if (!tfunction->is_oneway()) { indent(f_service_) << resultname << " result = new " << resultname << "();" << endl; } t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Try block for a function with exceptions if (xceptions.size() > 0) { f_service_ << indent() << "try {" << endl; indent_up(); } // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_service_ << "result.success = "; } f_service_ << "iface." << get_rpc_method_name(tfunction->get_name()) << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ");" << endl; // Set isset on success field if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) { indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl; } if (!tfunction->is_oneway() && xceptions.size() > 0) { indent_down(); f_service_ << indent() << "}"; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ") {" << endl; if (!tfunction->is_oneway()) { indent_up(); f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl; indent_down(); f_service_ << indent() << "}"; } else { f_service_ << "}"; } } f_service_ << endl; } if (tfunction->is_oneway()) { indent(f_service_) << "return null;" << endl; } else { indent(f_service_) << "return result;" << endl; } indent_down(); indent(f_service_) << "}"; // Close function f_service_ << endl; // Close class indent_down(); f_service_ << indent() << "}" << endl << endl; } /** * Deserializes a field of any type. * * @param tfield The field * @param prefix The variable name or container for this field */ void t_java_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, bool has_metadata) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + tfield->get_name(); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_deserialize_container(out, type, name, has_metadata); } else if (type->is_base_type()) { indent(out) << name << " = iprot."; t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "readBinary();"; } else { out << "readString();"; } break; case t_base_type::TYPE_BOOL: out << "readBool();"; break; case t_base_type::TYPE_I8: out << "readByte();"; break; case t_base_type::TYPE_I16: out << "readI16();"; break; case t_base_type::TYPE_I32: out << "readI32();"; break; case t_base_type::TYPE_I64: out << "readI64();"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble();"; break; default: throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); } out << endl; } else if (type->is_enum()) { indent(out) << name << " = " << type_name(tfield->get_type(), true, false, false, true) + ".findByValue(iprot.readI32());" << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str()); } } /** * Generates an unserializer for a struct, invokes read() */ void t_java_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { if (reuse_objects_) { indent(out) << "if (" << prefix << " == null) {" << endl; indent_up(); } indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl; if (reuse_objects_) { indent_down(); indent(out) << "}" << endl; } indent(out) << prefix << ".read(iprot);" << endl; } /** * Deserializes a container by reading its size and then iterating */ void t_java_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix, bool has_metadata) { scope_up(out); string obj; if (ttype->is_map()) { obj = tmp("_map"); } else if (ttype->is_set()) { obj = tmp("_set"); } else if (ttype->is_list()) { obj = tmp("_list"); } if (has_metadata) { // Declare variables, read header if (ttype->is_map()) { indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = iprot.readMapBegin();" << endl; } else if (ttype->is_set()) { indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = iprot.readSetBegin();" << endl; } else if (ttype->is_list()) { indent(out) << "org.apache.thrift.protocol.TList " << obj << " = iprot.readListBegin();" << endl; } } else { // Declare variables, read header if (ttype->is_map()) { indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = iprot.readMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << "); "<< endl; } else if (ttype->is_set()) { indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = iprot.readSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl; } else if (ttype->is_list()) { indent(out) << "org.apache.thrift.protocol.TList " << obj << " = iprot.readListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl; } } if (reuse_objects_) { indent(out) << "if (" << prefix << " == null) {" << endl; indent_up(); } if (is_enum_set(ttype)) { out << indent() << prefix << " = " << type_name(ttype, false, true, true) << ".noneOf"; } else { out << indent() << prefix << " = new " << type_name(ttype, false, true); } // construct the collection correctly i.e. with appropriate size/type if (is_enum_set(ttype) || is_enum_map(ttype)) { out << "(" << inner_enum_type_name(ttype) << ");" << endl; } else if (sorted_containers_ && (ttype->is_map() || ttype->is_set())) { // TreeSet and TreeMap don't have any constructor which takes a capacity as an argument out << "();" << endl; } else { out << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size" << ");" << endl; } if (reuse_objects_) { indent_down(); indent(out) << "}" << endl; } if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix, obj, has_metadata); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix, obj, has_metadata); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix, obj, has_metadata); } scope_down(out); if (has_metadata) { // Read container end if (ttype->is_map()) { indent(out) << "iprot.readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "iprot.readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "iprot.readListEnd();" << endl; } } scope_down(out); } /** * Generates code to deserialize a map */ void t_java_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix, string obj, bool has_metadata) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); indent(out) << declare_field(&fkey, reuse_objects_, false) << endl; indent(out) << declare_field(&fval, reuse_objects_, false) << endl; // For loop iterates over elements string i = tmp("_i"); indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" << "; " << "++" << i << ")" << endl; scope_up(out); generate_deserialize_field(out, &fkey, "", has_metadata); generate_deserialize_field(out, &fval, "", has_metadata); if (get_true_type(fkey.get_type())->is_enum()) { indent(out) << "if (" << key << " != null)" << endl; scope_up(out); } indent(out) << prefix << ".put(" << key << ", " << val << ");" << endl; if (get_true_type(fkey.get_type())->is_enum()) { scope_down(out); } if (reuse_objects_ && !get_true_type(fkey.get_type())->is_base_type()) { indent(out) << key << " = null;" << endl; } if (reuse_objects_ && !get_true_type(fval.get_type())->is_base_type()) { indent(out) << val << " = null;" << endl; } } /** * Deserializes a set element */ void t_java_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix, string obj, bool has_metadata) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << declare_field(&felem, reuse_objects_, false) << endl; // For loop iterates over elements string i = tmp("_i"); indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" << "; " << "++" << i << ")" << endl; scope_up(out); generate_deserialize_field(out, &felem, "", has_metadata); if (get_true_type(felem.get_type())->is_enum()) { indent(out) << "if (" << elem << " != null)" << endl; scope_up(out); } indent(out) << prefix << ".add(" << elem << ");" << endl; if (get_true_type(felem.get_type())->is_enum()) { scope_down(out); } if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) { indent(out) << elem << " = null;" << endl; } } /** * Deserializes a list element */ void t_java_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix, string obj, bool has_metadata) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << declare_field(&felem, reuse_objects_, false) << endl; // For loop iterates over elements string i = tmp("_i"); indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" << "; " << "++" << i << ")" << endl; scope_up(out); generate_deserialize_field(out, &felem, "", has_metadata); if (get_true_type(felem.get_type())->is_enum()) { indent(out) << "if (" << elem << " != null)" << endl; scope_up(out); } indent(out) << prefix << ".add(" << elem << ");" << endl; if (get_true_type(felem.get_type())->is_enum()) { scope_down(out); } if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) { indent(out) << elem << " = null;" << endl; } } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_java_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, bool has_metadata) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + tfield->get_name(), has_metadata); } else if (type->is_enum()) { indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl; } else if (type->is_base_type()) { string name = prefix + tfield->get_name(); indent(out) << "oprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "writeBinary(" << name << ");"; } else { out << "writeString(" << name << ");"; } break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ");"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ");"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ");"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ");"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ");"; break; default: throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32(struct." << name << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_java_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; out << indent() << prefix << ".write(oprot);" << endl; } /** * Serializes a container by writing its size then the elements. * * @param ttype The type of container * @param prefix String prefix for fields */ void t_java_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix, bool has_metadata) { scope_up(out); if (has_metadata) { if (ttype->is_map()) { indent(out) << "oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".size()));" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix << ".size()));" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListBegin(new org.apache.thrift.protocol.TList(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".size()));" << endl; } } else { indent(out) << "oprot.writeI32(" << prefix << ".size());" << endl; } string iter = tmp("_iter"); if (ttype->is_map()) { indent(out) << "for (java.util.Map.Entry<" << type_name(((t_map*)ttype)->get_key_type(), true, false) << ", " << type_name(((t_map*)ttype)->get_val_type(), true, false) << "> " << iter << " : " << prefix << ".entrySet())"; } else if (ttype->is_set()) { indent(out) << "for (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter << " : " << prefix << ")"; } else if (ttype->is_list()) { indent(out) << "for (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter << " : " << prefix << ")"; } out << endl; scope_up(out); if (ttype->is_map()) { generate_serialize_map_element(out, (t_map*)ttype, iter, prefix, has_metadata); } else if (ttype->is_set()) { generate_serialize_set_element(out, (t_set*)ttype, iter, has_metadata); } else if (ttype->is_list()) { generate_serialize_list_element(out, (t_list*)ttype, iter, has_metadata); } scope_down(out); if (has_metadata) { if (ttype->is_map()) { indent(out) << "oprot.writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListEnd();" << endl; } } scope_down(out); } /** * Serializes the members of a map. */ void t_java_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map, bool has_metadata) { (void)map; t_field kfield(tmap->get_key_type(), iter + ".getKey()"); generate_serialize_field(out, &kfield, "", has_metadata); t_field vfield(tmap->get_val_type(), iter + ".getValue()"); generate_serialize_field(out, &vfield, "", has_metadata); } /** * Serializes the members of a set. */ void t_java_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter, bool has_metadata) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, "", has_metadata); } /** * Serializes the members of a list. */ void t_java_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter, bool has_metadata) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, "", has_metadata); } /** * Returns a Java type name * * @param ttype The type * @param container Is the type going inside a container? * @return Java type name, i.e. java.util.HashMap */ string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool skip_generic, bool force_namespace) { // In Java typedefs are just resolved to their real type ttype = get_true_type(ttype); string prefix; if (ttype->is_base_type()) { return base_type_name((t_base_type*)ttype, in_container); } else if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; if (in_init) { if (is_enum_map(tmap)) { prefix = "java.util.EnumMap"; } else if (sorted_containers_) { prefix = "java.util.TreeMap"; } else { prefix = "java.util.HashMap"; } } else { prefix = "java.util.Map"; } return prefix + (skip_generic ? "" : "<" + type_name(tmap->get_key_type(), true) + "," + type_name(tmap->get_val_type(), true) + ">"); } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; if (in_init) { if (is_enum_set(tset)) { prefix = "java.util.EnumSet"; } else if (sorted_containers_) { prefix = "java.util.TreeSet"; } else { prefix = "java.util.HashSet"; } } else { prefix = "java.util.Set"; } return prefix + (skip_generic ? "" : "<" + type_name(tset->get_elem_type(), true) + ">"); } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; if (in_init) { prefix = "java.util.ArrayList"; } else { prefix = "java.util.List"; } return prefix + (skip_generic ? "" : "<" + type_name(tlist->get_elem_type(), true) + ">"); } // Check for namespacing t_program* program = ttype->get_program(); if ((program != nullptr) && ((program != program_) || force_namespace)) { string package = program->get_namespace("java"); if (!package.empty()) { return package + "." + ttype->get_name(); } } return ttype->get_name(); } /** * Returns the Java type that corresponds to the thrift type. * * @param tbase The base type * @param container Is it going in a Java container? */ string t_java_generator::base_type_name(t_base_type* type, bool in_container) { t_base_type::t_base tbase = type->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return (in_container ? "Void" : "void"); case t_base_type::TYPE_STRING: if (type->is_binary()) { return "java.nio.ByteBuffer"; } else { return "java.lang.String"; } case t_base_type::TYPE_BOOL: return (in_container ? "java.lang.Boolean" : "boolean"); case t_base_type::TYPE_I8: return (in_container ? "java.lang.Byte" : "byte"); case t_base_type::TYPE_I16: return (in_container ? "java.lang.Short" : "short"); case t_base_type::TYPE_I32: return (in_container ? "java.lang.Integer" : "int"); case t_base_type::TYPE_I64: return (in_container ? "java.lang.Long" : "long"); case t_base_type::TYPE_DOUBLE: return (in_container ? "java.lang.Double" : "double"); default: throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); } } /** * Declares a field, which may include initialization as necessary. * * @param tfield The field * @param init Whether to initialize the field */ string t_java_generator::declare_field(t_field* tfield, bool init, bool comment) { // TODO(mcslee): do we ever need to initialize the field? string result = ""; t_type* ttype = get_true_type(tfield->get_type()); if (type_can_be_null(ttype)) { result += java_nullable_annotation() + " "; } result += type_name(tfield->get_type()) + " " + tfield->get_name(); if (init) { if (ttype->is_base_type() && tfield->get_value() != nullptr) { std::ofstream dummy; result += " = " + render_const_value(dummy, ttype, tfield->get_value()); } else if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: result += " = null"; break; case t_base_type::TYPE_BOOL: result += " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = (double)0"; break; } } else if (ttype->is_enum()) { result += " = null"; } else if (ttype->is_container()) { result += " = new " + type_name(ttype, false, true) + "()"; } else { result += " = new " + type_name(ttype, false, true) + "()"; ; } } result += ";"; if (comment) { result += " // "; if (tfield->get_req() == t_field::T_OPTIONAL) { result += "optional"; } else { result += "required"; } } return result; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_java_generator::function_signature(t_function* tfunction, string prefix) { t_type* ttype = tfunction->get_returntype(); std::string fn_name = get_rpc_method_name(tfunction->get_name()); std::string result = type_name(ttype) + " " + prefix + fn_name + "(" + argument_list(tfunction->get_arglist()) + ") throws "; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { result += type_name((*x_iter)->get_type(), false, false) + ", "; } result += "org.apache.thrift.TException"; return result; } /** * Renders a function signature of the form 'void name(args, resultHandler)' * * @params tfunction Function definition * @return String of rendered function definition */ string t_java_generator::function_signature_async(t_function* tfunction, bool use_base_method, string prefix) { std::string arglist = async_function_call_arglist(tfunction, use_base_method, true); std::string ret_type = ""; if (use_base_method) { ret_type += "AsyncClient."; } ret_type += tfunction->get_name() + "_call"; std::string fn_name = get_rpc_method_name(tfunction->get_name()); std::string result = prefix + "void " + fn_name + "(" + arglist + ")"; return result; } string t_java_generator::async_function_call_arglist(t_function* tfunc, bool use_base_method, bool include_types) { (void)use_base_method; std::string arglist = ""; if (tfunc->get_arglist()->get_members().size() > 0) { arglist = argument_list(tfunc->get_arglist(), include_types) + ", "; } if (include_types) { arglist += "org.apache.thrift.async.AsyncMethodCallback<"; arglist += type_name(tfunc->get_returntype(), true) + "> "; } arglist += "resultHandler"; return arglist; } /** * Renders a comma separated field list, with type names */ string t_java_generator::argument_list(t_struct* tstruct, bool include_types) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } if (include_types) { result += type_name((*f_iter)->get_type()) + " "; } result += (*f_iter)->get_name(); } return result; } string t_java_generator::async_argument_list(t_function* tfunct, t_struct* tstruct, t_type* ttype, bool include_types) { (void)tfunct; (void)ttype; string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } if (include_types) { result += type_name((*f_iter)->get_type()) + " "; } result += (*f_iter)->get_name(); } if (!first) { result += ", "; } if (include_types) { result += "org.apache.thrift.async.AsyncMethodCallback<"; result += type_name(tfunct->get_returntype(), true) + "> "; } result += "resultHandler"; return result; } /** * Converts the parse type to a Java enum string for the given type. */ string t_java_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "org.apache.thrift.protocol.TType.STRING"; case t_base_type::TYPE_BOOL: return "org.apache.thrift.protocol.TType.BOOL"; case t_base_type::TYPE_I8: return "org.apache.thrift.protocol.TType.BYTE"; case t_base_type::TYPE_I16: return "org.apache.thrift.protocol.TType.I16"; case t_base_type::TYPE_I32: return "org.apache.thrift.protocol.TType.I32"; case t_base_type::TYPE_I64: return "org.apache.thrift.protocol.TType.I64"; case t_base_type::TYPE_DOUBLE: return "org.apache.thrift.protocol.TType.DOUBLE"; } } else if (type->is_enum()) { return "org.apache.thrift.protocol.TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "org.apache.thrift.protocol.TType.STRUCT"; } else if (type->is_map()) { return "org.apache.thrift.protocol.TType.MAP"; } else if (type->is_set()) { return "org.apache.thrift.protocol.TType.SET"; } else if (type->is_list()) { return "org.apache.thrift.protocol.TType.LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Takes a name and produes a valid Java source file name from it * * @param fromName The name which shall become a valid Java source file name * @return The produced identifier */ std::string t_java_generator::make_valid_java_filename(std::string const& fromName) { // if any further rules apply to source file names in Java, modify as necessary return make_valid_java_identifier(fromName); } /** * Takes a name and produes a valid Java identifier from it * * @param fromName The name which shall become a valid Java identifier * @return The produced identifier */ std::string t_java_generator::make_valid_java_identifier(std::string const& fromName) { std::string str = fromName; if (str.empty()) { return str; } // tests rely on this assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); // if the first letter is a number, we add an additional underscore in front of it char c = str.at(0); if (('0' <= c) && (c <= '9')) { str = "_" + str; } // following chars: letter, number or underscore for (size_t i = 0; i < str.size(); ++i) { c = str.at(i); if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) && ('_' != c)) { str.replace(i, 1, "_"); } } return str; } std::string t_java_generator::as_camel_case(std::string name, bool ucfirst) { std::string new_name; size_t i = 0; for (i = 0; i < name.size(); i++) { if (name[i] != '_') break; } if (ucfirst) { new_name += toupper(name[i++]); } else { new_name += tolower(name[i++]); } for (; i < name.size(); i++) { if (name[i] == '_') { if (i < name.size() - 1) { i++; new_name += toupper(name[i]); } } else { new_name += name[i]; } } return new_name; } std::string t_java_generator::get_rpc_method_name(std::string name) { if (fullcamel_style_) { return as_camel_case(name, false); } else { return name; } } /** * Applies the correct style to a string based on the value of nocamel_style_ * and/or fullcamel_style_ */ std::string t_java_generator::get_cap_name(std::string name) { if (nocamel_style_) { return "_" + name; } else if (fullcamel_style_) { return as_camel_case(name); } else { name[0] = toupper(name[0]); return name; } } string t_java_generator::constant_name(string name) { string constant_name; bool is_first = true; bool was_previous_char_upper = false; for (char character : name) { bool is_upper = isupper(character); if (is_upper && !is_first && !was_previous_char_upper) { constant_name += '_'; } constant_name += toupper(character); is_first = false; was_previous_char_upper = is_upper; } return constant_name; } void t_java_generator::generate_deep_copy_container(ostream& out, std::string source_name_p1, std::string source_name_p2, std::string result_name, t_type* type) { t_container* container = (t_container*)type; std::string source_name; if (source_name_p2 == "") source_name = source_name_p1; else source_name = source_name_p1 + "." + source_name_p2; bool copy_construct_container; if (container->is_map()) { t_map* tmap = (t_map*)container; copy_construct_container = tmap->get_key_type()->is_base_type() && tmap->get_val_type()->is_base_type(); } else { t_type* elem_type = container->is_list() ? ((t_list*)container)->get_elem_type() : ((t_set*)container)->get_elem_type(); copy_construct_container = elem_type->is_base_type(); } if (copy_construct_container) { // deep copy of base types can be done much more efficiently than iterating over all the // elements manually indent(out) << type_name(type, true, false) << " " << result_name << " = new " << type_name(container, false, true) << "(" << source_name << ");" << endl; return; } std::string constructor_args; if (is_enum_set(container) || is_enum_map(container)) { constructor_args = inner_enum_type_name(container); } else if (!(sorted_containers_ && (container->is_map() || container->is_set()))) { // unsorted containers accept a capacity value constructor_args = source_name + ".size()"; } if (is_enum_set(container)) { indent(out) << type_name(type, true, false) << " " << result_name << " = " << type_name(container, false, true, true) << ".noneOf(" << constructor_args << ");" << endl; } else { indent(out) << type_name(type, true, false) << " " << result_name << " = new " << type_name(container, false, true) << "(" << constructor_args << ");" << endl; } std::string iterator_element_name = source_name_p1 + "_element"; std::string result_element_name = result_name + "_copy"; if (container->is_map()) { t_type* key_type = ((t_map*)container)->get_key_type(); t_type* val_type = ((t_map*)container)->get_val_type(); indent(out) << "for (java.util.Map.Entry<" << type_name(key_type, true, false) << ", " << type_name(val_type, true, false) << "> " << iterator_element_name << " : " << source_name << ".entrySet()) {" << endl; indent_up(); out << endl; indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = " << iterator_element_name << ".getKey();" << endl; indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = " << iterator_element_name << ".getValue();" << endl; out << endl; if (key_type->is_container()) { generate_deep_copy_container(out, iterator_element_name + "_key", "", result_element_name + "_key", key_type); } else { indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = "; generate_deep_copy_non_container(out, iterator_element_name + "_key", result_element_name + "_key", key_type); out << ";" << endl; } out << endl; if (val_type->is_container()) { generate_deep_copy_container(out, iterator_element_name + "_value", "", result_element_name + "_value", val_type); } else { indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = "; generate_deep_copy_non_container(out, iterator_element_name + "_value", result_element_name + "_value", val_type); out << ";" << endl; } out << endl; indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name << "_value);" << endl; indent_down(); indent(out) << "}" << endl; } else { t_type* elem_type; if (container->is_set()) { elem_type = ((t_set*)container)->get_elem_type(); } else { elem_type = ((t_list*)container)->get_elem_type(); } indent(out) << "for (" << type_name(elem_type, true, false) << " " << iterator_element_name << " : " << source_name << ") {" << endl; indent_up(); if (elem_type->is_container()) { // recursive deep copy generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type); indent(out) << result_name << ".add(" << result_element_name << ");" << endl; } else { // iterative copy if (elem_type->is_binary()) { indent(out) << "java.nio.ByteBuffer temp_binary_element = "; generate_deep_copy_non_container(out, iterator_element_name, "temp_binary_element", elem_type); out << ";" << endl; indent(out) << result_name << ".add(temp_binary_element);" << endl; } else { indent(out) << result_name << ".add("; generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type); out << ");" << endl; } } indent_down(); indent(out) << "}" << endl; } } void t_java_generator::generate_deep_copy_non_container(ostream& out, std::string source_name, std::string dest_name, t_type* type) { (void)dest_name; type = get_true_type(type); if (type->is_base_type() || type->is_enum() || type->is_typedef()) { if (type->is_binary()) { out << "org.apache.thrift.TBaseHelper.copyBinary(" << source_name << ")"; } else { // everything else can be copied directly out << source_name; } } else { out << "new " << type_name(type, true, true) << "(" << source_name << ")"; } } std::string t_java_generator::generate_isset_check(t_field* field) { return generate_isset_check(field->get_name()); } std::string t_java_generator::isset_field_id(t_field* field) { return "__" + upcase_string(field->get_name() + "_isset_id"); } std::string t_java_generator::generate_isset_check(std::string field_name) { return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; } void t_java_generator::generate_isset_set(ostream& out, t_field* field, string prefix) { if (!type_can_be_null(field->get_type())) { indent(out) << prefix << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(true);" << endl; } } void t_java_generator::generate_struct_desc(ostream& out, t_struct* tstruct) { indent(out) << "private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new " "org.apache.thrift.protocol.TStruct(\"" << tstruct->get_name() << "\");" << endl; } void t_java_generator::generate_field_descs(ostream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "private static final org.apache.thrift.protocol.TField " << constant_name((*m_iter)->get_name()) << "_FIELD_DESC = new org.apache.thrift.protocol.TField(\"" << (*m_iter)->get_name() << "\", " << type_to_enum((*m_iter)->get_type()) << ", " << "(short)" << (*m_iter)->get_key() << ");" << endl; } } void t_java_generator::generate_scheme_map(ostream& out, t_struct* tstruct) { indent(out) << "private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new " << tstruct->get_name() << "StandardSchemeFactory();" << endl; indent(out) << "private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new " << tstruct->get_name() << "TupleSchemeFactory();" << endl; } void t_java_generator::generate_field_name_constants(ostream& out, t_struct* tstruct) { indent(out) << "/** The set of fields this struct contains, along with convenience methods for " "finding and manipulating them. */" << endl; indent(out) << "public enum _Fields implements org.apache.thrift.TFieldIdEnum {" << endl; indent_up(); bool first = true; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!first) { out << "," << endl; } first = false; generate_java_doc(out, *m_iter); indent(out) << constant_name((*m_iter)->get_name()) << "((short)" << (*m_iter)->get_key() << ", \"" << (*m_iter)->get_name() << "\")"; } out << ";" << endl << endl; indent(out) << "private static final java.util.Map byName = new java.util.HashMap();" << endl; out << endl; indent(out) << "static {" << endl; indent(out) << " for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {" << endl; indent(out) << " byName.put(field.getFieldName(), field);" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl << endl; indent(out) << "/**" << endl; indent(out) << " * Find the _Fields constant that matches fieldId, or null if its not found." << endl; indent(out) << " */" << endl; indent(out) << java_nullable_annotation() << endl; indent(out) << "public static _Fields findByThriftId(int fieldId) {" << endl; indent_up(); indent(out) << "switch(fieldId) {" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "case " << (*m_iter)->get_key() << ": // " << constant_name((*m_iter)->get_name()) << endl; indent(out) << " return " << constant_name((*m_iter)->get_name()) << ";" << endl; } indent(out) << "default:" << endl; indent(out) << " return null;" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl << endl; indent(out) << "/**" << endl; indent(out) << " * Find the _Fields constant that matches fieldId, throwing an exception" << endl; indent(out) << " * if it is not found." << endl; indent(out) << " */" << endl; indent(out) << "public static _Fields findByThriftIdOrThrow(int fieldId) {" << endl; indent(out) << " _Fields fields = findByThriftId(fieldId);" << endl; indent(out) << " if (fields == null) throw new java.lang.IllegalArgumentException(\"Field \" + fieldId + " "\" doesn't exist!\");" << endl; indent(out) << " return fields;" << endl; indent(out) << "}" << endl << endl; indent(out) << "/**" << endl; indent(out) << " * Find the _Fields constant that matches name, or null if its not found." << endl; indent(out) << " */" << endl; indent(out) << java_nullable_annotation() << endl; indent(out) << "public static _Fields findByName(java.lang.String name) {" << endl; indent(out) << " return byName.get(name);" << endl; indent(out) << "}" << endl << endl; indent(out) << "private final short _thriftId;" << endl; indent(out) << "private final java.lang.String _fieldName;" << endl << endl; indent(out) << "_Fields(short thriftId, java.lang.String fieldName) {" << endl; indent(out) << " _thriftId = thriftId;" << endl; indent(out) << " _fieldName = fieldName;" << endl; indent(out) << "}" << endl << endl; indent(out) << "public short getThriftFieldId() {" << endl; indent(out) << " return _thriftId;" << endl; indent(out) << "}" << endl << endl; indent(out) << "public java.lang.String getFieldName() {" << endl; indent(out) << " return _fieldName;" << endl; indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } t_java_generator::isset_type t_java_generator::needs_isset(t_struct* tstruct, std::string* outPrimitiveType) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; int count = 0; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) { count++; } } if (count == 0) { return ISSET_NONE; } else if (count <= 64) { if (outPrimitiveType != nullptr) { if (count <= 8) *outPrimitiveType = "byte"; else if (count <= 16) *outPrimitiveType = "short"; else if (count <= 32) *outPrimitiveType = "int"; else if (count <= 64) *outPrimitiveType = "long"; } return ISSET_PRIMITIVE; } else { return ISSET_BITSET; } } void t_java_generator::generate_java_struct_clear(std::ostream& out, t_struct* tstruct) { if (!java5_) { indent(out) << "@Override" << endl; } indent(out) << "public void clear() {" << endl; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = *m_iter; t_type* t = get_true_type(field->get_type()); if (field->get_value() != nullptr) { print_const_value(out, "this." + field->get_name(), t, field->get_value(), true, true); continue; } if (type_can_be_null(t)) { if (reuse_objects_ && (t->is_container() || t->is_struct())) { indent(out) << "if (this." << field->get_name() << " != null) {" << endl; indent_up(); indent(out) << "this." << field->get_name() << ".clear();" << endl; indent_down(); indent(out) << "}" << endl; } else { indent(out) << "this." << field->get_name() << " = null;" << endl; } continue; } // must be a base type // means it also needs to be explicitly unset indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(false);" << endl; t_base_type* base_type = (t_base_type*)t; switch (base_type->get_base()) { case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: indent(out) << "this." << field->get_name() << " = 0;" << endl; break; case t_base_type::TYPE_DOUBLE: indent(out) << "this." << field->get_name() << " = 0.0;" << endl; break; case t_base_type::TYPE_BOOL: indent(out) << "this." << field->get_name() << " = false;" << endl; break; default: throw "unsupported type: " + base_type->get_name() + " for field " + field->get_name(); } } indent_down(); indent(out) << "}" << endl << endl; } // generates java method to serialize (in the Java sense) the object void t_java_generator::generate_java_struct_write_object(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {" << endl; indent(out) << " try {" << endl; indent(out) << " write(new org.apache.thrift.protocol.TCompactProtocol(new " "org.apache.thrift.transport.TIOStreamTransport(out)));" << endl; indent(out) << " } catch (org.apache.thrift.TException te) {" << endl; indent(out) << " throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "") << ");" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl << endl; } // generates java method to serialize (in the Java sense) the object void t_java_generator::generate_java_struct_read_object(ostream& out, t_struct* tstruct) { indent(out) << "private void readObject(java.io.ObjectInputStream in) throws " "java.io.IOException, java.lang.ClassNotFoundException {" << endl; indent(out) << " try {" << endl; if (!tstruct->is_union()) { switch (needs_isset(tstruct)) { case ISSET_NONE: break; case ISSET_PRIMITIVE: indent(out) << " // it doesn't seem like you should have to do this, but java " "serialization is wacky, and doesn't call the default constructor." << endl; indent(out) << " __isset_bitfield = 0;" << endl; break; case ISSET_BITSET: indent(out) << " // it doesn't seem like you should have to do this, but java " "serialization is wacky, and doesn't call the default constructor." << endl; indent(out) << " __isset_bit_vector = new java.util.BitSet(1);" << endl; break; } } indent(out) << " read(new org.apache.thrift.protocol.TCompactProtocol(new " "org.apache.thrift.transport.TIOStreamTransport(in)));" << endl; indent(out) << " } catch (org.apache.thrift.TException te) {" << endl; indent(out) << " throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "") << ");" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl << endl; } void t_java_generator::generate_standard_reader(ostream& out, t_struct* tstruct) { out << indent() << "public void read(org.apache.thrift.protocol.TProtocol iprot, " << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // Declare stack tmp variables and read struct header out << indent() << "org.apache.thrift.protocol.TField schemeField;" << endl << indent() << "iprot.readStructBegin();" << endl; // Loop over reading in fields indent(out) << "while (true)" << endl; scope_up(out); // Read beginning field marker indent(out) << "schemeField = iprot.readFieldBegin();" << endl; // Check for field STOP marker and break indent(out) << "if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { " << endl; indent_up(); indent(out) << "break;" << endl; indent_down(); indent(out) << "}" << endl; // Switch statement on the field we are reading indent(out) << "switch (schemeField.id) {" << endl; indent_up(); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << (*f_iter)->get_key() << ": // " << constant_name((*f_iter)->get_name()) << endl; indent_up(); indent(out) << "if (schemeField.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); generate_deserialize_field(out, *f_iter, "struct.", true); indent(out) << "struct." << "set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") << "(true);" << endl; indent_down(); out << indent() << "} else { " << endl << indent() << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);" << endl << indent() << "}" << endl << indent() << "break;" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);" << endl; indent_down(); indent(out) << "}" << endl; // Read field end marker indent(out) << "iprot.readFieldEnd();" << endl; indent_down(); indent(out) << "}" << endl; out << indent() << "iprot.readStructEnd();" << endl; // in non-beans style, check for required fields of primitive type // (which can be checked here but not in the general validate method) if (!bean_style_) { out << endl << indent() << "// check for required fields of primitive type, which can't be " "checked in the validate method" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { out << indent() << "if (!struct." << generate_isset_check(*f_iter) << ") {" << endl << indent() << " throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl << indent() << "}" << endl; } } } // performs various checks (e.g. check that all required fields are set) indent(out) << "struct.validate();" << endl; indent_down(); out << indent() << "}" << endl; } void t_java_generator::generate_standard_writer(ostream& out, t_struct* tstruct, bool is_result) { indent_up(); out << indent() << "public void write(org.apache.thrift.protocol.TProtocol oprot, " << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; indent_up(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; // performs various checks (e.g. check that all required fields are set) indent(out) << "struct.validate();" << endl << endl; indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool null_allowed = type_can_be_null((*f_iter)->get_type()); if (null_allowed) { out << indent() << "if (struct." << (*f_iter)->get_name() << " != null) {" << endl; indent_up(); } bool optional = ((*f_iter)->get_req() == t_field::T_OPTIONAL) || (is_result && !null_allowed); if (optional) { indent(out) << "if (" << "struct." << generate_isset_check((*f_iter)) << ") {" << endl; indent_up(); } indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl; // Write field contents generate_serialize_field(out, *f_iter, "struct.", true); // Write field closer indent(out) << "oprot.writeFieldEnd();" << endl; if (optional) { indent_down(); indent(out) << "}" << endl; } if (null_allowed) { indent_down(); indent(out) << "}" << endl; } } // Write the struct map out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" << endl; indent_down(); out << indent() << "}" << endl << endl; indent_down(); } void t_java_generator::generate_java_struct_standard_scheme(ostream& out, t_struct* tstruct, bool is_result) { indent(out) << "private static class " << tstruct->get_name() << "StandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {" << endl; indent_up(); indent(out) << "public " << tstruct->get_name() << "StandardScheme getScheme() {" << endl; indent_up(); indent(out) << "return new " << tstruct->get_name() << "StandardScheme();" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl << endl; out << indent() << "private static class " << tstruct->get_name() << "StandardScheme extends org.apache.thrift.scheme.StandardScheme<" << tstruct->get_name() << "> {" << endl << endl; indent_up(); generate_standard_reader(out, tstruct); indent_down(); out << endl; generate_standard_writer(out, tstruct, is_result); out << indent() << "}" << endl << endl; } void t_java_generator::generate_java_struct_tuple_reader(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "public void read(org.apache.thrift.protocol.TProtocol prot, " << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;" << endl; int optional_count = 0; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { optional_count++; } if ((*f_iter)->get_req() == t_field::T_REQUIRED) { generate_deserialize_field(out, (*f_iter), "struct.", false); indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") << "(true);" << endl; } } if (optional_count > 0) { indent(out) << "java.util.BitSet incoming = iprot.readBitSet(" << optional_count << ");" << endl; int i = 0; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { indent(out) << "if (incoming.get(" << i << ")) {" << endl; indent_up(); generate_deserialize_field(out, (*f_iter), "struct.", false); indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") << "(true);" << endl; indent_down(); indent(out) << "}" << endl; i++; } } } indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_java_struct_tuple_writer(ostream& out, t_struct* tstruct) { indent(out) << "@Override" << endl; indent(out) << "public void write(org.apache.thrift.protocol.TProtocol prot, " << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl; indent_up(); indent(out) << "org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;" << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool has_optional = false; int optional_count = 0; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { optional_count++; has_optional = true; } if ((*f_iter)->get_req() == t_field::T_REQUIRED) { generate_serialize_field(out, (*f_iter), "struct.", false); } } if (has_optional) { indent(out) << "java.util.BitSet optionals = new java.util.BitSet();" << endl; int i = 0; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { indent(out) << "if (struct." << generate_isset_check((*f_iter)) << ") {" << endl; indent_up(); indent(out) << "optionals.set(" << i << ");" << endl; indent_down(); indent(out) << "}" << endl; i++; } } indent(out) << "oprot.writeBitSet(optionals, " << optional_count << ");" << endl; int j = 0; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { indent(out) << "if (struct." << generate_isset_check(*f_iter) << ") {" << endl; indent_up(); generate_serialize_field(out, (*f_iter), "struct.", false); indent_down(); indent(out) << "}" << endl; j++; } } } indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_java_struct_tuple_scheme(ostream& out, t_struct* tstruct) { indent(out) << "private static class " << tstruct->get_name() << "TupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {" << endl; indent_up(); indent(out) << "public " << tstruct->get_name() << "TupleScheme getScheme() {" << endl; indent_up(); indent(out) << "return new " << tstruct->get_name() << "TupleScheme();" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl << endl; out << indent() << "private static class " << tstruct->get_name() << "TupleScheme extends org.apache.thrift.scheme.TupleScheme<" << tstruct->get_name() << "> {" << endl << endl; indent_up(); generate_java_struct_tuple_writer(out, tstruct); out << endl; generate_java_struct_tuple_reader(out, tstruct); indent_down(); out << indent() << "}" << endl << endl; } void t_java_generator::generate_java_scheme_lookup(ostream& out) { indent(out) << "private static S scheme(" << "org.apache.thrift.protocol.TProtocol proto) {" << endl; indent_up(); indent(out) << "return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) " << "? STANDARD_SCHEME_FACTORY " << ": TUPLE_SCHEME_FACTORY" << ").getScheme();" << endl; indent_down(); indent(out) << "}" << endl; } void t_java_generator::generate_javax_generated_annotation(ostream& out) { time_t seconds = time(nullptr); struct tm* now = localtime(&seconds); indent(out) << "@javax.annotation.Generated(value = \"" << autogen_summary() << "\""; if (undated_generated_annotations_) { out << ")" << endl; } else { indent(out) << ", date = \"" << (now->tm_year + 1900) << "-" << setfill('0') << setw(2) << (now->tm_mon + 1) << "-" << setfill('0') << setw(2) << now->tm_mday << "\")" << endl; } } THRIFT_REGISTER_GENERATOR( java, "Java", " beans: Members will be private, and setter methods will return void.\n" " private-members: Members will be private, but setter methods will return 'this' like " "usual.\n" " nocamel: Do not use CamelCase field accessors with beans.\n" " fullcamel: Convert underscored_accessor_or_service_names to camelCase.\n" " android: Generated structures are Parcelable.\n" " android_legacy: Do not use java.io.IOException(throwable) (available for Android 2.3 and " "above).\n" " option_type: Wrap optional fields in an Option type.\n" " rethrow_unhandled_exceptions:\n" " Enable rethrow of unhandled exceptions and let them propagate further." " (Default behavior is to catch and log it.)\n" " java5: Generate Java 1.5 compliant code (includes android_legacy flag).\n" " reuse-objects: Data objects will not be allocated, but existing instances will be used " "(read and write).\n" " sorted_containers:\n" " Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of " "set/map.\n" " generated_annotations=[undated|suppress]:\n" " undated: suppress the date at @Generated annotations\n" " suppress: suppress @Generated annotations entirely\n" " unsafe_binaries: Do not copy ByteBuffers in constructors, getters, and setters.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_javame_generator.cc000066400000000000000000003435021420101504100255110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * Java code generator. * */ class t_javame_generator : public t_oop_generator { public: t_javame_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)parsed_options; (void)option_string; std::map::const_iterator iter; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option javame:" + iter->first; } out_dir_base_ = "gen-javame"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; void generate_consts(std::vector consts) override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_struct(t_struct* tstruct) override; void generate_union(t_struct* tunion); void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void print_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval = false); std::string render_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value); /** * Service-level generation functions */ void generate_java_struct(t_struct* tstruct, bool is_exception); void generate_java_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool in_class = false, bool is_result = false); void generate_java_struct_equality(std::ostream& out, t_struct* tstruct); void generate_java_struct_compare_to(std::ostream& out, t_struct* tstruct); void generate_java_struct_reader(std::ostream& out, t_struct* tstruct); void generate_java_validator(std::ostream& out, t_struct* tstruct); void generate_java_struct_result_writer(std::ostream& out, t_struct* tstruct); void generate_java_struct_writer(std::ostream& out, t_struct* tstruct); void generate_java_struct_tostring(std::ostream& out, t_struct* tstruct); void generate_java_struct_clear(std::ostream& out, t_struct* tstruct); void generate_field_value_meta_data(std::ostream& out, t_type* type); std::string get_java_type_string(t_type* type); void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name); void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name); void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct); void generate_java_bean_boilerplate(std::ostream& out, t_struct* tstruct); void generate_function_helpers(t_function* tfunction); std::string get_cap_name(std::string name); std::string generate_isset_check(t_field* field); std::string generate_isset_check(std::string field); void generate_isset_set(ostream& out, t_field* field); std::string isset_field_id(t_field* field); void generate_primitive_service_interface(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); void generate_java_union(t_struct* tstruct); void generate_union_constructor(ostream& out, t_struct* tstruct); void generate_union_getters_and_setters(ostream& out, t_struct* tstruct); void generate_union_abstract_methods(ostream& out, t_struct* tstruct); void generate_check_type(ostream& out, t_struct* tstruct); void generate_read_value(ostream& out, t_struct* tstruct); void generate_write_value(ostream& out, t_struct* tstruct); void generate_get_field_desc(ostream& out, t_struct* tstruct); void generate_get_struct_desc(ostream& out, t_struct* tstruct); void generate_get_field_name(ostream& out, t_struct* tstruct); void generate_union_comparisons(ostream& out, t_struct* tstruct); void generate_union_hashcode(ostream& out, t_struct* tstruct); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string iter, std::string map); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); void generate_java_doc(std::ostream& out, t_field* field) override; void generate_java_doc(std::ostream& out, t_doc* tdoc) override; void generate_java_doc(std::ostream& out, t_function* tdoc) override; void generate_java_docstring_comment(std::ostream& out, string contents) override; void generate_deep_copy_container(std::ostream& out, std::string source_name_p1, std::string source_name_p2, std::string result_name, t_type* type); void generate_deep_copy_non_container(std::ostream& out, std::string source_name, std::string dest_name, t_type* type); bool has_bit_vector(t_struct* tstruct); /** * Helper rendering functions */ std::string java_package(); std::string java_type_imports(); std::string java_thrift_imports(); std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false, bool skip_generic = false); std::string base_type_name(t_base_type* tbase, bool in_container = false); std::string declare_field(t_field* tfield, bool init = false); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string argument_list(t_struct* tstruct, bool include_types = true); std::string type_to_enum(t_type* ttype); std::string get_enum_class_name(t_type* type) override; void generate_struct_desc(ostream& out, t_struct* tstruct); void generate_field_descs(ostream& out, t_struct* tstruct); std::string box_type(t_type* type, string value); bool type_can_be_null(t_type* ttype) { ttype = get_true_type(ttype); return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string() || ttype->is_enum(); } std::string constant_name(std::string name); private: /** * File streams */ std::string package_name_; ofstream_with_content_based_conditional_update f_service_; std::string package_dir_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_javame_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); package_name_ = program_->get_namespace("java"); string dir = package_name_; string subdir = get_out_dir(); string::size_type loc; while ((loc = dir.find(".")) != string::npos) { subdir = subdir + "/" + dir.substr(0, loc); MKDIR(subdir.c_str()); dir = dir.substr(loc + 1); } if (dir.size() > 0) { subdir = subdir + "/" + dir; MKDIR(subdir.c_str()); } package_dir_ = subdir; } /** * Packages the generated file * * @return String of the package, i.e. "package org.apache.thriftdemo;" */ string t_javame_generator::java_package() { if (!package_name_.empty()) { return string("package ") + package_name_ + ";\n\n"; } return ""; } /** * Prints standard java imports * * @return List of imports for Java types that are used in here */ string t_javame_generator::java_type_imports() { return string() + "import java.util.Hashtable;\n" + "import java.util.Vector;\n" + "import java.util.Enumeration;\n\n"; } /** * Prints standard java imports * * @return List of imports necessary for thrift */ string t_javame_generator::java_thrift_imports() { return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + "import org.apache.thrift.transport.*;\n" + "import org.apache.thrift.protocol.*;\n\n"; } /** * Nothing in Java */ void t_javame_generator::close_generator() { } /** * Generates a typedef. This is not done in Java, since it does * not support arbitrary name replacements, and it'd be a wacky waste * of overhead to make wrapper classes. * * @param ttypedef The type definition */ void t_javame_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Enums are a class with a set of static constants. * * @param tenum The enumeration */ void t_javame_generator::generate_enum(t_enum* tenum) { // Make output file string f_enum_name = package_dir_ + "/" + (tenum->get_name()) + ".java"; ofstream_with_content_based_conditional_update f_enum; f_enum.open(f_enum_name.c_str()); // Comment and package it f_enum << autogen_comment() << java_package(); generate_java_doc(f_enum, tenum); indent(f_enum) << "public class " << tenum->get_name() << " implements org.apache.thrift.TEnum "; scope_up(f_enum); f_enum << endl; vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); generate_java_doc(f_enum, *c_iter); indent(f_enum) << "public static final " << tenum->get_name() << " " << (*c_iter)->get_name() << " = new " << tenum->get_name() << "(" << value << ");" << endl; } f_enum << endl; // Field for thriftCode indent(f_enum) << "private final int value;" << endl << endl; indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl; indent(f_enum) << " this.value = value;" << endl; indent(f_enum) << "}" << endl << endl; indent(f_enum) << "/**" << endl; indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL." << endl; indent(f_enum) << " */" << endl; indent(f_enum) << "public int getValue() {" << endl; indent(f_enum) << " return value;" << endl; indent(f_enum) << "}" << endl << endl; indent(f_enum) << "/**" << endl; indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL." << endl; indent(f_enum) << " * @return null if the value is not found." << endl; indent(f_enum) << " */" << endl; indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl; indent_up(); indent(f_enum) << "switch (value) {" << endl; indent_up(); for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); indent(f_enum) << "case " << value << ":" << endl; indent(f_enum) << " return " << (*c_iter)->get_name() << ";" << endl; } indent(f_enum) << "default:" << endl; indent(f_enum) << " return null;" << endl; indent_down(); indent(f_enum) << "}" << endl; indent_down(); indent(f_enum) << "}" << endl; scope_down(f_enum); f_enum.close(); } /** * Generates a class that holds all the constants. */ void t_javame_generator::generate_consts(std::vector consts) { if (consts.empty()) { return; } string f_consts_name = package_dir_ + "/" + program_name_ + "Constants.java"; ofstream_with_content_based_conditional_update f_consts; f_consts.open(f_consts_name.c_str()); // Print header f_consts << autogen_comment() << java_package() << java_type_imports(); f_consts << "public class " << program_name_ << "Constants {" << endl << endl; indent_up(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false); } indent_down(); indent(f_consts) << "}" << endl; f_consts.close(); } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ void t_javame_generator::print_const_value(std::ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) { type = get_true_type(type); indent(out); if (!defval) { out << (in_static ? "" : "public static final ") << type_name(type) << " "; } if (type->is_base_type()) { string v2 = render_const_value(out, name, type, value); out << name << " = " << v2 << ";" << endl << endl; } else if (type->is_enum()) { out << name << " = " << render_const_value(out, name, type, value) << ";" << endl << endl; } else if (type->is_struct() || type->is_xception()) { const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; out << name << " = new " << type_name(type, false, true) << "();" << endl; if (!in_static) { indent(out) << "static {" << endl; indent_up(); } for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string val = render_const_value(out, name, field_type, v_iter->second); indent(out) << name << "."; std::string cap_name = get_cap_name(v_iter->first->get_string()); out << "set" << cap_name << "(" << val << ");" << endl; } if (!in_static) { indent_down(); indent(out) << "}" << endl; } out << endl; } else if (type->is_map()) { out << name << " = new " << type_name(type, false, true) << "();" << endl; if (!in_static) { indent(out) << "static {" << endl; indent_up(); } t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(out, name, ktype, v_iter->first); string val = render_const_value(out, name, vtype, v_iter->second); indent(out) << name << ".put(" << box_type(ktype, key) << ", " << box_type(vtype, val) << ");" << endl; } if (!in_static) { indent_down(); indent(out) << "}" << endl; } out << endl; } else if (type->is_list() || type->is_set()) { out << name << " = new " << type_name(type, false, true) << "();" << endl; if (!in_static) { indent(out) << "static {" << endl; indent_up(); } t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(out, name, etype, *v_iter); if (type->is_list()) { indent(out) << name << ".addElement(" << box_type(etype, val) << ");" << endl; } else { indent(out) << name << ".put(" << box_type(etype, val) << ", " << box_type(etype, val) << ");" << endl; } } if (!in_static) { indent_down(); indent(out) << "}" << endl; } out << endl; } else { throw "compiler error: no const of type " + type->get_name(); } } string t_javame_generator::render_const_value(ostream& out, string name, t_type* type, t_const_value* value) { (void)name; type = get_true_type(type); std::ostringstream render; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: render << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: render << "(byte)" << value->get_integer(); break; case t_base_type::TYPE_I16: render << "(short)" << value->get_integer(); break; case t_base_type::TYPE_I32: render << value->get_integer(); break; case t_base_type::TYPE_I64: render << value->get_integer() << "L"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << "(double)" << value->get_integer(); } else { render << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { render << type_name(type, false, false) << "." << value->get_identifier(); } else { string t = tmp("tmp"); print_const_value(out, t, type, value, true); render << t; } return render.str(); } string t_javame_generator::box_type(t_type* type, string value) { if (type->is_base_type()) { switch (((t_base_type*)type)->get_base()) { case t_base_type::TYPE_BOOL: return "new Boolean(" + value + ")"; case t_base_type::TYPE_I8: return "new Byte(" + value + ")"; case t_base_type::TYPE_I16: return "new Short(" + value + ")"; case t_base_type::TYPE_I32: return "new Integer(" + value + ")"; case t_base_type::TYPE_I64: return "new Long(" + value + ")"; case t_base_type::TYPE_DOUBLE: return "new Double(" + value + ")"; default: break; } } return value; } /** * Generates a struct definition for a thrift data type. This will be a TBase * implementor. * * @param tstruct The struct definition */ void t_javame_generator::generate_struct(t_struct* tstruct) { if (tstruct->is_union()) { generate_java_union(tstruct); } else { generate_java_struct(tstruct, false); } } /** * Exceptions are structs, but they inherit from Exception * * @param tstruct The struct definition */ void t_javame_generator::generate_xception(t_struct* txception) { generate_java_struct(txception, true); } /** * Java struct definition. * * @param tstruct The struct definition */ void t_javame_generator::generate_java_struct(t_struct* tstruct, bool is_exception) { // Make output file string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java"; ofstream_with_content_based_conditional_update f_struct; f_struct.open(f_struct_name.c_str()); f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); generate_java_struct_definition(f_struct, tstruct, is_exception); f_struct.close(); } /** * Java union definition. * * @param tstruct The struct definition */ void t_javame_generator::generate_java_union(t_struct* tstruct) { // Make output file string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java"; ofstream_with_content_based_conditional_update f_struct; f_struct.open(f_struct_name.c_str()); f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); generate_java_doc(f_struct, tstruct); bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << tstruct->get_name() << " extends TUnion "; scope_up(f_struct); generate_struct_desc(f_struct, tstruct); generate_field_descs(f_struct, tstruct); f_struct << endl; generate_union_constructor(f_struct, tstruct); f_struct << endl; generate_union_abstract_methods(f_struct, tstruct); f_struct << endl; generate_union_getters_and_setters(f_struct, tstruct); f_struct << endl; generate_union_comparisons(f_struct, tstruct); f_struct << endl; generate_union_hashcode(f_struct, tstruct); f_struct << endl; scope_down(f_struct); f_struct.close(); } void t_javame_generator::generate_union_constructor(ostream& out, t_struct* tstruct) { indent(out) << "public " << type_name(tstruct) << "() {" << endl; indent(out) << " super();" << endl; indent(out) << "}" << endl << endl; indent(out) << "public " << type_name(tstruct) << "(_Fields setField, Object value) {" << endl; indent(out) << " super(setField, value);" << endl; indent(out) << "}" << endl << endl; indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {" << endl; indent(out) << " super(other);" << endl; indent(out) << "}" << endl; indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; indent(out) << "}" << endl << endl; // generate "constructors" for each field const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type()) << " value) {" << endl; indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl; indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl; indent(out) << " return x;" << endl; indent(out) << "}" << endl << endl; } } void t_javame_generator::generate_union_getters_and_setters(ostream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; bool first = true; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (first) { first = false; } else { out << endl; } t_field* field = (*m_iter); generate_java_doc(out, field); indent(out) << "public " << type_name(field->get_type()) << " get" << get_cap_name(field->get_name()) << "() {" << endl; indent(out) << " if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" << endl; indent(out) << " return (" << type_name(field->get_type(), true) << ")getFieldValue();" << endl; indent(out) << " } else {" << endl; indent(out) << " throw new RuntimeException(\"Cannot get field '" << field->get_name() << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl; out << endl; generate_java_doc(out, field); indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" << type_name(field->get_type()) << " value) {" << endl; if (type_can_be_null(field->get_type())) { indent(out) << " if (value == null) throw new NullPointerException();" << endl; } indent(out) << " setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl; indent(out) << " value_ = value;" << endl; indent(out) << "}" << endl; } } void t_javame_generator::generate_union_abstract_methods(ostream& out, t_struct* tstruct) { generate_check_type(out, tstruct); out << endl; generate_read_value(out, tstruct); out << endl; generate_write_value(out, tstruct); out << endl; generate_get_field_desc(out, tstruct); out << endl; generate_get_struct_desc(out, tstruct); out << endl; } void t_javame_generator::generate_check_type(ostream& out, t_struct* tstruct) { indent(out) << "protected void checkType(_Fields setField, Object value) throws ClassCastException {" << endl; indent_up(); indent(out) << "switch (setField) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent(out) << " if (value instanceof " << type_name(field->get_type(), true, false, true) << ") {" << endl; indent(out) << " break;" << endl; indent(out) << " }" << endl; indent(out) << " throw new ClassCastException(\"Was expecting value of type " << type_name(field->get_type(), true, false) << " for field '" << field->get_name() << "', but got \" + value.getClass().getSimpleName());" << endl; // do the real check here } indent(out) << "default:" << endl; indent(out) << " throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_javame_generator::generate_read_value(ostream& out, t_struct* tstruct) { indent(out) << "protected Object readValue(TProtocol iprot, TField field) throws TException {" << endl; indent_up(); indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl; indent(out) << "if (setField != null) {" << endl; indent_up(); indent(out) << "switch (setField) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent_up(); indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {" << endl; indent_up(); indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl; generate_deserialize_field(out, field, ""); indent(out) << "return " << field->get_name() << ";" << endl; indent_down(); indent(out) << "} else {" << endl; indent(out) << " TProtocolUtil.skip(iprot, field.type);" << endl; indent(out) << " return null;" << endl; indent(out) << "}" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " throw new IllegalStateException(\"setField wasn't null, but didn't match any " "of the case statements!\");" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "} else {" << endl; indent_up(); indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl; indent(out) << "return null;" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_javame_generator::generate_write_value(ostream& out, t_struct* tstruct) { indent(out) << "protected void writeValue(TProtocol oprot) throws TException {" << endl; indent_up(); indent(out) << "switch (setField_) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent_up(); indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = (" << type_name(field->get_type(), true, false) << ")value_;" << endl; generate_serialize_field(out, field, ""); indent(out) << "return;" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " throw new IllegalStateException(\"Cannot write union with unknown field \" + " "setField_);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_javame_generator::generate_get_field_desc(ostream& out, t_struct* tstruct) { indent(out) << "protected TField getFieldDesc(_Fields setField) {" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; indent(out) << "switch (setField) {" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); indent(out) << "case " << constant_name(field->get_name()) << ":" << endl; indent(out) << " return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl; } indent(out) << "default:" << endl; indent(out) << " throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl; indent_down(); indent(out) << "}" << endl; indent_down(); indent(out) << "}" << endl; } void t_javame_generator::generate_get_struct_desc(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "protected TStruct getStructDesc() {" << endl; indent(out) << " return STRUCT_DESC;" << endl; indent(out) << "}" << endl; } void t_javame_generator::generate_union_comparisons(ostream& out, t_struct* tstruct) { // equality indent(out) << "public boolean equals(Object other) {" << endl; indent(out) << " if (other instanceof " << tstruct->get_name() << ") {" << endl; indent(out) << " return equals((" << tstruct->get_name() << ")other);" << endl; indent(out) << " } else {" << endl; indent(out) << " return false;" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl; out << endl; indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl; indent(out) << " return other != null && getSetField() == other.getSetField() && " "getFieldValue().equals(other.getFieldValue());" << endl; indent(out) << "}" << endl; out << endl; indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; indent(out) << " int lastComparison = TBaseHelper.compareTo(getSetField(), other.getSetField());" << endl; indent(out) << " if (lastComparison == 0) {" << endl; indent(out) << " return TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());" << endl; indent(out) << " }" << endl; indent(out) << " return lastComparison;" << endl; indent(out) << "}" << endl; out << endl; } void t_javame_generator::generate_union_hashcode(ostream& out, t_struct* tstruct) { (void)tstruct; indent(out) << "/**" << endl; indent(out) << " * If you'd like this to perform more respectably, use the hashcode generator option." << endl; indent(out) << " */" << endl; indent(out) << "public int hashCode() {" << endl; indent(out) << " return 0;" << endl; indent(out) << "}" << endl; } /** * Java struct definition. This has various parameters, as it could be * generated standalone or inside another class as a helper. If it * is a helper than it is a static class. * * @param tstruct The struct definition * @param is_exception Is this an exception? * @param in_class If inside a class, needs to be static class * @param is_result If this is a result it needs a different writer */ void t_javame_generator::generate_java_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result) { generate_java_doc(out, tstruct); bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class " << tstruct->get_name() << " "; if (is_exception) { out << "extends Exception "; } out << "implements TBase "; scope_up(out); generate_struct_desc(out, tstruct); // Members are public for -java, private for -javabean const vector& members = tstruct->get_members(); vector::const_iterator m_iter; out << endl; generate_field_descs(out, tstruct); out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "private "; out << declare_field(*m_iter, false) << endl; } // isset data if (members.size() > 0) { out << endl; indent(out) << "// isset id assignments" << endl; int i = 0; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!type_can_be_null((*m_iter)->get_type())) { indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";" << endl; i++; } } if (i > 0) { indent(out) << "private boolean[] __isset_vector = new boolean[" << i << "];" << endl; } out << endl; } bool all_optional_members = true; // Default constructor indent(out) << "public " << tstruct->get_name() << "() {" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr) { print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true); } if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { all_optional_members = false; } } indent_down(); indent(out) << "}" << endl << endl; if (!members.empty() && !all_optional_members) { // Full constructor for all fields indent(out) << "public " << tstruct->get_name() << "(" << endl; indent_up(); bool first = true; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { if (!first) { out << "," << endl; } first = false; indent(out) << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name(); } } out << ")" << endl; indent_down(); indent(out) << "{" << endl; indent_up(); indent(out) << "this();" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if ((*m_iter)->get_req() != t_field::T_OPTIONAL) { indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";" << endl; generate_isset_set(out, (*m_iter)); } } indent_down(); indent(out) << "}" << endl << endl; } // copy constructor indent(out) << "/**" << endl; indent(out) << " * Performs a deep copy on other." << endl; indent(out) << " */" << endl; indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {" << endl; indent_up(); if (has_bit_vector(tstruct)) { indent(out) << "System.arraycopy(other.__isset_vector, 0, __isset_vector, 0, " "other.__isset_vector.length);" << endl; } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = (*m_iter); std::string field_name = field->get_name(); t_type* type = field->get_type(); bool can_be_null = type_can_be_null(type); if (can_be_null) { indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl; indent_up(); } if (type->is_container()) { generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type); indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl; } else { indent(out) << "this." << field_name << " = "; generate_deep_copy_non_container(out, "other." + field_name, field_name, type); out << ";" << endl; } if (can_be_null) { indent_down(); indent(out) << "}" << endl; } } indent_down(); indent(out) << "}" << endl << endl; // clone method, so that you can deep copy an object when you don't know its class. indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl; indent(out) << " return new " << tstruct->get_name() << "(this);" << endl; indent(out) << "}" << endl << endl; generate_java_struct_clear(out, tstruct); generate_java_bean_boilerplate(out, tstruct); generate_generic_field_getters_setters(out, tstruct); generate_java_struct_equality(out, tstruct); generate_java_struct_compare_to(out, tstruct); generate_java_struct_reader(out, tstruct); if (is_result) { generate_java_struct_result_writer(out, tstruct); } else { generate_java_struct_writer(out, tstruct); } generate_java_struct_tostring(out, tstruct); generate_java_validator(out, tstruct); scope_down(out); out << endl; } /** * Generates equals methods and a hashCode method for a structure. * * @param tstruct The struct definition */ void t_javame_generator::generate_java_struct_equality(ostream& out, t_struct* tstruct) { out << indent() << "public boolean equals(Object that) {" << endl; indent_up(); out << indent() << "if (that == null)" << endl << indent() << " return false;" << endl << indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl << indent() << " return this.equals((" << tstruct->get_name() << ")that);" << endl << indent() << "return false;" << endl; scope_down(out); out << endl; out << indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl; indent_up(); out << indent() << "if (that == null)" << endl << indent() << " return false;" << endl << indent() << "if (this == that)" << endl << indent() << " return true;" << endl; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << endl; t_type* t = get_true_type((*m_iter)->get_type()); // Most existing Thrift code does not use isset or optional/required, // so we treat "default" fields as required. bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL; bool can_be_null = type_can_be_null(t); string name = (*m_iter)->get_name(); string this_present = "true"; string that_present = "true"; string unequal; if (is_optional || can_be_null) { this_present += " && this." + generate_isset_check(*m_iter); that_present += " && that." + generate_isset_check(*m_iter); } out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl << indent() << "if (" << "this_present_" << name << " || that_present_" << name << ") {" << endl; indent_up(); out << indent() << "if (!(" << "this_present_" << name << " && that_present_" << name << "))" << endl << indent() << " return false;" << endl; if (t->is_binary()) { unequal = "TBaseHelper.compareTo(this." + name + ", that." + name + ") != 0"; } else if (can_be_null) { unequal = "!this." + name + ".equals(that." + name + ")"; } else { unequal = "this." + name + " != that." + name; } out << indent() << "if (" << unequal << ")" << endl << indent() << " return false;" << endl; scope_down(out); } out << endl; indent(out) << "return true;" << endl; scope_down(out); out << endl; out << indent() << "public int hashCode() {" << endl; indent_up(); indent(out) << "return 0;" << endl; indent_down(); indent(out) << "}" << endl << endl; } void t_javame_generator::generate_java_struct_compare_to(ostream& out, t_struct* tstruct) { indent(out) << "public int compareTo(Object otherObject) {" << endl; // indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl; indent_up(); indent(out) << "if (!getClass().equals(otherObject.getClass())) {" << endl; indent(out) << " return getClass().getName().compareTo(otherObject.getClass().getName());" << endl; indent(out) << "}" << endl; out << endl; indent(out) << type_name(tstruct) << " other = (" << type_name(tstruct) << ")otherObject;"; indent(out) << "int lastComparison = 0;" << endl; out << endl; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* field = *m_iter; indent(out) << "lastComparison = TBaseHelper.compareTo(" << generate_isset_check(field) << ", other." << generate_isset_check(field) << ");" << endl; indent(out) << "if (lastComparison != 0) {" << endl; indent(out) << " return lastComparison;" << endl; indent(out) << "}" << endl; indent(out) << "if (" << generate_isset_check(field) << ") {" << endl; if (field->get_type()->is_struct() || field->get_type()->is_xception()) { indent(out) << " lastComparison = this." << field->get_name() << ".compareTo(other." << field->get_name() << ");" << endl; } else { indent(out) << " lastComparison = TBaseHelper.compareTo(this." << field->get_name() << ", other." << field->get_name() << ");" << endl; } indent(out) << " if (lastComparison != 0) {" << endl; indent(out) << " return lastComparison;" << endl; indent(out) << " }" << endl; indent(out) << "}" << endl; } indent(out) << "return 0;" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a function to read all the fields of the struct. * * @param tstruct The struct definition */ void t_javame_generator::generate_java_struct_reader(ostream& out, t_struct* tstruct) { out << indent() << "public void read(TProtocol iprot) throws TException {" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // Declare stack tmp variables and read struct header out << indent() << "TField field;" << endl << indent() << "iprot.readStructBegin();" << endl; // Loop over reading in fields indent(out) << "while (true)" << endl; scope_up(out); // Read beginning field marker indent(out) << "field = iprot.readFieldBegin();" << endl; // Check for field STOP marker and break indent(out) << "if (field.type == TType.STOP) { " << endl; indent_up(); indent(out) << "break;" << endl; indent_down(); indent(out) << "}" << endl; // Switch statement on the field we are reading indent(out) << "switch (field.id) {" << endl; indent_up(); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << (*f_iter)->get_key() << ": // " << constant_name((*f_iter)->get_name()) << endl; indent_up(); indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); generate_deserialize_field(out, *f_iter, "this."); generate_isset_set(out, *f_iter); indent_down(); out << indent() << "} else { " << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" << endl << indent() << "}" << endl << indent() << "break;" << endl; indent_down(); } indent(out) << "default:" << endl; indent(out) << " TProtocolUtil.skip(iprot, field.type);" << endl; indent_down(); indent(out) << "}" << endl; // Read field end marker indent(out) << "iprot.readFieldEnd();" << endl; indent_down(); indent(out) << "}" << endl; out << indent() << "iprot.readStructEnd();" << endl; // performs various checks (e.g. check that all required fields are set) indent(out) << "validate();" << endl; indent_down(); out << indent() << "}" << endl << endl; } // generates java method to perform various checks // (e.g. check that all required fields are set) void t_javame_generator::generate_java_validator(ostream& out, t_struct* tstruct) { indent(out) << "public void validate() throws TException {" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; out << indent() << "// check for required fields" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED) { out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl << indent() << " throw new TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl << indent() << "}" << endl << endl; } } indent_down(); indent(out) << "}" << endl << endl; } /** * Generates a function to write all the fields of the struct * * @param tstruct The struct definition */ void t_javame_generator::generate_java_struct_writer(ostream& out, t_struct* tstruct) { out << indent() << "public void write(TProtocol oprot) throws TException {" << endl; indent_up(); string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; // performs various checks (e.g. check that all required fields are set) indent(out) << "validate();" << endl << endl; indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool null_allowed = type_can_be_null((*f_iter)->get_type()); if (null_allowed) { out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl; indent_up(); } bool optional = (*f_iter)->get_req() == t_field::T_OPTIONAL; if (optional) { indent(out) << "if (" << generate_isset_check((*f_iter)) << ") {" << endl; indent_up(); } indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this."); // Write field closer indent(out) << "oprot.writeFieldEnd();" << endl; if (optional) { indent_down(); indent(out) << "}" << endl; } if (null_allowed) { indent_down(); indent(out) << "}" << endl; } } // Write the struct map out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" << endl; indent_down(); out << indent() << "}" << endl << endl; } /** * Generates a function to write all the fields of the struct, * which is a function result. These fields are only written * if they are set in the Isset array, and only one of them * can be set at a time. * * @param tstruct The struct definition */ void t_javame_generator::generate_java_struct_result_writer(ostream& out, t_struct* tstruct) { out << indent() << "public void write(TProtocol oprot) throws TException {" << endl; indent_up(); string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; out << endl << indent() << "if "; } else { out << " else if "; } out << "(this." << generate_isset_check(*f_iter) << ") {" << endl; indent_up(); indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this."); // Write field closer indent(out) << "oprot.writeFieldEnd();" << endl; indent_down(); indent(out) << "}"; } // Write the struct map out << endl << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();" << endl; indent_down(); out << indent() << "}" << endl << endl; } void t_javame_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) { indent(out) << "case " << constant_name(field_name) << ":" << endl; indent_up(); if (type->is_base_type() && !type->is_string()) { t_base_type* base_type = (t_base_type*)type; indent(out) << "return new " << type_name(type, true, false) << "(" << (base_type->is_bool() ? "is" : "get") << cap_name << "());" << endl << endl; } else { indent(out) << "return get" << cap_name << "();" << endl << endl; } indent_down(); } void t_javame_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) { indent(out) << "case " << constant_name(field_name) << ":" << endl; indent_up(); indent(out) << "if (value == null) {" << endl; indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; indent(out) << "} else {" << endl; indent(out) << " set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl; indent(out) << "}" << endl; indent(out) << "break;" << endl << endl; indent_down(); } void t_javame_generator::generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct) { (void)out; std::ostringstream getter_stream; std::ostringstream setter_stream; // build up the bodies of both the getter and setter at once const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; t_type* type = get_true_type(field->get_type()); std::string field_name = field->get_name(); std::string cap_name = get_cap_name(field_name); indent_up(); generate_reflection_setters(setter_stream, type, field_name, cap_name); generate_reflection_getters(getter_stream, type, field_name, cap_name); indent_down(); } } /** * Generates a set of Java Bean boilerplate functions (setters, getters, etc.) * for the given struct. * * @param tstruct The struct definition */ void t_javame_generator::generate_java_bean_boilerplate(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; t_type* type = get_true_type(field->get_type()); std::string field_name = field->get_name(); std::string cap_name = get_cap_name(field_name); if (type->is_container()) { // Method to return the size of the collection indent(out) << "public int get" << cap_name; out << get_cap_name("size() {") << endl; indent_up(); indent(out) << "return (this." << field_name << " == null) ? 0 : " << "this." << field_name << ".size();" << endl; indent_down(); indent(out) << "}" << endl << endl; } if (type->is_set() || type->is_list()) { t_type* element_type; if (type->is_set()) { element_type = ((t_set*)type)->get_elem_type(); } else { element_type = ((t_list*)type)->get_elem_type(); } // Iterator getter for sets and lists indent(out) << "public Enumeration get" << cap_name; out << get_cap_name("Enumeration() {") << endl; indent_up(); indent(out) << "return (this." << field_name << " == null) ? null : " << "this." << field_name << ".elements();" << endl; indent_down(); indent(out) << "}" << endl << endl; // Add to set or list, create if the set/list is null indent(out); out << "public void add" << get_cap_name("to"); out << cap_name << "(" << type_name(element_type) << " elem) {" << endl; indent_up(); indent(out) << "if (this." << field_name << " == null) {" << endl; indent_up(); indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();" << endl; indent_down(); indent(out) << "}" << endl; if (type->is_set()) { indent(out) << "this." << field_name << ".put(" << box_type(element_type, "elem") << ", " << box_type(element_type, "elem") << ");" << endl; } else { indent(out) << "this." << field_name << ".addElement(" << box_type(element_type, "elem") << ");" << endl; } indent_down(); indent(out) << "}" << endl << endl; } else if (type->is_map()) { // Put to map t_type* key_type = ((t_map*)type)->get_key_type(); t_type* val_type = ((t_map*)type)->get_val_type(); indent(out); out << "public void putTo" << cap_name << "(" << type_name(key_type, true) << " key, " << type_name(val_type, true) << " val) {" << endl; indent_up(); indent(out) << "if (this." << field_name << " == null) {" << endl; indent_up(); indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();" << endl; indent_down(); indent(out) << "}" << endl; indent(out) << "this." << field_name << ".put(key, val);" << endl; indent_down(); indent(out) << "}" << endl << endl; } // Simple getter generate_java_doc(out, field); indent(out) << "public " << type_name(type); if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) { out << " is"; } else { out << " get"; } out << cap_name << "() {" << endl; indent_up(); indent(out) << "return this." << field_name << ";" << endl; indent_down(); indent(out) << "}" << endl << endl; // Simple setter generate_java_doc(out, field); indent(out) << "public "; out << "void"; out << " set" << cap_name << "(" << type_name(type) << " " << field_name << ") {" << endl; indent_up(); indent(out) << "this." << field_name << " = " << field_name << ";" << endl; generate_isset_set(out, field); indent_down(); indent(out) << "}" << endl << endl; // Unsetter indent(out) << "public void unset" << cap_name << "() {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "this." << field_name << " = null;" << endl; } else { indent(out) << "__isset_vector[" << isset_field_id(field) << "] = false;" << endl; } indent_down(); indent(out) << "}" << endl << endl; // isSet method indent(out) << "/** Returns true if field " << field_name << " is set (has been assigned a value) and false otherwise */" << endl; indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "return this." << field_name << " != null;" << endl; } else { indent(out) << "return __isset_vector[" << isset_field_id(field) << "];" << endl; } indent_down(); indent(out) << "}" << endl << endl; indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {" << endl; indent_up(); if (type_can_be_null(type)) { indent(out) << "if (!value) {" << endl; indent(out) << " this." << field_name << " = null;" << endl; indent(out) << "}" << endl; } else { indent(out) << "__isset_vector[" << isset_field_id(field) << "] = value;" << endl; } indent_down(); indent(out) << "}" << endl << endl; } } /** * Generates a toString() method for the given struct * * @param tstruct The struct definition */ void t_javame_generator::generate_java_struct_tostring(ostream& out, t_struct* tstruct) { out << indent() << "public String toString() {" << endl; indent_up(); out << indent() << "StringBuffer sb = new StringBuffer(\"" << tstruct->get_name() << "(\");" << endl; out << indent() << "boolean first = true;" << endl << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; if (could_be_unset) { indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; indent_up(); } t_field* field = (*f_iter); if (!first) { indent(out) << "if (!first) sb.append(\", \");" << endl; } indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl; bool can_be_null = type_can_be_null(field->get_type()); if (can_be_null) { indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; indent(out) << " sb.append(\"null\");" << endl; indent(out) << "} else {" << endl; indent_up(); } if (field->get_type()->is_binary()) { indent(out) << "TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl; } else { indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl; } if (can_be_null) { indent_down(); indent(out) << "}" << endl; } indent(out) << "first = false;" << endl; if (could_be_unset) { indent_down(); indent(out) << "}" << endl; } first = false; } out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl; indent_down(); indent(out) << "}" << endl << endl; } /** * Returns a string with the java representation of the given thrift type * (e.g. for the type struct it returns "TType.STRUCT") */ std::string t_javame_generator::get_java_type_string(t_type* type) { if (type->is_list()) { return "TType.LIST"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_enum()) { return "TType.ENUM"; } else if (type->is_typedef()) { return get_java_type_string(((t_typedef*)type)->get_type()); } else if (type->is_base_type()) { switch (((t_base_type*)type)->get_base()) { case t_base_type::TYPE_VOID: return "TType.VOID"; break; case t_base_type::TYPE_STRING: return "TType.STRING"; break; case t_base_type::TYPE_BOOL: return "TType.BOOL"; break; case t_base_type::TYPE_I8: return "TType.BYTE"; break; case t_base_type::TYPE_I16: return "TType.I16"; break; case t_base_type::TYPE_I32: return "TType.I32"; break; case t_base_type::TYPE_I64: return "TType.I64"; break; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; break; default: throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_javame_generator::get_java_type_string!"); break; // This should never happen! } } else { throw std::runtime_error( "Unknown thrift type \"" + type->get_name() + "\" passed to t_javame_generator::get_java_type_string!"); // This should never happen! } } void t_javame_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) { out << endl; indent_up(); indent_up(); if (type->is_struct() || type->is_xception()) { indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type) << ".class"; } else if (type->is_container()) { if (type->is_list()) { indent(out) << "new ListMetaData(TType.LIST, "; t_type* elem_type = ((t_list*)type)->get_elem_type(); generate_field_value_meta_data(out, elem_type); } else if (type->is_set()) { indent(out) << "new SetMetaData(TType.SET, "; t_type* elem_type = ((t_list*)type)->get_elem_type(); generate_field_value_meta_data(out, elem_type); } else { // map indent(out) << "new MapMetaData(TType.MAP, "; t_type* key_type = ((t_map*)type)->get_key_type(); t_type* val_type = ((t_map*)type)->get_val_type(); generate_field_value_meta_data(out, key_type); out << ", "; generate_field_value_meta_data(out, val_type); } } else if (type->is_enum()) { indent(out) << "new EnumMetaData(TType.ENUM, " << type_name(type) << ".class"; } else { indent(out) << "new FieldValueMetaData(" << get_java_type_string(type); if (type->is_typedef()) { indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\""; } } out << ")"; indent_down(); indent_down(); } /** * Generates a thrift service. In C++, this comprises an entirely separate * header and source file. The header file defines the methods and includes * the data types defined in the main header file, and the implementation * file contains implementations of the basic printer and default interfaces. * * @param tservice The service definition */ void t_javame_generator::generate_service(t_service* tservice) { // Make output file string f_service_name = package_dir_ + "/" + service_name_ + ".java"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); f_service_ << "public class " << service_name_ << " {" << endl << endl; indent_up(); // Generate the three main parts of the service generate_service_interface(tservice); generate_service_client(tservice); generate_service_server(tservice); generate_service_helpers(tservice); indent_down(); f_service_ << "}" << endl; f_service_.close(); } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_javame_generator::generate_primitive_service_interface(t_service* tservice) { f_service_ << indent() << "public interface Iface extends " << service_name_ << "Iface { }" << endl << endl; string f_interface_name = package_dir_ + "/" + service_name_ + "Iface.java"; ofstream_with_content_based_conditional_update f_iface; f_iface.open(f_interface_name.c_str()); string extends_iface = ""; if (tservice->get_extends() != nullptr) { extends_iface = " extends " + type_name(tservice->get_extends()) + "Iface"; } f_iface << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports(); generate_java_doc(f_iface, tservice); f_iface << "public interface " << service_name_ << "Iface" << extends_iface << " {" << endl << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_java_doc(f_iface, *f_iter); f_iface << " public " << function_signature(*f_iter) << ";" << endl << endl; } f_iface << "}" << endl << endl; } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_javame_generator::generate_service_interface(t_service* tservice) { string extends = ""; string extends_iface = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_iface = " extends " + extends + ".Iface"; } generate_java_doc(f_service_, tservice); f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_java_doc(f_service_, *f_iter); indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl; } indent_down(); f_service_ << indent() << "}" << endl << endl; } /** * Generates structs for all the service args and return types * * @param tservice The service */ void t_javame_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_java_struct_definition(f_service_, ts, false, true); generate_function_helpers(*f_iter); } } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_javame_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_client = " extends " + extends + ".Client"; } indent(f_service_) << "public static class Client" << extends_client << " implements TServiceClient, Iface {" << endl; indent_up(); indent(f_service_) << "public Client(TProtocol prot)" << endl; scope_up(f_service_); indent(f_service_) << "this(prot, prot);" << endl; scope_down(f_service_); f_service_ << endl; indent(f_service_) << "public Client(TProtocol iprot, TProtocol oprot)" << endl; scope_up(f_service_); if (extends.empty()) { f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl; } else { f_service_ << indent() << "super(iprot, oprot);" << endl; } scope_down(f_service_); f_service_ << endl; if (extends.empty()) { f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent() << "protected TProtocol oprot_;" << endl << endl << indent() << "protected int seqid_;" << endl << endl; indent(f_service_) << "public TProtocol getInputProtocol()" << endl; scope_up(f_service_); indent(f_service_) << "return this.iprot_;" << endl; scope_down(f_service_); f_service_ << endl; indent(f_service_) << "public TProtocol getOutputProtocol()" << endl; scope_up(f_service_); indent(f_service_) << "return this.oprot_;" << endl; scope_down(f_service_); f_service_ << endl; } // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); // Open function indent(f_service_) << "public " << function_signature(*f_iter) << endl; scope_up(f_service_); indent(f_service_) << "send_" << funname << "("; // Get the struct of function call params t_struct* arg_struct = (*f_iter)->get_arglist(); // Declare the function arguments const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; bool first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << (*fld_iter)->get_name(); } f_service_ << ");" << endl; if (!(*f_iter)->is_oneway()) { f_service_ << indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << "return "; } f_service_ << "recv_" << funname << "();" << endl; } scope_down(f_service_); f_service_ << endl; t_function send_function(g_type_void, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); string argsname = (*f_iter)->get_name() + "_args"; // Open function indent(f_service_) << "public " << function_signature(&send_function) << endl; scope_up(f_service_); // Serialize the request f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", " << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") << ", ++seqid_));" << endl << indent() << argsname << " args = new " << argsname << "();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" << (*fld_iter)->get_name() << ");" << endl; } f_service_ << indent() << "args.write(oprot_);" << endl << indent() << "oprot_.writeMessageEnd();" << endl << indent() << "oprot_.getTransport().flush();" << endl; scope_down(f_service_); f_service_ << endl; if (!(*f_iter)->is_oneway()) { string resultname = (*f_iter)->get_name() + "_result"; t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs, (*f_iter)->get_xceptions()); // Open function indent(f_service_) << "public " << function_signature(&recv_function) << endl; scope_up(f_service_); f_service_ << indent() << "TMessage msg = iprot_.readMessageBegin();" << endl << indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl << indent() << " TApplicationException x = TApplicationException.read(iprot_);" << endl << indent() << " iprot_.readMessageEnd();" << endl << indent() << " throw x;" << endl << indent() << "}" << endl << indent() << "if (msg.seqid != seqid_) {" << endl << indent() << " throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, \"" << (*f_iter)->get_name() << " failed: out of sequence response\");" << endl << indent() << "}" << endl << indent() << resultname << " result = new " << resultname << "();" << endl << indent() << "result.read(iprot_);" << endl << indent() << "iprot_.readMessageEnd();" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl << indent() << " return result.success;" << endl << indent() << "}" << endl; } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl << indent() << " throw result." << (*x_iter)->get_name() << ";" << endl << indent() << "}" << endl; } // If you get here it's an exception, unless a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "return;" << endl; } else { f_service_ << indent() << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; } // Close function scope_down(f_service_); f_service_ << endl; } } indent_down(); indent(f_service_) << "}" << endl; } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_javame_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; // Extends stuff string extends = ""; string extends_processor = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_processor = " extends " + extends + ".Processor"; } // Generate the header portion indent(f_service_) << "public static class Processor" << extends_processor << " implements TProcessor {" << endl; indent_up(); indent(f_service_) << "public Processor(Iface iface)" << endl; scope_up(f_service_); if (!extends.empty()) { f_service_ << indent() << "super(iface);" << endl; } f_service_ << indent() << "iface_ = iface;" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl; } scope_down(f_service_); f_service_ << endl; if (extends.empty()) { f_service_ << indent() << "protected static interface ProcessFunction {" << endl << indent() << " public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;" << endl << indent() << "}" << endl << endl; } f_service_ << indent() << "private Iface iface_;" << endl; if (extends.empty()) { f_service_ << indent() << "protected final Hashtable processMap_ = new Hashtable();" << endl; } f_service_ << endl; // Generate the server implementation indent(f_service_) << "public boolean process(TProtocol iprot, TProtocol oprot) throws TException" << endl; scope_up(f_service_); f_service_ << indent() << "TMessage msg = iprot.readMessageBegin();" << endl; // TODO(mcslee): validate message, was the seqid etc. legit? f_service_ << indent() << "ProcessFunction fn = (ProcessFunction)processMap_.get(msg.name);" << endl << indent() << "if (fn == null) {" << endl << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl << indent() << " iprot.readMessageEnd();" << endl << indent() << " TApplicationException x = new " "TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: " "'\"+msg.name+\"'\");" << endl << indent() << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl << indent() << " x.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" << endl << indent() << " oprot.getTransport().flush();" << endl << indent() << " return true;" << endl << indent() << "}" << endl << indent() << "fn.process(msg.seqid, iprot, oprot);" << endl; f_service_ << indent() << "return true;" << endl; scope_down(f_service_); f_service_ << endl; // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } indent_down(); indent(f_service_) << "}" << endl << endl; } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_javame_generator::generate_function_helpers(t_function* tfunction) { if (tfunction->is_oneway()) { return; } t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_java_struct_definition(f_service_, &result, false, true, true); } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_javame_generator::generate_process_function(t_service* tservice, t_function* tfunction) { (void)tservice; // Open class indent(f_service_) << "private class " << tfunction->get_name() << " implements ProcessFunction {" << endl; indent_up(); // Open function indent(f_service_) << "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException" << endl; scope_up(f_service_); string argsname = tfunction->get_name() + "_args"; string resultname = tfunction->get_name() + "_result"; f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl << indent() << "try {" << endl; indent_up(); f_service_ << indent() << "args.read(iprot);" << endl; indent_down(); f_service_ << indent() << "} catch (TProtocolException e) {" << endl; indent_up(); f_service_ << indent() << "iprot.readMessageEnd();" << endl << indent() << "TApplicationException x = new " "TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());" << endl << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << indent() << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() << "oprot.getTransport().flush();" << endl << indent() << "return;" << endl; indent_down(); f_service_ << indent() << "}" << endl; f_service_ << indent() << "iprot.readMessageEnd();" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Declare result for non oneway function if (!tfunction->is_oneway()) { f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl; } // Try block for a function with exceptions if (xceptions.size() > 0) { f_service_ << indent() << "try {" << endl; indent_up(); } // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_service_ << "result.success = "; } f_service_ << "iface_." << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ");" << endl; // Set isset on success field if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) { f_service_ << indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl; } if (!tfunction->is_oneway() && xceptions.size() > 0) { indent_down(); f_service_ << indent() << "}"; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ") {" << endl; if (!tfunction->is_oneway()) { indent_up(); f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl; indent_down(); f_service_ << indent() << "}"; } else { f_service_ << "}"; } } f_service_ << " catch (Throwable th) {" << endl; indent_up(); f_service_ << indent() << "TApplicationException x = new " "TApplicationException(TApplicationException.INTERNAL_ERROR, " "\"Internal error processing " << tfunction->get_name() << "\");" << endl << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << indent() << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() << "oprot.getTransport().flush();" << endl << indent() << "return;" << endl; indent_down(); f_service_ << indent() << "}" << endl; } // Shortcut out here for oneway functions if (tfunction->is_oneway()) { f_service_ << indent() << "return;" << endl; scope_down(f_service_); // Close class indent_down(); f_service_ << indent() << "}" << endl << endl; return; } f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() << "oprot.getTransport().flush();" << endl; // Close function scope_down(f_service_); f_service_ << endl; // Close class indent_down(); f_service_ << indent() << "}" << endl << endl; } /** * Deserializes a field of any type. * * @param tfield The field * @param prefix The variable name or container for this field */ void t_javame_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + tfield->get_name(); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type()) { indent(out) << name << " = iprot."; t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (!type->is_binary()) { out << "readString();"; } else { out << "readBinary();"; } break; case t_base_type::TYPE_BOOL: out << "readBool();"; break; case t_base_type::TYPE_I8: out << "readByte();"; break; case t_base_type::TYPE_I16: out << "readI16();"; break; case t_base_type::TYPE_I32: out << "readI32();"; break; case t_base_type::TYPE_I64: out << "readI64();"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble();"; break; default: throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); } out << endl; } else if (type->is_enum()) { indent(out) << name << " = " << type_name(tfield->get_type(), true, false) + ".findByValue(iprot.readI32());" << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str()); } } /** * Generates an unserializer for a struct, invokes read() */ void t_javame_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent() << prefix << ".read(iprot);" << endl; } /** * Deserializes a container by reading its size and then iterating */ void t_javame_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); string obj; if (ttype->is_map()) { obj = tmp("_map"); } else if (ttype->is_set()) { obj = tmp("_set"); } else if (ttype->is_list()) { obj = tmp("_list"); } // Declare variables, read header if (ttype->is_map()) { indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl; } else if (ttype->is_set()) { indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl; } else if (ttype->is_list()) { indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl; } indent(out) << prefix << " = new " << type_name(ttype, false, true) // size the collection correctly << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size" << ");" << endl; // For loop iterates over elements string i = tmp("_i"); indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size" << "; " << "++" << i << ")" << endl; scope_up(out); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } scope_down(out); // Read container end if (ttype->is_map()) { indent(out) << "iprot.readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "iprot.readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "iprot.readListEnd();" << endl; } scope_down(out); } /** * Generates code to deserialize a map */ void t_javame_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); indent(out) << declare_field(&fkey) << endl; indent(out) << declare_field(&fval) << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); indent(out) << prefix << ".put(" << box_type(tmap->get_key_type(), key) << ", " << box_type(tmap->get_val_type(), val) << ");" << endl; } /** * Deserializes a set element */ void t_javame_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".put(" << box_type(tset->get_elem_type(), elem) << ", " << box_type(tset->get_elem_type(), elem) << ");" << endl; } /** * Deserializes a list element */ void t_javame_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".addElement(" << box_type(tlist->get_elem_type(), elem) << ");" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_javame_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + tfield->get_name()); } else if (type->is_enum()) { indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl; } else if (type->is_base_type()) { string name = prefix + tfield->get_name(); indent(out) << "oprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "writeBinary(" << name << ");"; } else { out << "writeString(" << name << ");"; } break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ");"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ");"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ");"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ");"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ");"; break; default: throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32(" << name << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_javame_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; out << indent() << prefix << ".write(oprot);" << endl; } /** * Serializes a container by writing its size then the elements. * * @param ttype The type of container * @param prefix String prefix for fields */ void t_javame_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); if (ttype->is_map()) { indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".size()));" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix << ".size()));" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListBegin(new TList(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".size()));" << endl; } string iter = tmp("_iter"); if (ttype->is_map()) { string enumer = iter + "_enum"; string key_type = type_name(((t_map*)ttype)->get_key_type(), true, false); indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer << ".hasMoreElements(); ) "; scope_up(out); indent(out) << key_type << " " << iter << " = (" << key_type << ")" << enumer << ".nextElement();" << endl; } else if (ttype->is_set()) { string enumer = iter + "_enum"; string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true); indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer << ".hasMoreElements(); ) "; scope_up(out); indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer << ".nextElement();" << endl; } else if (ttype->is_list()) { string enumer = iter + "_enum"; indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".elements(); " << enumer << ".hasMoreElements(); ) "; scope_up(out); string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true); indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer << ".nextElement();" << endl; } if (ttype->is_map()) { generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); } else if (ttype->is_set()) { generate_serialize_set_element(out, (t_set*)ttype, iter); } else if (ttype->is_list()) { generate_serialize_list_element(out, (t_list*)ttype, iter); } scope_down(out); if (ttype->is_map()) { indent(out) << "oprot.writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListEnd();" << endl; } scope_down(out); } /** * Serializes the members of a map. */ void t_javame_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map) { t_field kfield(tmap->get_key_type(), iter); generate_serialize_field(out, &kfield, ""); string val_type = type_name(tmap->get_val_type(), true, false); t_field vfield(tmap->get_val_type(), "((" + val_type + ")" + map + ".get(" + iter + "))"); generate_serialize_field(out, &vfield, ""); } /** * Serializes the members of a set. */ void t_javame_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Serializes the members of a list. */ void t_javame_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Returns a Java type name * * @param ttype The type * @param container Is the type going inside a container? * @return Java type name, i.e. Vector */ string t_javame_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool skip_generic) { (void)in_init; (void)skip_generic; // In Java typedefs are just resolved to their real type ttype = get_true_type(ttype); string prefix; if (ttype->is_base_type()) { return base_type_name((t_base_type*)ttype, in_container); } else if (ttype->is_map()) { return "Hashtable"; } else if (ttype->is_set()) { return "Hashtable"; } else if (ttype->is_list()) { return "Vector"; } // Check for namespacing t_program* program = ttype->get_program(); if (program != nullptr && program != program_) { string package = program->get_namespace("java"); if (!package.empty()) { return package + "." + ttype->get_name(); } } return ttype->get_name(); } /** * Returns the C++ type that corresponds to the thrift type. * * @param tbase The base type * @param container Is it going in a Java container? */ string t_javame_generator::base_type_name(t_base_type* type, bool in_container) { t_base_type::t_base tbase = type->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: if (!type->is_binary()) { return "String"; } else { return "byte[]"; } case t_base_type::TYPE_BOOL: return (in_container ? "Boolean" : "boolean"); case t_base_type::TYPE_I8: return (in_container ? "Byte" : "byte"); case t_base_type::TYPE_I16: return (in_container ? "Short" : "short"); case t_base_type::TYPE_I32: return (in_container ? "Integer" : "int"); case t_base_type::TYPE_I64: return (in_container ? "Long" : "long"); case t_base_type::TYPE_DOUBLE: return (in_container ? "Double" : "double"); default: throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase); } } /** * Declares a field, which may include initialization as necessary. * * @param ttype The type */ string t_javame_generator::declare_field(t_field* tfield, bool init) { // TODO(mcslee): do we ever need to initialize the field? string result = type_name(tfield->get_type()) + " " + tfield->get_name(); if (init) { t_type* ttype = get_true_type(tfield->get_type()); if (ttype->is_base_type() && tfield->get_value() != nullptr) { std::ofstream dummy; result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); } else if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: result += " = null"; break; case t_base_type::TYPE_BOOL: result += " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = (double)0"; break; } } else if (ttype->is_enum()) { result += " = 0"; } else if (ttype->is_container()) { result += " = new " + type_name(ttype, false, true) + "()"; } else { result += " = new " + type_name(ttype, false, true) + "()"; ; } } return result + ";"; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_javame_generator::function_signature(t_function* tfunction, string prefix) { t_type* ttype = tfunction->get_returntype(); std::string result = type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws "; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { result += type_name((*x_iter)->get_type(), false, false) + ", "; } result += "TException"; return result; } /** * Renders a comma separated field list, with type names */ string t_javame_generator::argument_list(t_struct* tstruct, bool include_types) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } if (include_types) { result += type_name((*f_iter)->get_type()) + " "; } result += (*f_iter)->get_name(); } return result; } /** * Converts the parse type to a C++ enum string for the given type. */ string t_javame_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.STRING"; case t_base_type::TYPE_BOOL: return "TType.BOOL"; case t_base_type::TYPE_I8: return "TType.BYTE"; case t_base_type::TYPE_I16: return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; } } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_list()) { return "TType.LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Applies the correct style to a string based on the value of nocamel_style_ */ std::string t_javame_generator::get_cap_name(std::string name) { name[0] = toupper(name[0]); return name; } string t_javame_generator::constant_name(string name) { string constant_name; bool is_first = true; bool was_previous_char_upper = false; for (char character : name) { bool is_upper = isupper(character); if (is_upper && !is_first && !was_previous_char_upper) { constant_name += '_'; } constant_name += toupper(character); is_first = false; was_previous_char_upper = is_upper; } return constant_name; } void t_javame_generator::generate_java_docstring_comment(ostream& out, string contents) { generate_docstring_comment(out, "/**\n", " * ", contents, " */\n"); } void t_javame_generator::generate_java_doc(ostream& out, t_field* field) { if (field->get_type()->is_enum()) { string combined_message = field->get_doc() + "\n@see " + get_enum_class_name(field->get_type()); generate_java_docstring_comment(out, combined_message); } else { generate_java_doc(out, (t_doc*)field); } } /** * Emits a JavaDoc comment if the provided object has a doc in Thrift */ void t_javame_generator::generate_java_doc(ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_java_docstring_comment(out, tdoc->get_doc()); } } /** * Emits a JavaDoc comment if the provided function object has a doc in Thrift */ void t_javame_generator::generate_java_doc(ostream& out, t_function* tfunction) { if (tfunction->has_doc()) { stringstream ss; ss << tfunction->get_doc(); const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; ss << "\n@param " << p->get_name(); if (p->has_doc()) { ss << " " << p->get_doc(); } } generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); } } void t_javame_generator::generate_deep_copy_container(ostream& out, std::string source_name_p1, std::string source_name_p2, std::string result_name, t_type* type) { t_container* container = (t_container*)type; std::string source_name; if (source_name_p2 == "") source_name = source_name_p1; else source_name = source_name_p1 + "." + source_name_p2; indent(out) << type_name(type, true, false) << " " << result_name << " = new " << type_name(container, false, true) << "();" << endl; std::string iterator_element_name = source_name_p1 + "_element"; std::string enumeration_name = source_name_p1 + "_enum"; std::string result_element_name = result_name + "_copy"; if (container->is_map()) { t_type* key_type = ((t_map*)container)->get_key_type(); t_type* val_type = ((t_map*)container)->get_val_type(); indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name << ".keys(); " << enumeration_name << ".hasMoreElements(); ) {" << endl; indent_up(); out << endl; indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = (" << type_name(key_type, true, false) << ")" << enumeration_name << ".nextElement();" << endl; indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = (" << type_name(val_type, true, false) << ")" << source_name << ".get(" << iterator_element_name << "_key);" << endl; out << endl; if (key_type->is_container()) { generate_deep_copy_container(out, iterator_element_name + "_key", "", result_element_name + "_key", key_type); } else { indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = "; generate_deep_copy_non_container(out, iterator_element_name + "_key", result_element_name + "_key", key_type); out << ";" << endl; } out << endl; if (val_type->is_container()) { generate_deep_copy_container(out, iterator_element_name + "_value", "", result_element_name + "_value", val_type); } else { indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = "; generate_deep_copy_non_container(out, iterator_element_name + "_value", result_element_name + "_value", val_type); out << ";" << endl; } out << endl; indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name << "_value);" << endl; indent_down(); indent(out) << "}" << endl; } else { t_type* elem_type; if (container->is_set()) { elem_type = ((t_set*)container)->get_elem_type(); } else { elem_type = ((t_list*)container)->get_elem_type(); } indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name << ".elements(); " << enumeration_name << ".hasMoreElements(); ) {" << endl; indent_up(); indent(out) << type_name(elem_type, true, false) << " " << iterator_element_name << " = (" << type_name(elem_type, true, false) << ")" << enumeration_name << ".nextElement();" << endl; if (elem_type->is_container()) { // recursive deep copy generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type); if (elem_type->is_list()) { indent(out) << result_name << ".addElement(" << result_element_name << ");" << endl; } else { indent(out) << result_name << ".put(" << result_element_name << ", " << result_element_name << ");" << endl; } } else { // iterative copy if (elem_type->is_binary()) { indent(out) << type_name(elem_type, true, false) << " temp_binary_element = "; generate_deep_copy_non_container(out, iterator_element_name, "temp_binary_element", elem_type); out << ";" << endl; if (elem_type->is_list()) { indent(out) << result_name << ".addElement(temp_binary_element);" << endl; } else { indent(out) << result_name << ".put(temp_binary_element, temp_binary_element);" << endl; } } else { indent(out) << result_name << ".addElement("; generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type); out << ");" << endl; } } indent_down(); indent(out) << "}" << endl; } } void t_javame_generator::generate_deep_copy_non_container(ostream& out, std::string source_name, std::string dest_name, t_type* type) { if (type->is_base_type() || type->is_enum() || type->is_typedef()) { // binary fields need to be copied with System.arraycopy if (type->is_binary()) { out << "new byte[" << source_name << ".length];" << endl; indent(out) << "System.arraycopy(" << source_name << ", 0, " << dest_name << ", 0, " << source_name << ".length)"; } // everything else can be copied directly else out << source_name; } else { out << "new " << type_name(type, true, true) << "(" << source_name << ")"; } } std::string t_javame_generator::generate_isset_check(t_field* field) { return generate_isset_check(field->get_name()); } std::string t_javame_generator::isset_field_id(t_field* field) { return "__" + upcase_string(field->get_name() + "_isset_id"); } std::string t_javame_generator::generate_isset_check(std::string field_name) { return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; } void t_javame_generator::generate_isset_set(ostream& out, t_field* field) { if (!type_can_be_null(field->get_type())) { indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(true);" << endl; } } std::string t_javame_generator::get_enum_class_name(t_type* type) { string package = ""; t_program* program = type->get_program(); if (program != nullptr && program != program_) { package = program->get_namespace("java") + "."; } return package + type->get_name(); } void t_javame_generator::generate_struct_desc(ostream& out, t_struct* tstruct) { indent(out) << "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() << "\");" << endl; } void t_javame_generator::generate_field_descs(ostream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << "private static final TField " << constant_name((*m_iter)->get_name()) << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " << type_to_enum((*m_iter)->get_type()) << ", " << "(short)" << (*m_iter)->get_key() << ");" << endl; } } bool t_javame_generator::has_bit_vector(t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) { return true; } } return false; } void t_javame_generator::generate_java_struct_clear(std::ostream& out, t_struct* tstruct) { indent(out) << "public void clear() {" << endl; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr) { print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true); } else { if (type_can_be_null(t)) { indent(out) << "this." << (*m_iter)->get_name() << " = null;" << endl; } else { // must be a base type // means it also needs to be explicitly unset indent(out) << "set" << get_cap_name((*m_iter)->get_name()) << get_cap_name("isSet") << "(false);" << endl; switch (((t_base_type*)t)->get_base()) { case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: indent(out) << "this." << (*m_iter)->get_name() << " = 0;" << endl; break; case t_base_type::TYPE_DOUBLE: indent(out) << "this." << (*m_iter)->get_name() << " = 0.0;" << endl; break; case t_base_type::TYPE_BOOL: indent(out) << "this." << (*m_iter)->get_name() << " = false;" << endl; break; default: // prevent gcc compiler warning break; } } } } indent_down(); indent(out) << "}" << endl << endl; } THRIFT_REGISTER_GENERATOR(javame, "Java ME", "") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_js_generator.cc000066400000000000000000003125011420101504100246550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::unordered_map; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes static const string episode_file_name = "thrift.js.episode"; // largest consecutive integer representable by a double (2 ^ 53 - 1) static const int64_t max_safe_integer = 0x1fffffffffffff; // smallest consecutive number representable by a double (-2 ^ 53 + 1) static const int64_t min_safe_integer = -max_safe_integer; #include "thrift/generate/t_oop_generator.h" /** * JS code generator. */ class t_js_generator : public t_oop_generator { public: t_js_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; gen_node_ = false; gen_jquery_ = false; gen_ts_ = false; gen_es6_ = false; gen_episode_file_ = false; bool with_ns_ = false; for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("node") == 0) { gen_node_ = true; } else if( iter->first.compare("jquery") == 0) { gen_jquery_ = true; } else if( iter->first.compare("ts") == 0) { gen_ts_ = true; } else if( iter->first.compare("with_ns") == 0) { with_ns_ = true; } else if( iter->first.compare("es6") == 0) { gen_es6_ = true; } else if( iter->first.compare("imports") == 0) { parse_imports(program, iter->second); } else if (iter->first.compare("thrift_package_output_directory") == 0) { parse_thrift_package_output_directory(iter->second); } else { throw std::invalid_argument("unknown option js:" + iter->first); } } if (gen_es6_ && gen_jquery_) { throw std::invalid_argument("invalid switch: [-gen js:es6,jquery] options not compatible"); } if (gen_node_ && gen_jquery_) { throw std::invalid_argument("invalid switch: [-gen js:node,jquery] options not compatible, try: [-gen js:node -gen " "js:jquery]"); } if (!gen_node_ && with_ns_) { throw std::invalid_argument("invalid switch: [-gen js:with_ns] is only valid when using node.js"); } // Depending on the processing flags, we will update these to be ES6 compatible js_const_type_ = "var "; js_let_type_ = "var "; js_var_type_ = "var "; if (gen_es6_) { js_const_type_ = "const "; js_let_type_ = "let "; } if (gen_node_) { out_dir_base_ = "gen-nodejs"; no_ns_ = !with_ns_; } else { out_dir_base_ = "gen-js"; no_ns_ = false; } escape_['\''] = "\\'"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; std::string render_recv_throw(std::string var); std::string render_recv_return(std::string var); std::string render_const_value(t_type* type, t_const_value* value); /** * Structs! */ void generate_js_struct(t_struct* tstruct, bool is_exception); void generate_js_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool is_exported = true); void generate_js_struct_reader(std::ostream& out, t_struct* tstruct); void generate_js_struct_writer(std::ostream& out, t_struct* tstruct); void generate_js_function_helpers(t_function* tfunction); /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_rest(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_processor(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", bool inclass = false); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); /** * Helper rendering functions */ std::string js_includes(); std::string ts_includes(); std::string ts_service_includes(); std::string render_includes(); std::string render_ts_includes(); std::string get_import_path(t_program* program); std::string declare_field(t_field* tfield, bool init = false, bool obj = false); std::string function_signature(t_function* tfunction, std::string prefix = "", bool include_callback = false); std::string argument_list(t_struct* tstruct, bool include_callback = false); std::string type_to_enum(t_type* ttype); std::string make_valid_nodeJs_identifier(std::string const& name); std::string next_identifier_name(std::vector const& fields, std::string const& base_name); bool find_field(std::vector const& fields, std::string const& name); /** * Helper parser functions */ void parse_imports(t_program* program, const std::string& imports_string); void parse_thrift_package_output_directory(const std::string& thrift_package_output_directory); std::string autogen_comment() override { return std::string("//\n") + "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "//\n" + "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "//\n"; } t_type* get_contained_type(t_type* t); std::vector js_namespace_pieces(t_program* p) { std::string ns = p->get_namespace("js"); std::string::size_type loc; std::vector pieces; if (no_ns_) { return pieces; } if (ns.size() > 0) { while ((loc = ns.find(".")) != std::string::npos) { pieces.push_back(ns.substr(0, loc)); ns = ns.substr(loc + 1); } } if (ns.size() > 0) { pieces.push_back(ns); } return pieces; } std::string js_type_namespace(t_program* p) { if (gen_node_) { if (p != nullptr && p != program_) { return make_valid_nodeJs_identifier(p->get_name()) + "_ttypes."; } return "ttypes."; } return js_namespace(p); } std::string js_export_namespace(t_program* p) { if (gen_node_) { return "exports."; } return js_namespace(p); } bool has_js_namespace(t_program* p) { if (no_ns_) { return false; } std::string ns = p->get_namespace("js"); return (ns.size() > 0); } std::string js_namespace(t_program* p) { if (no_ns_) { return ""; } std::string ns = p->get_namespace("js"); if (ns.size() > 0) { ns += "."; } return ns; } /** * TypeScript Definition File helper functions */ string ts_function_signature(t_function* tfunction, bool include_callback); string ts_get_type(t_type* type); /** * Special indentation for TypeScript Definitions because of the module. * Returns the normal indentation + " " if a module was defined. * @return string */ string ts_indent() { return indent() + (!ts_module_.empty() ? " " : ""); } /** * Returns "declare " if no module was defined. * @return string */ string ts_declare() { return (ts_module_.empty() ? (gen_node_ ? "declare " : "export declare ") : ""); } /** * Returns "?" if the given field is optional or has a default value. * @param t_field The field to check * @return string */ string ts_get_req(t_field* field) {return (field->get_req() == t_field::T_OPTIONAL || field->get_value() != nullptr ? "?" : ""); } /** * Returns the documentation, if the provided documentable object has one. * @param t_doc The object to get the documentation from * @return string The documentation */ string ts_print_doc(t_doc* tdoc) { string result = endl; if (tdoc->has_doc()) { std::stringstream doc(tdoc->get_doc()); string item; result += ts_indent() + "/**" + endl; while (std::getline(doc, item)) { result += ts_indent() + " * " + item + endl; } result += ts_indent() + " */" + endl; } return result; } private: /** * True if we should generate NodeJS-friendly RPC services. */ bool gen_node_; /** * True if we should generate services that use jQuery ajax (async/sync). */ bool gen_jquery_; /** * True if we should generate a TypeScript Definition File for each service. */ bool gen_ts_; /** * True if we should generate ES6 code, i.e. with Promises */ bool gen_es6_; /** * True if we will generate an episode file. */ bool gen_episode_file_; /** * The name of the defined module(s), for TypeScript Definition Files. */ string ts_module_; /** * True if we should not generate namespace objects for node. */ bool no_ns_; /** * The node modules to use when importing the previously generated files. */ vector imports; /** * Cache for imported modules. */ unordered_map module_name_2_import_path; /** * Cache for TypeScript includes to generated import name. */ unordered_map include_2_import_name; /** * The prefix to use when generating the episode file. */ string thrift_package_output_directory_; /** * The variable decorator for "const" variables. Will default to "var" if in an incompatible language. */ string js_const_type_; /** * The variable decorator for "let" variables. Will default to "var" if in an incompatible language. */ string js_let_type_; /** * The default variable decorator. Supports all javascript languages, but is not scoped to functions or closures. */ string js_var_type_; /** * File streams */ ofstream_with_content_based_conditional_update f_episode_; ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_service_; ofstream_with_content_based_conditional_update f_types_ts_; ofstream_with_content_based_conditional_update f_service_ts_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_js_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); const auto outdir = get_out_dir(); // Make output file(s) if (gen_episode_file_) { const auto f_episode_file_path = outdir + episode_file_name; f_episode_.open(f_episode_file_path); } const auto f_types_name = outdir + program_->get_name() + "_types.js"; f_types_.open(f_types_name.c_str()); if (gen_episode_file_) { const auto types_module = program_->get_name() + "_types"; f_episode_ << types_module << ":" << thrift_package_output_directory_ << "/" << types_module << endl; } if (gen_ts_) { const auto f_types_ts_name = outdir + program_->get_name() + "_types.d.ts"; f_types_ts_.open(f_types_ts_name.c_str()); } // Print header f_types_ << autogen_comment(); if ((gen_node_ || gen_es6_) && no_ns_) { f_types_ << "\"use strict\";" << endl << endl; } f_types_ << js_includes() << endl << render_includes() << endl; if (gen_ts_) { f_types_ts_ << autogen_comment() << ts_includes() << endl << render_ts_includes() << endl; } if (gen_node_) { f_types_ << js_const_type_ << "ttypes = module.exports = {};" << endl; } string pns; // setup the namespace // TODO should the namespace just be in the directory structure for node? vector ns_pieces = js_namespace_pieces(program_); if (ns_pieces.size() > 0) { for (size_t i = 0; i < ns_pieces.size(); ++i) { pns += ((i == 0) ? "" : ".") + ns_pieces[i]; f_types_ << "if (typeof " << pns << " === 'undefined') {" << endl; f_types_ << " " << pns << " = {};" << endl; f_types_ << "}" << endl; f_types_ << "" << "if (typeof module !== 'undefined' && module.exports) {" << endl; f_types_ << " module.exports." << pns << " = " << pns << ";" << endl << "}" << endl; } if (gen_ts_) { ts_module_ = pns; f_types_ts_ << "declare module " << ts_module_ << " {"; } } } /** * Prints standard js imports */ string t_js_generator::js_includes() { if (gen_node_) { string result = js_const_type_ + "thrift = require('thrift');\n" + js_const_type_ + "Thrift = thrift.Thrift;\n"; if (!gen_es6_) { result += js_const_type_ + "Q = thrift.Q;\n"; } result += js_const_type_ + "Int64 = require('node-int64');\n"; return result; } string result = "if (typeof Int64 === 'undefined' && typeof require === 'function') {\n " + js_const_type_ + "Int64 = require('node-int64');\n}\n"; return result; } /** * Prints standard ts imports */ string t_js_generator::ts_includes() { if (gen_node_) { return string( "import thrift = require('thrift');\n" "import Thrift = thrift.Thrift;\n" "import Q = thrift.Q;\n" "import Int64 = require('node-int64');"); } return string("import Int64 = require('node-int64');"); } /** * Prints service ts imports */ string t_js_generator::ts_service_includes() { if (gen_node_) { return string( "import thrift = require('thrift');\n" "import Thrift = thrift.Thrift;\n" "import Q = thrift.Q;\n" "import Int64 = require('node-int64');"); } return string("import Int64 = require('node-int64');"); } /** * Renders all the imports necessary for including another Thrift program */ string t_js_generator::render_includes() { string result = ""; if (gen_node_) { const vector& includes = program_->get_includes(); for (auto include : includes) { result += js_const_type_ + make_valid_nodeJs_identifier(include->get_name()) + "_ttypes = require('" + get_import_path(include) + "');\n"; } if (includes.size() > 0) { result += "\n"; } } return result; } /** * Renders all the imports necessary for including another Thrift program */ string t_js_generator::render_ts_includes() { string result; if (!gen_node_) { return result; } const vector& includes = program_->get_includes(); for (auto include : includes) { string include_name = make_valid_nodeJs_identifier(include->get_name()) + "_ttypes"; include_2_import_name.insert({include, include_name}); result += "import " + include_name + " = require('" + get_import_path(include) + "');\n"; } if (includes.size() > 0) { result += "\n"; } return result; } string t_js_generator::get_import_path(t_program* program) { const string import_file_name(program->get_name() + "_types"); if (program->get_recursive()) { return "./" + import_file_name; } const string import_file_name_with_extension = import_file_name + ".js"; auto module_name_and_import_path_iterator = module_name_2_import_path.find(import_file_name); if (module_name_and_import_path_iterator != module_name_2_import_path.end()) { return module_name_and_import_path_iterator->second; } return "./" + import_file_name; } /** * Close up (or down) some filez. */ void t_js_generator::close_generator() { // Close types file(s) f_types_.close(); if (gen_ts_) { if (!ts_module_.empty()) { f_types_ts_ << "}"; } f_types_ts_.close(); } if (gen_episode_file_){ f_episode_.close(); } } /** * Generates a typedef. This is not done in JS, types are all implicit. * * @param ttypedef The type definition */ void t_js_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Generates code for an enumerated type. Since define is expensive to lookup * in JS, we use a global array for this. * * @param tenum The enumeration */ void t_js_generator::generate_enum(t_enum* tenum) { f_types_ << js_type_namespace(tenum->get_program()) << tenum->get_name() << " = {" << endl; if (gen_ts_) { f_types_ts_ << ts_print_doc(tenum) << ts_indent() << ts_declare() << "enum " << tenum->get_name() << " {" << endl; } indent_up(); vector const& constants = tenum->get_constants(); vector::const_iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); if (gen_ts_) { f_types_ts_ << ts_indent() << (*c_iter)->get_name() << " = " << value << "," << endl; // add 'value: key' in addition to 'key: value' for TypeScript enums f_types_ << indent() << "'" << value << "' : '" << (*c_iter)->get_name() << "'," << endl; } f_types_ << indent() << "'" << (*c_iter)->get_name() << "' : " << value; if (c_iter != constants.end() - 1) { f_types_ << ","; } f_types_ << endl; } indent_down(); f_types_ << "};" << endl; if (gen_ts_) { f_types_ts_ << ts_indent() << "}" << endl; } } /** * Generate a constant value */ void t_js_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); f_types_ << js_type_namespace(program_) << name << " = "; f_types_ << render_const_value(type, value) << ";" << endl; if (gen_ts_) { f_types_ts_ << ts_print_doc(tconst) << ts_indent() << ts_declare() << js_const_type_ << name << ": " << ts_get_type(type) << ";" << endl; } } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_js_generator::render_const_value(t_type* type, t_const_value* value) { std::ostringstream out; type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << "'" << get_escaped_string(value) << "'"; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: out << value->get_integer(); break; case t_base_type::TYPE_I64: { int64_t const& integer_value = value->get_integer(); if (integer_value <= max_safe_integer && integer_value >= min_safe_integer) { out << "new Int64(" << integer_value << ")"; } else { out << "new Int64('" << std::hex << integer_value << std::dec << "')"; } } break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << emit_double_as_string(value->get_double()); } break; default: throw std::runtime_error("compiler error: no const of base type " + t_base_type::t_base_name(tbase)); } } else if (type->is_enum()) { out << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << "new " << js_type_namespace(type->get_program()) << type->get_name() << "({"; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw std::runtime_error("type error: " + type->get_name() + " has no field " + v_iter->first->get_string()); } if (v_iter != val.begin()) out << ","; out << endl << indent() << render_const_value(g_type_string, v_iter->first); out << " : "; out << render_const_value(field_type, v_iter->second); } indent_down(); out << endl << indent() << "})"; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); out << "{" << endl; indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { if (v_iter != val.begin()) out << "," << endl; if (ktype->is_base_type() && ((t_base_type*)get_true_type(ktype))->get_base() == t_base_type::TYPE_I64){ out << indent() << "\"" << v_iter->first->get_integer() << "\""; } else { out << indent() << render_const_value(ktype, v_iter->first); } out << " : "; out << render_const_value(vtype, v_iter->second); } indent_down(); out << endl << indent() << "}"; } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } out << "["; const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { if (v_iter != val.begin()) out << ","; out << render_const_value(etype, *v_iter); } out << "]"; } return out.str(); } /** * Make a struct */ void t_js_generator::generate_struct(t_struct* tstruct) { generate_js_struct(tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_js_generator::generate_xception(t_struct* txception) { generate_js_struct(txception, true); } /** * Structs can be normal or exceptions. */ void t_js_generator::generate_js_struct(t_struct* tstruct, bool is_exception) { generate_js_struct_definition(f_types_, tstruct, is_exception); } /** * Return type of contained elements for a container type. For maps * this is type of value (keys are always strings in js) */ t_type* t_js_generator::get_contained_type(t_type* t) { t_type* etype; if (t->is_list()) { etype = ((t_list*)t)->get_elem_type(); } else if (t->is_set()) { etype = ((t_set*)t)->get_elem_type(); } else { etype = ((t_map*)t)->get_val_type(); } return etype; } /** * Generates a struct definition for a thrift data type. This is nothing in JS * where the objects are all just associative arrays (unless of course we * decide to start using objects for them...) * * @param tstruct The struct definition */ void t_js_generator::generate_js_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool is_exported) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; if (gen_node_) { string prefix = has_js_namespace(tstruct->get_program()) ? js_namespace(tstruct->get_program()) : js_const_type_; out << prefix << tstruct->get_name() << (is_exported ? " = module.exports." + tstruct->get_name() : ""); if (gen_ts_) { f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << "class " << tstruct->get_name() << (is_exception ? " extends Thrift.TException" : "") << " {" << endl; } } else { out << js_namespace(tstruct->get_program()) << tstruct->get_name(); if (gen_ts_) { f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << "class " << tstruct->get_name() << (is_exception ? " extends Thrift.TException" : "") << " {" << endl; } } if (gen_es6_) { if (gen_node_ && is_exception) { out << " = class extends Thrift.TException {" << endl; } else { out << " = class {" << endl; } indent_up(); indent(out) << "constructor(args) {" << endl; } else { out << " = function(args) {" << endl; } indent_up(); // Call super() method on inherited Error class if (gen_node_ && is_exception) { if (gen_es6_) { indent(out) << "super(args);" << endl; } else { indent(out) << "Thrift.TException.call(this, \"" << js_namespace(tstruct->get_program()) << tstruct->get_name() << "\");" << endl; } out << indent() << "this.name = \"" << js_namespace(tstruct->get_program()) << tstruct->get_name() << "\";" << endl; } // members with arguments for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { string dval = declare_field(*m_iter, false, true); t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr && !(t->is_struct() || t->is_xception())) { dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value()); out << indent() << "this." << (*m_iter)->get_name() << " = " << dval << ";" << endl; } else { out << indent() << dval << ";" << endl; } if (gen_ts_) { string ts_access = gen_node_ ? "public " : ""; f_types_ts_ << ts_indent() << ts_access << (*m_iter)->get_name() << ts_get_req(*m_iter) << ": " << ts_get_type((*m_iter)->get_type()) << ";" << endl; } } // Generate constructor from array if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr && (t->is_struct() || t->is_xception())) { indent(out) << "this." << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl; } } // Early returns for exceptions for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if (t->is_xception()) { out << indent() << "if (args instanceof " << js_type_namespace(t->get_program()) << t->get_name() << ") {" << endl << indent() << indent() << "this." << (*m_iter)->get_name() << " = args;" << endl << indent() << indent() << "return;" << endl << indent() << "}" << endl; } } indent(out) << "if (args) {" << endl; indent_up(); if (gen_ts_) { f_types_ts_ << endl << ts_indent() << "constructor(args?: { "; } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); indent(out) << "if (args." << (*m_iter)->get_name() << " !== undefined && args." << (*m_iter)->get_name() << " !== null) {" << endl; indent_up(); indent(out) << "this." << (*m_iter)->get_name(); if (t->is_struct()) { out << (" = new " + js_type_namespace(t->get_program()) + t->get_name() + "(args."+(*m_iter)->get_name() +");"); out << endl; } else if (t->is_container()) { t_type* etype = get_contained_type(t); string copyFunc = t->is_map() ? "Thrift.copyMap" : "Thrift.copyList"; string type_list = ""; while (etype->is_container()) { if (type_list.length() > 0) { type_list += ", "; } type_list += etype->is_map() ? "Thrift.copyMap" : "Thrift.copyList"; etype = get_contained_type(etype); } if (etype->is_struct()) { if (type_list.length() > 0) { type_list += ", "; } type_list += js_type_namespace(etype->get_program()) + etype->get_name(); } else { if (type_list.length() > 0) { type_list += ", "; } type_list += "null"; } out << (" = " + copyFunc + "(args." + (*m_iter)->get_name() + ", [" + type_list + "]);"); out << endl; } else { out << " = args." << (*m_iter)->get_name() << ";" << endl; } indent_down(); if (!(*m_iter)->get_req()) { indent(out) << "} else {" << endl; indent(out) << " throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, " "'Required field " << (*m_iter)->get_name() << " is unset!');" << endl; } indent(out) << "}" << endl; if (gen_ts_) { f_types_ts_ << (*m_iter)->get_name() << ts_get_req(*m_iter) << ": " << ts_get_type((*m_iter)->get_type()) << "; "; } } indent_down(); out << indent() << "}" << endl; if (gen_ts_) { f_types_ts_ << "});" << endl; } } // Done with constructor indent_down(); if (gen_es6_) { indent(out) << "}" << endl << endl; } else { indent(out) << "};" << endl; } if (gen_ts_) { f_types_ts_ << ts_indent() << "}" << endl; } if (!gen_es6_) { if (is_exception) { out << "Thrift.inherits(" << js_namespace(tstruct->get_program()) << tstruct->get_name() << ", Thrift.TException);" << endl; out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype.name = '" << tstruct->get_name() << "';" << endl; } else { // init prototype manually if we aren't using es6 out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype = {};" << endl; } } generate_js_struct_reader(out, tstruct); generate_js_struct_writer(out, tstruct); // Close out the class definition if (gen_es6_) { indent_down(); indent(out) << "};" << endl; } } /** * Generates the read() method for a struct */ void t_js_generator::generate_js_struct_reader(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; if (gen_es6_) { indent(out) << "read (input) {" << endl; } else { indent(out) << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype.read = function(input) {" << endl; } indent_up(); indent(out) << "input.readStructBegin();" << endl; // Loop over reading in fields indent(out) << "while (true) {" << endl; indent_up(); indent(out) << js_const_type_ << "ret = input.readFieldBegin();" << endl; indent(out) << js_const_type_ << "ftype = ret.ftype;" << endl; if (!fields.empty()) { indent(out) << js_const_type_ << "fid = ret.fid;" << endl; } // Check for field STOP marker and break indent(out) << "if (ftype == Thrift.Type.STOP) {" << endl; indent_up(); indent(out) << "break;" << endl; indent_down(); indent(out) << "}" << endl; if (!fields.empty()) { // Switch statement on the field we are reading indent(out) << "switch (fid) {" << endl; indent_up(); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); generate_deserialize_field(out, *f_iter, "this."); indent_down(); indent(out) << "} else {" << endl; indent(out) << " input.skip(ftype);" << endl; out << indent() << "}" << endl << indent() << "break;" << endl; } if (fields.size() == 1) { // pseudo case to make jslint happy indent(out) << "case 0:" << endl; indent(out) << " input.skip(ftype);" << endl; indent(out) << " break;" << endl; } // In the default case we skip the field indent(out) << "default:" << endl; indent(out) << " input.skip(ftype);" << endl; scope_down(out); } else { indent(out) << "input.skip(ftype);" << endl; } indent(out) << "input.readFieldEnd();" << endl; scope_down(out); indent(out) << "input.readStructEnd();" << endl; indent(out) << "return;" << endl; indent_down(); if (gen_es6_) { indent(out) << "}" << endl << endl; } else { indent(out) << "};" << endl << endl; } } /** * Generates the write() method for a struct */ void t_js_generator::generate_js_struct_writer(ostream& out, t_struct* tstruct) { string name = tstruct->get_name(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; if (gen_es6_) { indent(out) << "write (output) {" << endl; } else { indent(out) << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype.write = function(output) {" << endl; } indent_up(); indent(out) << "output.writeStructBegin('" << name << "');" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { out << indent() << "if (this." << (*f_iter)->get_name() << " !== null && this." << (*f_iter)->get_name() << " !== undefined) {" << endl; indent_up(); indent(out) << "output.writeFieldBegin(" << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ");" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this."); indent(out) << "output.writeFieldEnd();" << endl; indent_down(); indent(out) << "}" << endl; } out << indent() << "output.writeFieldStop();" << endl << indent() << "output.writeStructEnd();" << endl; out << indent() << "return;" << endl; indent_down(); if (gen_es6_) { out << indent() << "}" << endl << endl; } else { out << indent() << "};" << endl << endl; } } /** * Generates a thrift service. * * @param tservice The service definition */ void t_js_generator::generate_service(t_service* tservice) { string f_service_name = get_out_dir() + service_name_ + ".js"; f_service_.open(f_service_name.c_str()); if (gen_episode_file_) { f_episode_ << service_name_ << ":" << thrift_package_output_directory_ << "/" << service_name_ << endl; } if (gen_ts_) { string f_service_ts_name = get_out_dir() + service_name_ + ".d.ts"; f_service_ts_.open(f_service_ts_name.c_str()); } f_service_ << autogen_comment(); if ((gen_node_ || gen_es6_) && no_ns_) { f_service_ << "\"use strict\";" << endl << endl; } f_service_ << js_includes() << endl << render_includes() << endl; if (gen_ts_) { if (tservice->get_extends() != nullptr) { f_service_ts_ << "/// get_extends()->get_name() << ".d.ts\" />" << endl; } f_service_ts_ << autogen_comment() << endl << ts_includes() << endl << render_ts_includes() << endl; if (gen_node_) { f_service_ts_ << "import ttypes = require('./" + program_->get_name() + "_types');" << endl; // Generate type aliases // enum vector const& enums = program_->get_enums(); vector::const_iterator e_iter; for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) { f_service_ts_ << "import " << (*e_iter)->get_name() << " = ttypes." << js_namespace(program_) << (*e_iter)->get_name() << endl; } // const vector const& consts = program_->get_consts(); vector::const_iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { f_service_ts_ << "import " << (*c_iter)->get_name() << " = ttypes." << js_namespace(program_) << (*c_iter)->get_name() << endl; } // exception vector const& exceptions = program_->get_xceptions(); vector::const_iterator x_iter; for (x_iter = exceptions.begin(); x_iter != exceptions.end(); ++x_iter) { f_service_ts_ << "import " << (*x_iter)->get_name() << " = ttypes." << js_namespace(program_) << (*x_iter)->get_name() << endl; } // structs vector const& structs = program_->get_structs(); vector::const_iterator s_iter; for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) { f_service_ts_ << "import " << (*s_iter)->get_name() << " = ttypes." << js_namespace(program_) << (*s_iter)->get_name() << endl; } } else { f_service_ts_ << "import { " << program_->get_name() << " } from \"./" << program_->get_name() << "_types\";" << endl << endl; } if (!ts_module_.empty()) { if (gen_node_) { f_service_ts_ << "declare module " << ts_module_ << " {"; } else { f_service_ts_ << "declare module \"./" << program_->get_name() << "_types\" {" << endl; indent_up(); f_service_ts_ << ts_indent() << "module " << program_->get_name() << " {" << endl; indent_up(); } } } if (gen_node_) { if (tservice->get_extends() != nullptr) { f_service_ << js_const_type_ << tservice->get_extends()->get_name() << " = require('./" << tservice->get_extends()->get_name() << "');" << endl << js_const_type_ << tservice->get_extends()->get_name() << "Client = " << tservice->get_extends()->get_name() << ".Client;" << endl << js_const_type_ << tservice->get_extends()->get_name() << "Processor = " << tservice->get_extends()->get_name() << ".Processor;" << endl; f_service_ts_ << "import " << tservice->get_extends()->get_name() << " = require('./" << tservice->get_extends()->get_name() << "');" << endl; } f_service_ << js_const_type_ << "ttypes = require('./" + program_->get_name() + "_types');" << endl; } generate_service_helpers(tservice); generate_service_interface(tservice); generate_service_client(tservice); if (gen_node_) { generate_service_processor(tservice); } f_service_.close(); if (gen_ts_) { if (!ts_module_.empty()) { if (gen_node_) { f_service_ts_ << "}" << endl; } else { indent_down(); f_service_ts_ << ts_indent() << "}" << endl; f_service_ts_ << "}" << endl; } } f_service_ts_.close(); } } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_js_generator::generate_service_processor(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; if (gen_node_) { string prefix = has_js_namespace(tservice->get_program()) ? js_namespace(tservice->get_program()) : js_const_type_; f_service_ << prefix << service_name_ << "Processor = " << "exports.Processor"; if (gen_ts_) { f_service_ts_ << endl << "declare class Processor "; if (tservice->get_extends() != nullptr) { f_service_ts_ << "extends " << tservice->get_extends()->get_name() << ".Processor "; } f_service_ts_ << "{" << endl; indent_up(); if(tservice->get_extends() == nullptr) { f_service_ts_ << ts_indent() << "private _handler: object;" << endl << endl; } f_service_ts_ << ts_indent() << "constructor(handler: object);" << endl; f_service_ts_ << ts_indent() << "process(input: thrift.TProtocol, output: thrift.TProtocol): void;" << endl; indent_down(); } } else { f_service_ << js_namespace(tservice->get_program()) << service_name_ << "Processor = " << "exports.Processor"; } bool is_subclass_service = tservice->get_extends() != nullptr; // ES6 Constructor if (gen_es6_) { if (is_subclass_service) { f_service_ << " = class " << service_name_ << "Processor extends " << tservice->get_extends()->get_name() << "Processor {" << endl; } else { f_service_ << " = class " << service_name_ << "Processor {" << endl; } indent_up(); indent(f_service_) << "constructor(handler) {" << endl; } else { f_service_ << " = function(handler) {" << endl; } indent_up(); if (gen_es6_ && is_subclass_service) { indent(f_service_) << "super(handler);" << endl; } indent(f_service_) << "this._handler = handler;" << endl; indent_down(); // Done with constructor if (gen_es6_) { indent(f_service_) << "}" << endl; } else { indent(f_service_) << "};" << endl; } // ES5 service inheritance if (!gen_es6_ && is_subclass_service) { indent(f_service_) << "Thrift.inherits(" << js_namespace(tservice->get_program()) << service_name_ << "Processor, " << tservice->get_extends()->get_name() << "Processor);" << endl; } // Generate the server implementation if (gen_es6_) { indent(f_service_) << "process (input, output) {" << endl; } else { indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Processor.prototype.process = function(input, output) {" << endl; } indent_up(); indent(f_service_) << js_const_type_ << "r = input.readMessageBegin();" << endl << indent() << "if (this['process_' + r.fname]) {" << endl << indent() << " return this['process_' + r.fname].call(this, r.rseqid, input, output);" << endl << indent() << "} else {" << endl << indent() << " input.skip(Thrift.Type.STRUCT);" << endl << indent() << " input.readMessageEnd();" << endl << indent() << " " << js_const_type_ << "x = new " "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN_METHOD, " "'Unknown function ' + r.fname);" << endl << indent() << " output.writeMessageBegin(r.fname, Thrift.MessageType.EXCEPTION, r.rseqid);" << endl << indent() << " x.write(output);" << endl << indent() << " output.writeMessageEnd();" << endl << indent() << " output.flush();" << endl << indent() << "}" << endl; indent_down(); if (gen_es6_) { indent(f_service_) << "}" << endl; } else { indent(f_service_) << "};" << endl; } // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } // Close off the processor class definition if (gen_es6_) { indent_down(); indent(f_service_) << "};" << endl; } if (gen_node_ && gen_ts_) { f_service_ts_ << "}" << endl; } } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_js_generator::generate_process_function(t_service* tservice, t_function* tfunction) { if (gen_es6_) { indent(f_service_) << "process_" + tfunction->get_name() + " (seqid, input, output) {" << endl; } else { indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Processor.prototype.process_" + tfunction->get_name() + " = function(seqid, input, output) {" << endl; } if (gen_ts_) { indent_up(); f_service_ts_ << ts_indent() << "process_" << tfunction->get_name() << "(seqid: number, input: thrift.TProtocol, output: thrift.TProtocol): void;" << endl; indent_down(); } indent_up(); string argsname = js_namespace(program_) + service_name_ + "_" + tfunction->get_name() + "_args"; string resultname = js_namespace(program_) + service_name_ + "_" + tfunction->get_name() + "_result"; indent(f_service_) << js_const_type_ << "args = new " << argsname << "();" << endl << indent() << "args.read(input);" << endl << indent() << "input.readMessageEnd();" << endl; // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; // Shortcut out here for oneway functions if (tfunction->is_oneway()) { indent(f_service_) << "this._handler." << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ");" << endl; indent_down(); if (gen_es6_) { indent(f_service_) << "}" << endl; } else { indent(f_service_) << "};" << endl; } return; } // Promise style invocation indent(f_service_) << "if (this._handler." << tfunction->get_name() << ".length === " << fields.size() << ") {" << endl; indent_up(); if (gen_es6_) { indent(f_service_) << "Promise.resolve(this._handler." << tfunction->get_name() << ".bind(this._handler)(" << endl; } else { string maybeComma = (fields.size() > 0 ? "," : ""); indent(f_service_) << "Q.fcall(this._handler." << tfunction->get_name() << ".bind(this._handler)" << maybeComma << endl; } indent_up(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { string maybeComma = (f_iter != fields.end() - 1 ? "," : ""); indent(f_service_) << "args." << (*f_iter)->get_name() << maybeComma << endl; } indent_down(); if (gen_es6_) { indent(f_service_) << ")).then(result => {" << endl; } else { indent(f_service_) << ").then(function(result) {" << endl; } indent_up(); f_service_ << indent() << js_const_type_ << "result_obj = new " << resultname << "({success: result});" << endl << indent() << "output.writeMessageBegin(\"" << tfunction->get_name() << "\", Thrift.MessageType.REPLY, seqid);" << endl << indent() << "result_obj.write(output);" << endl << indent() << "output.writeMessageEnd();" << endl << indent() << "output.flush();" << endl; indent_down(); if (gen_es6_) { indent(f_service_) << "}).catch(err => {" << endl; } else { indent(f_service_) << "}).catch(function (err) {" << endl; } indent_up(); indent(f_service_) << js_let_type_ << "result;" << endl; bool has_exception = false; t_struct* exceptions = tfunction->get_xceptions(); if (exceptions) { const vector& members = exceptions->get_members(); for (auto member : members) { t_type* t = get_true_type(member->get_type()); if (t->is_xception()) { if (!has_exception) { has_exception = true; indent(f_service_) << "if (err instanceof " << js_type_namespace(t->get_program()) << t->get_name(); } else { f_service_ << " || err instanceof " << js_type_namespace(t->get_program()) << t->get_name(); } } } } if (has_exception) { f_service_ << ") {" << endl; indent_up(); f_service_ << indent() << "result = new " << resultname << "(err);" << endl << indent() << "output.writeMessageBegin(\"" << tfunction->get_name() << "\", Thrift.MessageType.REPLY, seqid);" << endl; indent_down(); indent(f_service_) << "} else {" << endl; indent_up(); } f_service_ << indent() << "result = new " "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN," " err.message);" << endl << indent() << "output.writeMessageBegin(\"" << tfunction->get_name() << "\", Thrift.MessageType.EXCEPTION, seqid);" << endl; if (has_exception) { indent_down(); indent(f_service_) << "}" << endl; } f_service_ << indent() << "result.write(output);" << endl << indent() << "output.writeMessageEnd();" << endl << indent() << "output.flush();" << endl; indent_down(); indent(f_service_) << "});" << endl; indent_down(); // End promise style invocation // Callback style invocation indent(f_service_) << "} else {" << endl; indent_up(); indent(f_service_) << "this._handler." << tfunction->get_name() << "("; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { f_service_ << "args." << (*f_iter)->get_name() << ", "; } if (gen_es6_) { f_service_ << "(err, result) => {" << endl; } else { f_service_ << "function (err, result) {" << endl; } indent_up(); indent(f_service_) << js_let_type_ << "result_obj;" << endl; indent(f_service_) << "if ((err === null || typeof err === 'undefined')"; if (has_exception) { const vector& members = exceptions->get_members(); for (auto member : members) { t_type* t = get_true_type(member->get_type()); if (t->is_xception()) { f_service_ << " || err instanceof " << js_type_namespace(t->get_program()) << t->get_name(); } } } f_service_ << ") {" << endl; indent_up(); f_service_ << indent() << "result_obj = new " << resultname << "((err !== null || typeof err === 'undefined') ? err : {success: result});" << endl << indent() << "output.writeMessageBegin(\"" << tfunction->get_name() << "\", Thrift.MessageType.REPLY, seqid);" << endl; indent_down(); indent(f_service_) << "} else {" << endl; indent_up(); f_service_ << indent() << "result_obj = new " "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN," " err.message);" << endl << indent() << "output.writeMessageBegin(\"" << tfunction->get_name() << "\", Thrift.MessageType.EXCEPTION, seqid);" << endl; indent_down(); f_service_ << indent() << "}" << endl << indent() << "result_obj.write(output);" << endl << indent() << "output.writeMessageEnd();" << endl << indent() << "output.flush();" << endl; indent_down(); indent(f_service_) << "});" << endl; indent_down(); indent(f_service_) << "}" << endl; // End callback style invocation indent_down(); if (gen_es6_) { indent(f_service_) << "}" << endl; } else { indent(f_service_) << "};" << endl; } } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_js_generator::generate_service_helpers(t_service* tservice) { // Do not generate TS definitions for helper functions bool gen_ts_tmp = gen_ts_; gen_ts_ = false; vector functions = tservice->get_functions(); vector::iterator f_iter; f_service_ << "//HELPER FUNCTIONS AND STRUCTURES" << endl << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); string name = ts->get_name(); ts->set_name(service_name_ + "_" + name); generate_js_struct_definition(f_service_, ts, false, false); generate_js_function_helpers(*f_iter); ts->set_name(name); } gen_ts_ = gen_ts_tmp; } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_js_generator::generate_js_function_helpers(t_function* tfunction) { t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_js_struct_definition(f_service_, &result, false, false); } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_js_generator::generate_service_interface(t_service* tservice) { (void)tservice; } /** * Generates a REST interface */ void t_js_generator::generate_service_rest(t_service* tservice) { (void)tservice; } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_js_generator::generate_service_client(t_service* tservice) { bool is_subclass_service = tservice->get_extends() != nullptr; if (gen_node_) { string prefix = has_js_namespace(tservice->get_program()) ? js_namespace(tservice->get_program()) : js_const_type_; f_service_ << prefix << service_name_ << "Client = " << "exports.Client"; if (gen_ts_) { f_service_ts_ << ts_print_doc(tservice) << ts_indent() << ts_declare() << "class " << "Client "; if (tservice->get_extends() != nullptr) { f_service_ts_ << "extends " << tservice->get_extends()->get_name() << ".Client "; } f_service_ts_ << "{" << endl; } } else { f_service_ << js_namespace(tservice->get_program()) << service_name_ << "Client"; if (gen_ts_) { f_service_ts_ << ts_print_doc(tservice) << ts_indent() << ts_declare() << "class " << service_name_ << "Client "; if (is_subclass_service) { f_service_ts_ << "extends " << tservice->get_extends()->get_name() << "Client "; } f_service_ts_ << "{" << endl; } } // ES6 Constructor if (gen_es6_) { if (is_subclass_service) { f_service_ << " = class " << service_name_ << "Client extends " << js_namespace(tservice->get_extends()->get_program()) << tservice->get_extends()->get_name() << "Client {" << endl; } else { f_service_ << " = class " << service_name_ << "Client {" << endl; } indent_up(); if (gen_node_) { indent(f_service_) << "constructor(output, pClass) {" << endl; } else { indent(f_service_) << "constructor(input, output) {" << endl; } } else { if (gen_node_) { f_service_ << " = function(output, pClass) {" << endl; } else { f_service_ << " = function(input, output) {" << endl; } } indent_up(); if (gen_node_) { if (gen_es6_ && is_subclass_service) { indent(f_service_) << "super(output, pClass);" << endl; } indent(f_service_) << "this.output = output;" << endl; indent(f_service_) << "this.pClass = pClass;" << endl; indent(f_service_) << "this._seqid = 0;" << endl; indent(f_service_) << "this._reqs = {};" << endl; if (gen_ts_) { if(!is_subclass_service) { f_service_ts_ << ts_indent() << "private output: thrift.TTransport;" << endl << ts_indent() << "private pClass: thrift.TProtocol;" << endl << ts_indent() << "private _seqid: number;" << endl << endl; } f_service_ts_ << ts_indent() << "constructor(output: thrift.TTransport, pClass: { new(trans: thrift.TTransport): thrift.TProtocol });" << endl; } } else { indent(f_service_) << "this.input = input;" << endl; indent(f_service_) << "this.output = (!output) ? input : output;" << endl; indent(f_service_) << "this.seqid = 0;" << endl; if (gen_ts_) { f_service_ts_ << ts_indent() << "input: Thrift.TJSONProtocol;" << endl << ts_indent() << "output: Thrift.TJSONProtocol;" << endl << ts_indent() << "seqid: number;" << endl << endl << ts_indent() << "constructor(input: Thrift.TJSONProtocol, output?: Thrift.TJSONProtocol);" << endl; } } indent_down(); if (gen_es6_) { indent(f_service_) << "}" << endl; } else { indent(f_service_) << "};" << endl; if (is_subclass_service) { indent(f_service_) << "Thrift.inherits(" << js_namespace(tservice->get_program()) << service_name_ << "Client, " << js_namespace(tservice->get_extends()->get_program()) << tservice->get_extends()->get_name() << "Client);" << endl; } else { // init prototype indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype = {};" << endl; } } // utils for multiplexed services if (gen_node_) { if (gen_es6_) { indent(f_service_) << "seqid () { return this._seqid; }" << endl; indent(f_service_) << "new_seqid () { return this._seqid += 1; }" << endl; } else { indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype.seqid = function() { return this._seqid; };" << endl << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype.new_seqid = function() { return this._seqid += 1; };" << endl; } } // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = (*f_iter)->get_name(); string arglist = argument_list(arg_struct); // Open function f_service_ << endl; if (gen_es6_) { indent(f_service_) << funname << " (" << arglist << ") {" << endl; } else { indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype." << function_signature(*f_iter, "", !gen_es6_) << " {" << endl; } indent_up(); if (gen_ts_) { // function definition without callback f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << ts_function_signature(*f_iter, false) << endl; if (!gen_es6_) { // overload with callback f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << ts_function_signature(*f_iter, true) << endl; } else { // overload with callback f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << ts_function_signature(*f_iter, true) << endl; } } if (gen_es6_ && gen_node_) { indent(f_service_) << "this._seqid = this.new_seqid();" << endl; indent(f_service_) << js_const_type_ << "self = this;" << endl << indent() << "return new Promise((resolve, reject) => {" << endl; indent_up(); indent(f_service_) << "self._reqs[self.seqid()] = (error, result) => {" << endl; indent_up(); indent(f_service_) << "return error ? reject(error) : resolve(result);" << endl; indent_down(); indent(f_service_) << "};" << endl; indent(f_service_) << "self.send_" << funname << "(" << arglist << ");" << endl; indent_down(); indent(f_service_) << "});" << endl; } else if (gen_node_) { // Node.js output ./gen-nodejs f_service_ << indent() << "this._seqid = this.new_seqid();" << endl << indent() << "if (callback === undefined) {" << endl; indent_up(); f_service_ << indent() << js_const_type_ << "_defer = Q.defer();" << endl << indent() << "this._reqs[this.seqid()] = function(error, result) {" << endl; indent_up(); indent(f_service_) << "if (error) {" << endl; indent_up(); indent(f_service_) << "_defer.reject(error);" << endl; indent_down(); indent(f_service_) << "} else {" << endl; indent_up(); indent(f_service_) << "_defer.resolve(result);" << endl; indent_down(); indent(f_service_) << "}" << endl; indent_down(); indent(f_service_) << "};" << endl; f_service_ << indent() << "this.send_" << funname << "(" << arglist << ");" << endl << indent() << "return _defer.promise;" << endl; indent_down(); indent(f_service_) << "} else {" << endl; indent_up(); f_service_ << indent() << "this._reqs[this.seqid()] = callback;" << endl << indent() << "this.send_" << funname << "(" << arglist << ");" << endl; indent_down(); indent(f_service_) << "}" << endl; } else if (gen_es6_) { f_service_ << indent() << js_const_type_ << "self = this;" << endl << indent() << "return new Promise((resolve, reject) => {" << endl; indent_up(); f_service_ << indent() << "self.send_" << funname << "(" << arglist << (arglist.empty() ? "" : ", ") << "(error, result) => {" << endl; indent_up(); indent(f_service_) << "return error ? reject(error) : resolve(result);" << endl; indent_down(); f_service_ << indent() << "});" << endl; indent_down(); f_service_ << indent() << "});" << endl; } else if (gen_jquery_) { // jQuery output ./gen-js f_service_ << indent() << "if (callback === undefined) {" << endl; indent_up(); f_service_ << indent() << "this.send_" << funname << "(" << arglist << ");" << endl; if (!(*f_iter)->is_oneway()) { f_service_ << indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << "return "; } f_service_ << "this.recv_" << funname << "();" << endl; } indent_down(); f_service_ << indent() << "} else {" << endl; indent_up(); f_service_ << indent() << js_const_type_ << "postData = this.send_" << funname << "(" << arglist << (arglist.empty() ? "" : ", ") << "true);" << endl; f_service_ << indent() << "return this.output.getTransport()" << endl; indent_up(); f_service_ << indent() << ".jqRequest(this, postData, arguments, this.recv_" << funname << ");" << endl; indent_down(); indent_down(); f_service_ << indent() << "}" << endl; } else { // Standard JavaScript ./gen-js f_service_ << indent() << "this.send_" << funname << "(" << arglist << (arglist.empty() ? "" : ", ") << "callback); " << endl; if (!(*f_iter)->is_oneway()) { f_service_ << indent() << "if (!callback) {" << endl; f_service_ << indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << " return "; } f_service_ << "this.recv_" << funname << "();" << endl; f_service_ << indent() << "}" << endl; } } indent_down(); if (gen_es6_) { indent(f_service_) << "}" << endl << endl; } else { indent(f_service_) << "};" << endl << endl; } // Send function if (gen_es6_) { if (gen_node_) { indent(f_service_) << "send_" << funname << " (" << arglist << ") {" << endl; } else { // ES6 js still uses callbacks here. Should refactor this to promise style later.. indent(f_service_) << "send_" << funname << " (" << argument_list(arg_struct, true) << ") {" << endl; } } else { indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype.send_" << function_signature(*f_iter, "", !gen_node_) << " {" << endl; } indent_up(); std::string outputVar; if (gen_node_) { f_service_ << indent() << js_const_type_ << "output = new this.pClass(this.output);" << endl; outputVar = "output"; } else { outputVar = "this.output"; } std::string argsname = js_namespace(program_) + service_name_ + "_" + (*f_iter)->get_name() + "_args"; std::string messageType = (*f_iter)->is_oneway() ? "Thrift.MessageType.ONEWAY" : "Thrift.MessageType.CALL"; // Build args if (fields.size() > 0){ // It is possible that a method argument is named "params", we need to ensure the locally // generated identifier "params" is uniquely named std::string params_identifier = this->next_identifier_name(fields, "params"); f_service_ << indent() << js_const_type_ << params_identifier << " = {" << endl; indent_up(); for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { indent(f_service_) << (*fld_iter)->get_name() << ": " << (*fld_iter)->get_name(); if (fld_iter != fields.end()-1) { f_service_ << "," << endl; } else { f_service_ << endl; } } indent_down(); indent(f_service_) << "};" << endl; // NOTE: "args" is a reserved keyword, so no need to generate a unique identifier indent(f_service_) << js_const_type_ << "args = new " << argsname << "(" << params_identifier << ");" << endl; } else { indent(f_service_) << js_const_type_ << "args = new " << argsname << "();" << endl; } // Serialize the request header within try/catch indent(f_service_) << "try {" << endl; indent_up(); if (gen_node_) { f_service_ << indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name() << "', " << messageType << ", this.seqid());" << endl; } else { f_service_ << indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name() << "', " << messageType << ", this.seqid);" << endl; } // Write to the stream f_service_ << indent() << "args.write(" << outputVar << ");" << endl << indent() << outputVar << ".writeMessageEnd();" << endl; if (gen_node_) { if((*f_iter)->is_oneway()) { f_service_ << indent() << "this.output.flush();" << endl; f_service_ << indent() << js_const_type_ << "callback = this._reqs[this.seqid()] || function() {};" << endl; f_service_ << indent() << "delete this._reqs[this.seqid()];" << endl; f_service_ << indent() << "callback(null);" << endl; } else { f_service_ << indent() << "return this.output.flush();" << endl; } } else { if (gen_jquery_) { f_service_ << indent() << "return this.output.getTransport().flush(callback);" << endl; } else if (gen_es6_) { f_service_ << indent() << js_const_type_ << "self = this;" << endl; if((*f_iter)->is_oneway()) { f_service_ << indent() << "this.output.getTransport().flush(true, null);" << endl; f_service_ << indent() << "callback();" << endl; } else { f_service_ << indent() << "this.output.getTransport().flush(true, () => {" << endl; indent_up(); f_service_ << indent() << js_let_type_ << "error = null, result = null;" << endl; f_service_ << indent() << "try {" << endl; f_service_ << indent() << " result = self.recv_" << funname << "();" << endl; f_service_ << indent() << "} catch (e) {" << endl; f_service_ << indent() << " error = e;" << endl; f_service_ << indent() << "}" << endl; f_service_ << indent() << "callback(error, result);" << endl; indent_down(); f_service_ << indent() << "});" << endl; } } else { f_service_ << indent() << "if (callback) {" << endl; indent_up(); if((*f_iter)->is_oneway()) { f_service_ << indent() << "this.output.getTransport().flush(true, null);" << endl; f_service_ << indent() << "callback();" << endl; } else { f_service_ << indent() << js_const_type_ << "self = this;" << endl; f_service_ << indent() << "this.output.getTransport().flush(true, function() {" << endl; indent_up(); f_service_ << indent() << js_let_type_ << "result = null;" << endl; f_service_ << indent() << "try {" << endl; f_service_ << indent() << " result = self.recv_" << funname << "();" << endl; f_service_ << indent() << "} catch (e) {" << endl; f_service_ << indent() << " result = e;" << endl; f_service_ << indent() << "}" << endl; f_service_ << indent() << "callback(result);" << endl; indent_down(); f_service_ << indent() << "});" << endl; } indent_down(); f_service_ << indent() << "} else {" << endl; f_service_ << indent() << " return this.output.getTransport().flush();" << endl; f_service_ << indent() << "}" << endl; } } indent_down(); f_service_ << indent() << "}" << endl; // Reset the transport and delete registered callback if there was a serialization error f_service_ << indent() << "catch (e) {" << endl; indent_up(); if (gen_node_) { f_service_ << indent() << "delete this._reqs[this.seqid()];" << endl; f_service_ << indent() << "if (typeof " << outputVar << ".reset === 'function') {" << endl; f_service_ << indent() << " " << outputVar << ".reset();" << endl; f_service_ << indent() << "}" << endl; } else { f_service_ << indent() << "if (typeof " << outputVar << ".getTransport().reset === 'function') {" << endl; f_service_ << indent() << " " << outputVar << ".getTransport().reset();" << endl; f_service_ << indent() << "}" << endl; } f_service_ << indent() << "throw e;" << endl; indent_down(); f_service_ << indent() << "}" << endl; indent_down(); // Close send function if (gen_es6_) { indent(f_service_) << "}" << endl; } else { indent(f_service_) << "};" << endl; } // Receive function if (!(*f_iter)->is_oneway()) { std::string resultname = js_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result"; f_service_ << endl; // Open receive function if (gen_node_) { if (gen_es6_) { indent(f_service_) << "recv_" << (*f_iter)->get_name() << " (input, mtype, rseqid) {" << endl; } else { indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype.recv_" << (*f_iter)->get_name() << " = function(input,mtype,rseqid) {" << endl; } } else { if (gen_es6_) { indent(f_service_) << "recv_" << (*f_iter)->get_name() << " () {" << endl; } else { t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype." << function_signature(&recv_function) << " {" << endl; } } indent_up(); std::string inputVar; if (gen_node_) { inputVar = "input"; } else { inputVar = "this.input"; } if (gen_node_) { f_service_ << indent() << js_const_type_ << "callback = this._reqs[rseqid] || function() {};" << endl << indent() << "delete this._reqs[rseqid];" << endl; } else { f_service_ << indent() << js_const_type_ << "ret = this.input.readMessageBegin();" << endl << indent() << js_const_type_ << "mtype = ret.mtype;" << endl; } f_service_ << indent() << "if (mtype == Thrift.MessageType.EXCEPTION) {" << endl; indent_up(); f_service_ << indent() << js_const_type_ << "x = new Thrift.TApplicationException();" << endl << indent() << "x.read(" << inputVar << ");" << endl << indent() << inputVar << ".readMessageEnd();" << endl << indent() << render_recv_throw("x") << endl; scope_down(f_service_); f_service_ << indent() << js_const_type_ << "result = new " << resultname << "();" << endl << indent() << "result.read(" << inputVar << ");" << endl; f_service_ << indent() << inputVar << ".readMessageEnd();" << endl << endl; t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << "if (null !== result." << (*x_iter)->get_name() << ") {" << endl << indent() << " " << render_recv_throw("result." + (*x_iter)->get_name()) << endl << indent() << "}" << endl; } // Careful, only return result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << "if (null !== result.success) {" << endl << indent() << " " << render_recv_return("result.success") << endl << indent() << "}" << endl; f_service_ << indent() << render_recv_throw("'" + (*f_iter)->get_name() + " failed: unknown result'") << endl; } else { if (gen_node_) { indent(f_service_) << "callback(null);" << endl; } else { indent(f_service_) << "return;" << endl; } } // Close receive function indent_down(); if (gen_es6_) { indent(f_service_) << "}" << endl; } else { indent(f_service_) << "};" << endl; } } } // Finish class definitions if (gen_ts_) { f_service_ts_ << ts_indent() << "}" << endl; } if (gen_es6_) { indent_down(); f_service_ << "};" << endl; } } std::string t_js_generator::render_recv_throw(std::string var) { if (gen_node_) { return "return callback(" + var + ");"; } else { return "throw " + var + ";"; } } std::string t_js_generator::render_recv_return(std::string var) { if (gen_node_) { return "return callback(null, " + var + ");"; } else { return "return " + var + ";"; } } /** * Deserializes a field of any type. */ void t_js_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, bool inclass) { (void)inclass; t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw std::runtime_error("CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name()); } string name = prefix + tfield->get_name(); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << name << " = input."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw std::runtime_error("compiler error: cannot serialize void field in a struct: " + name); break; case t_base_type::TYPE_STRING: out << (type->is_binary() ? "readBinary()" : "readString()"); break; case t_base_type::TYPE_BOOL: out << "readBool()"; break; case t_base_type::TYPE_I8: out << "readByte()"; break; case t_base_type::TYPE_I16: out << "readI16()"; break; case t_base_type::TYPE_I32: out << "readI32()"; break; case t_base_type::TYPE_I64: out << "readI64()"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble()"; break; default: throw std::runtime_error("compiler error: no JS name for base type " + t_base_type::t_base_name(tbase)); } } else if (type->is_enum()) { out << "readI32()"; } if (!gen_node_) { out << ".value"; } out << ";" << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type->get_name().c_str()); } } /** * Generates an unserializer for a variable. This makes two key assumptions, * first that there is a const char* variable named data that points to the * buffer for deserialization, and that there is a variable protocol which * is a reference to a TProtocol serialization object. */ void t_js_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { out << indent() << prefix << " = new " << js_type_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl << indent() << prefix << ".read(input);" << endl; } void t_js_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { string size = tmp("_size"); string rtmp3 = tmp("_rtmp3"); t_field fsize(g_type_i32, size); // Declare variables, read header if (ttype->is_map()) { out << indent() << prefix << " = {};" << endl; out << indent() << js_const_type_ << rtmp3 << " = input.readMapBegin();" << endl; out << indent() << js_const_type_ << size << " = " << rtmp3 << ".size || 0;" << endl; } else if (ttype->is_set()) { out << indent() << prefix << " = [];" << endl << indent() << js_const_type_ << rtmp3 << " = input.readSetBegin();" << endl << indent() << js_const_type_ << size << " = " << rtmp3 << ".size || 0;" << endl; } else if (ttype->is_list()) { out << indent() << prefix << " = [];" << endl << indent() << js_const_type_ << rtmp3 << " = input.readListBegin();" << endl << indent() << js_const_type_ << size << " = " << rtmp3 << ".size || 0;" << endl; } // For loop iterates over elements string i = tmp("_i"); indent(out) << "for (" << js_let_type_ << i << " = 0; " << i << " < " << size << "; ++" << i << ") {" << endl; indent_up(); if (ttype->is_map()) { if (!gen_node_) { out << indent() << "if (" << i << " > 0 ) {" << endl << indent() << " if (input.rstack.length > input.rpos[input.rpos.length -1] + 1) {" << endl << indent() << " input.rstack.pop();" << endl << indent() << " }" << endl << indent() << "}" << endl; } generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } scope_down(out); // Read container end if (ttype->is_map()) { indent(out) << "input.readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "input.readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "input.readListEnd();" << endl; } } /** * Generates code to deserialize a map */ void t_js_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("key"); string val = tmp("val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); indent(out) << declare_field(&fkey, false, false) << ";" << endl; indent(out) << declare_field(&fval, false, false) << ";" << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); indent(out) << prefix << "[" << key << "] = " << val << ";" << endl; } void t_js_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << js_let_type_ << elem << " = null;" << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".push(" << elem << ");" << endl; } void t_js_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << js_let_type_ << elem << " = null;" << endl; generate_deserialize_field(out, &felem); indent(out) << prefix << ".push(" << elem << ");" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_js_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw std::runtime_error("CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name()); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + tfield->get_name()); } else if (type->is_base_type() || type->is_enum()) { string name = tfield->get_name(); // Hack for when prefix is defined (always a hash ref) if (!prefix.empty()) name = prefix + tfield->get_name(); indent(out) << "output."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw std::runtime_error("compiler error: cannot serialize void field in a struct: " + name); break; case t_base_type::TYPE_STRING: out << (type->is_binary() ? "writeBinary(" : "writeString(") << name << ")"; break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ")"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ")"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ")"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ")"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ")"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ")"; break; default: throw std::runtime_error("compiler error: no JS name for base type " + t_base_type::t_base_name(tbase)); } } else if (type->is_enum()) { out << "writeI32(" << name << ")"; } out << ";" << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type->get_name().c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_js_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; indent(out) << prefix << ".write(output);" << endl; } /** * Writes out a container */ void t_js_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { if (ttype->is_map()) { indent(out) << "output.writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "Thrift.objectLength(" << prefix << "));" << endl; } else if (ttype->is_set()) { indent(out) << "output.writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix << ".length);" << endl; } else if (ttype->is_list()) { indent(out) << "output.writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length);" << endl; } if (ttype->is_map()) { string kiter = tmp("kiter"); string viter = tmp("viter"); indent(out) << "for (" << js_let_type_ << kiter << " in " << prefix << ") {" << endl; indent_up(); indent(out) << "if (" << prefix << ".hasOwnProperty(" << kiter << ")) {" << endl; indent_up(); indent(out) << js_let_type_ << viter << " = " << prefix << "[" << kiter << "];" << endl; generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); scope_down(out); scope_down(out); } else if (ttype->is_set()) { string iter = tmp("iter"); indent(out) << "for (" << js_let_type_ << iter << " in " << prefix << ") {" << endl; indent_up(); indent(out) << "if (" << prefix << ".hasOwnProperty(" << iter << ")) {" << endl; indent_up(); indent(out) << iter << " = " << prefix << "[" << iter << "];" << endl; generate_serialize_set_element(out, (t_set*)ttype, iter); scope_down(out); scope_down(out); } else if (ttype->is_list()) { string iter = tmp("iter"); indent(out) << "for (" << js_let_type_ << iter << " in " << prefix << ") {" << endl; indent_up(); indent(out) << "if (" << prefix << ".hasOwnProperty(" << iter << ")) {" << endl; indent_up(); indent(out) << iter << " = " << prefix << "[" << iter << "];" << endl; generate_serialize_list_element(out, (t_list*)ttype, iter); scope_down(out); scope_down(out); } if (ttype->is_map()) { indent(out) << "output.writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "output.writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "output.writeListEnd();" << endl; } } /** * Serializes the members of a map. * */ void t_js_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter) { t_field kfield(tmap->get_key_type(), kiter); generate_serialize_field(out, &kfield); t_field vfield(tmap->get_val_type(), viter); generate_serialize_field(out, &vfield); } /** * Serializes the members of a set. */ void t_js_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield); } /** * Serializes the members of a list. */ void t_js_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield); } /** * Declares a field, which may include initialization as necessary. * * @param ttype The type */ string t_js_generator::declare_field(t_field* tfield, bool init, bool obj) { string result = "this." + tfield->get_name(); if (!obj) { result = js_let_type_ + tfield->get_name(); } if (init) { t_type* type = get_true_type(tfield->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: break; case t_base_type::TYPE_STRING: case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_DOUBLE: result += " = null"; break; default: throw std::runtime_error("compiler error: no JS initializer for base type " + t_base_type::t_base_name(tbase)); } } else if (type->is_enum()) { result += " = null"; } else if (type->is_map()) { result += " = null"; } else if (type->is_container()) { result += " = null"; } else if (type->is_struct() || type->is_xception()) { if (obj) { result += " = new " + js_type_namespace(type->get_program()) + type->get_name() + "()"; } else { result += " = null"; } } } else { result += " = null"; } return result; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_js_generator::function_signature(t_function* tfunction, string prefix, bool include_callback) { string str; str = prefix + tfunction->get_name() + " = function("; str += argument_list(tfunction->get_arglist(), include_callback); str += ")"; return str; } /** * Renders a field list */ string t_js_generator::argument_list(t_struct* tstruct, bool include_callback) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += (*f_iter)->get_name(); } if (include_callback) { if (!fields.empty()) { result += ", "; } result += "callback"; } return result; } /** * Converts the parse type to a C++ enum string for the given type. */ string t_js_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw std::runtime_error("NO T_VOID CONSTRUCT"); case t_base_type::TYPE_STRING: return "Thrift.Type.STRING"; case t_base_type::TYPE_BOOL: return "Thrift.Type.BOOL"; case t_base_type::TYPE_I8: return "Thrift.Type.BYTE"; case t_base_type::TYPE_I16: return "Thrift.Type.I16"; case t_base_type::TYPE_I32: return "Thrift.Type.I32"; case t_base_type::TYPE_I64: return "Thrift.Type.I64"; case t_base_type::TYPE_DOUBLE: return "Thrift.Type.DOUBLE"; } } else if (type->is_enum()) { return "Thrift.Type.I32"; } else if (type->is_struct() || type->is_xception()) { return "Thrift.Type.STRUCT"; } else if (type->is_map()) { return "Thrift.Type.MAP"; } else if (type->is_set()) { return "Thrift.Type.SET"; } else if (type->is_list()) { return "Thrift.Type.LIST"; } throw std::runtime_error("INVALID TYPE IN type_to_enum: " + type->get_name()); } /** * Converts a t_type to a TypeScript type (string). * @param t_type Type to convert to TypeScript * @return String TypeScript type */ string t_js_generator::ts_get_type(t_type* type) { std::string ts_type; type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: ts_type = type->is_binary() ? "Buffer" : "string"; break; case t_base_type::TYPE_BOOL: ts_type = "boolean"; break; case t_base_type::TYPE_I8: ts_type = "any"; break; case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_DOUBLE: ts_type = "number"; break; case t_base_type::TYPE_I64: ts_type = "Int64"; break; case t_base_type::TYPE_VOID: ts_type = "void"; } } else if (type->is_enum() || type->is_struct() || type->is_xception()) { std::string type_name; if (type->get_program()) { type_name = js_namespace(type->get_program()); // If the type is not defined within the current program, we need to prefix it with the same name as // the generated "import" statement for the types containing program if(type->get_program() != program_) { auto prefix = include_2_import_name.find(type->get_program()); if(prefix != include_2_import_name.end()) { type_name.append(prefix->second); type_name.append("."); } } } type_name.append(type->get_name()); ts_type = type_name; } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } ts_type = ts_get_type(etype) + "[]"; } else if (type->is_map()) { string ktype = ts_get_type(((t_map*)type)->get_key_type()); string vtype = ts_get_type(((t_map*)type)->get_val_type()); if (ktype == "number" || ktype == "string" ) { ts_type = "{ [k: " + ktype + "]: " + vtype + "; }"; } else if ((((t_map*)type)->get_key_type())->is_enum()) { // Not yet supported (enum map): https://github.com/Microsoft/TypeScript/pull/2652 //ts_type = "{ [k: " + ktype + "]: " + vtype + "; }"; ts_type = "{ [k: number /*" + ktype + "*/]: " + vtype + "; }"; } else { ts_type = "any"; } } return ts_type; } /** * Renders a TypeScript function signature of the form 'name(args: types): type;' * * @param t_function Function definition * @param bool in-/exclude the callback argument * @return String of rendered function definition */ std::string t_js_generator::ts_function_signature(t_function* tfunction, bool include_callback) { string str; const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator f_iter; str = tfunction->get_name() + "("; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { str += (*f_iter)->get_name() + ts_get_req(*f_iter) + ": " + ts_get_type((*f_iter)->get_type()); if (f_iter + 1 != fields.end() || (include_callback && fields.size() > 0)) { str += ", "; } } if (include_callback) { if (gen_node_) { t_struct* exceptions = tfunction->get_xceptions(); string exception_types; if (exceptions) { const vector& members = exceptions->get_members(); for (vector::const_iterator it = members.begin(); it != members.end(); ++it) { t_type* t = get_true_type((*it)->get_type()); if (it == members.begin()) { exception_types = js_type_namespace(t->get_program()) + t->get_name(); } else { exception_types += " | " + js_type_namespace(t->get_program()) + t->get_name(); } } } if (exception_types == "") { str += "callback?: (error: void, response: " + ts_get_type(tfunction->get_returntype()) + ")=>void): "; } else { str += "callback?: (error: " + exception_types + ", response: " + ts_get_type(tfunction->get_returntype()) + ")=>void): "; } } else { str += "callback?: (data: " + ts_get_type(tfunction->get_returntype()) + ")=>void): "; } if (gen_jquery_) { str += "JQueryPromise<" + ts_get_type(tfunction->get_returntype()) +">;"; } else { str += "void;"; } } else { if (gen_es6_) { str += "): Promise<" + ts_get_type(tfunction->get_returntype()) + ">;"; } else { str += "): " + ts_get_type(tfunction->get_returntype()) + ";"; } } return str; } /** * Takes a name and produces a valid NodeJS identifier from it * * @param name The name which shall become a valid NodeJS identifier * @return The modified name with the updated identifier */ std::string t_js_generator::make_valid_nodeJs_identifier(std::string const& name) { std::string str = name; if (str.empty()) { return str; } // tests rely on this assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); // if the first letter is a number, we add an additional underscore in front of it char c = str.at(0); if (('0' <= c) && (c <= '9')) { str = "_" + str; } // following chars: letter, number or underscore for (size_t i = 0; i < str.size(); ++i) { c = str.at(i); if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) && ('_' != c) && ('$' != c)) { str.replace(i, 1, "_"); } } return str; } void t_js_generator::parse_imports(t_program* program, const std::string& imports_string) { if (program->get_recursive()) { throw std::invalid_argument("[-gen js:imports=] option is not usable in recursive code generation mode"); } std::stringstream sstream(imports_string); std::string import; while (std::getline(sstream, import, ':')) { imports.emplace_back(import); } if (imports.empty()) { throw std::invalid_argument("invalid usage: [-gen js:imports=] requires at least one path " "(multiple paths are separated by ':')"); } for (auto& import : imports) { // Strip trailing '/' if (!import.empty() && import[import.size() - 1] == '/') { import = import.substr(0, import.size() - 1); } if (import.empty()) { throw std::invalid_argument("empty paths are not allowed in imports"); } std::ifstream episode_file; string line; const auto episode_file_path = import + "/" + episode_file_name; episode_file.open(episode_file_path); if (!episode_file) { throw std::runtime_error("failed to open the file '" + episode_file_path + "'"); } while (std::getline(episode_file, line)) { const auto separator_position = line.find(':'); if (separator_position == string::npos) { // could not find the separator in the line throw std::runtime_error("the episode file '" + episode_file_path + "' is malformed, the line '" + line + "' does not have a key:value separator ':'"); } const auto module_name = line.substr(0, separator_position); const auto import_path = line.substr(separator_position + 1); if (module_name.empty()) { throw std::runtime_error("the episode file '" + episode_file_path + "' is malformed, the module name is empty"); } if (import_path.empty()) { throw std::runtime_error("the episode file '" + episode_file_path + "' is malformed, the import path is empty"); } const auto module_import_path = import.substr(import.find_last_of('/') + 1) + "/" + import_path; const auto result = module_name_2_import_path.emplace(module_name, module_import_path); if (!result.second) { throw std::runtime_error("multiple providers of import path found for " + module_name + "\n\t" + module_import_path + "\n\t" + result.first->second); } } } } void t_js_generator::parse_thrift_package_output_directory(const std::string& thrift_package_output_directory) { thrift_package_output_directory_ = thrift_package_output_directory; // Strip trailing '/' if (!thrift_package_output_directory_.empty() && thrift_package_output_directory_[thrift_package_output_directory_.size() - 1] == '/') { thrift_package_output_directory_ = thrift_package_output_directory_.substr(0, thrift_package_output_directory_.size() - 1); } // Check that the thrift_package_output_directory is not empty after stripping if (thrift_package_output_directory_.empty()) { throw std::invalid_argument("the thrift_package_output_directory argument must not be empty"); } else { gen_episode_file_ = true; } } /** * Checks is the specified field name is contained in the specified field vector */ bool t_js_generator::find_field(const std::vector& fields, const std::string& name) { vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == name) { return true; } } return false; } /** * Given a vector of fields, generate a valid identifier name that does not conflict with avaliable field names */ std::string t_js_generator::next_identifier_name(const std::vector& fields, const std::string& base_name) { // Search through fields until a match is not found, if a match is found prepend "_" to the identifier name std::string current_name = this->make_valid_nodeJs_identifier(base_name); while(this->find_field(fields, current_name)) { current_name = this->make_valid_nodeJs_identifier("_" + current_name); } return current_name; } THRIFT_REGISTER_GENERATOR(js, "Javascript", " jquery: Generate jQuery compatible code.\n" " node: Generate node.js compatible code.\n" " ts: Generate TypeScript definition files.\n" " with_ns: Create global namespace objects when using node.js\n" " es6: Create ES6 code with Promises\n" " thrift_package_output_directory=:\n" " Generate episode file and use the as prefix\n" " imports=:\n" " ':' separated list of paths of modules that has episode files in their root\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_json_generator.cc000066400000000000000000000527251420101504100252230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; using std::stack; static const string endl = "\n"; static const string quot = "\""; static const bool NO_INDENT = false; static const bool FORCE_STRING = true; class t_json_generator : public t_generator { public: t_json_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; should_merge_includes_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("merge") == 0) { should_merge_includes_ = true; } else { throw "unknown option json:" + iter->first; } } out_dir_base_ = "gen-json"; } ~t_json_generator() override = default; /** * Init and close methods */ void init_generator() override; void close_generator() override; void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_program() override; void generate_function(t_function* tfunc); void generate_field(t_field* field); void generate_service(t_service* tservice) override; void generate_struct(t_struct* tstruct) override; private: bool should_merge_includes_; ofstream_with_content_based_conditional_update f_json_; std::stack comma_needed_; template string number_to_string(T t) { std::ostringstream out; out.imbue(std::locale::classic()); out.precision(std::numeric_limits::digits10); out << t; return out.str(); } template void write_number(T n) { f_json_ << number_to_string(n); } string get_type_name(t_type* ttype); string get_qualified_name(t_type* ttype); void start_object(bool should_indent = true); void start_array(); void end_object(); void end_array(); void write_comma_if_needed(); void indicate_comma_needed(); string escape_json_string(const string& input); string json_str(const string& str); void merge_includes(t_program*); void generate_constant(t_const* con); void write_type_spec_entry(const char* name, t_type* ttype); void write_type_spec_object(const char* name, t_type* ttype); void write_type_spec(t_type* ttype); void write_string(const string& value); void write_value(t_type* tvalue); void write_const_value(t_const_value* value, bool force_string = false); void write_key_and(string key); void write_key_and_string(string key, string val); void write_key_and_integer(string key, int val); void write_key_and_bool(string key, bool val); }; void t_json_generator::init_generator() { MKDIR(get_out_dir().c_str()); string f_json_name = get_out_dir() + program_->get_name() + ".json"; f_json_.open(f_json_name.c_str()); // Merge all included programs into this one so we can output one big file. if (should_merge_includes_) { merge_includes(program_); } } string t_json_generator::escape_json_string(const string& input) { std::ostringstream ss; for (char iter : input) { switch (iter) { case '\\': ss << "\\\\"; break; case '"': ss << "\\\""; break; case '/': ss << "\\/"; break; case '\b': ss << "\\b"; break; case '\f': ss << "\\f"; break; case '\n': ss << "\\n"; break; case '\r': ss << "\\r"; break; case '\t': ss << "\\t"; break; default: ss << iter; break; } } return ss.str(); } void t_json_generator::start_object(bool should_indent) { f_json_ << (should_indent ? indent() : "") << "{" << endl; indent_up(); comma_needed_.push(false); } void t_json_generator::start_array() { f_json_ << "[" << endl; indent_up(); comma_needed_.push(false); } void t_json_generator::write_comma_if_needed() { if (comma_needed_.top()) { f_json_ << "," << endl; } } void t_json_generator::indicate_comma_needed() { comma_needed_.pop(); comma_needed_.push(true); } void t_json_generator::write_key_and(string key) { write_comma_if_needed(); indent(f_json_) << json_str(key) << ": "; indicate_comma_needed(); } void t_json_generator::write_key_and_integer(string key, int val) { write_comma_if_needed(); indent(f_json_) << json_str(key) << ": " << number_to_string(val); indicate_comma_needed(); } void t_json_generator::write_key_and_string(string key, string val) { write_comma_if_needed(); indent(f_json_) << json_str(key) << ": " << json_str(val); indicate_comma_needed(); } void t_json_generator::write_key_and_bool(string key, bool val) { write_comma_if_needed(); indent(f_json_) << json_str(key) << ": " << (val ? "true" : "false"); indicate_comma_needed(); } void t_json_generator::end_object() { indent_down(); f_json_ << endl << indent() << "}"; comma_needed_.pop(); } void t_json_generator::end_array() { indent_down(); if (comma_needed_.top()) { f_json_ << endl; } indent(f_json_) << "]"; comma_needed_.pop(); } void t_json_generator::write_type_spec_object(const char* name, t_type* ttype) { ttype = ttype->get_true_type(); if (ttype->is_struct() || ttype->is_xception() || ttype->is_container()) { write_key_and(name); start_object(NO_INDENT); write_key_and("typeId"); write_type_spec(ttype); end_object(); } } void t_json_generator::write_type_spec_entry(const char* name, t_type* ttype) { write_key_and(name); write_type_spec(ttype); } void t_json_generator::write_type_spec(t_type* ttype) { ttype = ttype->get_true_type(); write_string(get_type_name(ttype)); if (ttype->annotations_.size() > 0) { write_key_and("annotations"); start_object(); for (auto & annotation : ttype->annotations_) { write_key_and_string(annotation.first, annotation.second); } end_object(); } if (ttype->is_struct() || ttype->is_xception()) { write_key_and_string("class", get_qualified_name(ttype)); } else if (ttype->is_map()) { t_type* ktype = ((t_map*)ttype)->get_key_type(); t_type* vtype = ((t_map*)ttype)->get_val_type(); write_key_and_string("keyTypeId", get_type_name(ktype)); write_key_and_string("valueTypeId", get_type_name(vtype)); write_type_spec_object("keyType", ktype); write_type_spec_object("valueType", vtype); } else if (ttype->is_list()) { t_type* etype = ((t_list*)ttype)->get_elem_type(); write_key_and_string("elemTypeId", get_type_name(etype)); write_type_spec_object("elemType", etype); } else if (ttype->is_set()) { t_type* etype = ((t_set*)ttype)->get_elem_type(); write_key_and_string("elemTypeId", get_type_name(etype)); write_type_spec_object("elemType", etype); } } void t_json_generator::close_generator() { f_json_ << endl; f_json_.close(); } void t_json_generator::merge_includes(t_program* program) { vector includes = program->get_includes(); vector::iterator inc_iter; for (inc_iter = includes.begin(); inc_iter != includes.end(); ++inc_iter) { t_program* include = *inc_iter; // recurse in case we get crazy merge_includes(include); // merge enums vector enums = include->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { program->add_enum(*en_iter); } // merge typedefs vector typedefs = include->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { program->add_typedef(*td_iter); } // merge structs vector objects = include->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { program->add_struct(*o_iter); } // merge constants vector consts = include->get_consts(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { program->add_const(*c_iter); } // merge services vector services = include->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { program->add_service(*sv_iter); } } } void t_json_generator::generate_program() { init_generator(); start_object(); write_key_and_string("name", program_->get_name()); if (program_->has_doc()) { write_key_and_string("doc", program_->get_doc()); } // When merging includes, the "namespaces" and "includes" sections // become ambiguous, so just skip them. if (!should_merge_includes_) { // Generate namespaces write_key_and("namespaces"); start_object(NO_INDENT); const map& namespaces = program_->get_namespaces(); map::const_iterator ns_it; for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) { write_key_and_string(ns_it->first, ns_it->second); indicate_comma_needed(); } end_object(); // Generate includes write_key_and("includes"); start_array(); const vector includes = program_->get_includes(); vector::const_iterator inc_it; for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) { write_comma_if_needed(); write_string((*inc_it)->get_name()); indicate_comma_needed(); } end_array(); } // Generate enums write_key_and("enums"); start_array(); vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { write_comma_if_needed(); generate_enum(*en_iter); indicate_comma_needed(); } end_array(); // Generate typedefs write_key_and("typedefs"); start_array(); vector typedefs = program_->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { write_comma_if_needed(); generate_typedef(*td_iter); indicate_comma_needed(); } end_array(); // Generate structs, exceptions, and unions in declared order write_key_and("structs"); start_array(); vector objects = program_->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { write_comma_if_needed(); if ((*o_iter)->is_xception()) { generate_xception(*o_iter); } else { generate_struct(*o_iter); } indicate_comma_needed(); } end_array(); // Generate constants write_key_and("constants"); start_array(); vector consts = program_->get_consts(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { write_comma_if_needed(); generate_constant(*c_iter); indicate_comma_needed(); } end_array(); // Generate services write_key_and("services"); start_array(); vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { write_comma_if_needed(); generate_service(*sv_iter); indicate_comma_needed(); } end_array(); end_object(); // Close the generator close_generator(); } void t_json_generator::generate_typedef(t_typedef* ttypedef) { start_object(); write_key_and_string("name", get_qualified_name(ttypedef)); write_key_and_string("typeId", get_type_name(ttypedef->get_true_type())); write_type_spec_object("type", ttypedef->get_true_type()); if (ttypedef->has_doc()) { write_key_and_string("doc", ttypedef->get_doc()); } if (ttypedef->annotations_.size() > 0) { write_key_and("annotations"); start_object(); for (auto & annotation : ttypedef->annotations_) { write_key_and_string(annotation.first, annotation.second); } end_object(); } end_object(); } void t_json_generator::write_string(const string& value) { f_json_ << quot << escape_json_string(value) << quot; } void t_json_generator::write_const_value(t_const_value* value, bool should_force_string) { switch (value->get_type()) { case t_const_value::CV_IDENTIFIER: case t_const_value::CV_INTEGER: if (should_force_string) { write_string(number_to_string(value->get_integer())); } else { write_number(value->get_integer()); } break; case t_const_value::CV_DOUBLE: if (should_force_string) { write_string(number_to_string(value->get_double())); } else { write_number(value->get_double()); } break; case t_const_value::CV_STRING: write_string(value->get_string()); break; case t_const_value::CV_LIST: { start_array(); std::vector list = value->get_list(); std::vector::iterator lit; for (lit = list.begin(); lit != list.end(); ++lit) { write_comma_if_needed(); f_json_ << indent(); write_const_value(*lit); indicate_comma_needed(); } end_array(); break; } case t_const_value::CV_MAP: { start_object(NO_INDENT); std::map map = value->get_map(); std::map::iterator mit; for (mit = map.begin(); mit != map.end(); ++mit) { write_comma_if_needed(); f_json_ << indent(); // JSON objects only allow string keys write_const_value(mit->first, FORCE_STRING); f_json_ << ": "; write_const_value(mit->second); indicate_comma_needed(); } end_object(); break; } default: f_json_ << "null"; break; } } string t_json_generator::json_str(const string& str) { return quot + escape_json_string(str) + quot; } void t_json_generator::generate_constant(t_const* con) { start_object(); write_key_and_string("name", con->get_name()); write_key_and_string("typeId", get_type_name(con->get_type())); write_type_spec_object("type", con->get_type()); if (con->has_doc()) { write_key_and_string("doc", con->get_doc()); } write_key_and("value"); write_const_value(con->get_value()); end_object(); } void t_json_generator::generate_enum(t_enum* tenum) { start_object(); write_key_and_string("name", tenum->get_name()); if (tenum->has_doc()) { write_key_and_string("doc", tenum->get_doc()); } if (tenum->annotations_.size() > 0) { write_key_and("annotations"); start_object(); for (auto & annotation : tenum->annotations_) { write_key_and_string(annotation.first, annotation.second); } end_object(); } write_key_and("members"); start_array(); vector values = tenum->get_constants(); vector::iterator val_iter; for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { write_comma_if_needed(); t_enum_value* val = (*val_iter); start_object(); write_key_and_string("name", val->get_name()); write_key_and_integer("value", val->get_value()); if (val->has_doc()) { write_key_and_string("doc", val->get_doc()); } end_object(); indicate_comma_needed(); } end_array(); end_object(); } void t_json_generator::generate_struct(t_struct* tstruct) { start_object(); write_key_and_string("name", tstruct->get_name()); if (tstruct->has_doc()) { write_key_and_string("doc", tstruct->get_doc()); } if (tstruct->annotations_.size() > 0) { write_key_and("annotations"); start_object(); for (auto & annotation : tstruct->annotations_) { write_key_and_string(annotation.first, annotation.second); } end_object(); } write_key_and_bool("isException", tstruct->is_xception()); write_key_and_bool("isUnion", tstruct->is_union()); write_key_and("fields"); start_array(); vector members = tstruct->get_members(); vector::iterator mem_iter; for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) { write_comma_if_needed(); generate_field(*mem_iter); indicate_comma_needed(); } end_array(); end_object(); } void t_json_generator::generate_service(t_service* tservice) { start_object(); write_key_and_string("name", get_qualified_name(tservice)); if (tservice->get_extends()) { write_key_and_string("extends", get_qualified_name(tservice->get_extends())); } if (tservice->has_doc()) { write_key_and_string("doc", tservice->get_doc()); } if (tservice->annotations_.size() > 0) { write_key_and("annotations"); start_object(); for (auto & annotation : tservice->annotations_) { write_key_and_string(annotation.first, annotation.second); } end_object(); } write_key_and("functions"); start_array(); vector functions = tservice->get_functions(); vector::iterator fn_iter = functions.begin(); for (; fn_iter != functions.end(); fn_iter++) { write_comma_if_needed(); generate_function(*fn_iter); indicate_comma_needed(); } end_array(); end_object(); } void t_json_generator::generate_function(t_function* tfunc) { start_object(); write_key_and_string("name", tfunc->get_name()); write_key_and_string("returnTypeId", get_type_name(tfunc->get_returntype())); write_type_spec_object("returnType", tfunc->get_returntype()); write_key_and_bool("oneway", tfunc->is_oneway()); if (tfunc->has_doc()) { write_key_and_string("doc", tfunc->get_doc()); } if (tfunc->annotations_.size() > 0) { write_key_and("annotations"); start_object(); for (auto & annotation : tfunc->annotations_) { write_key_and_string(annotation.first, annotation.second); } end_object(); } write_key_and("arguments"); start_array(); vector members = tfunc->get_arglist()->get_members(); vector::iterator mem_iter = members.begin(); for (; mem_iter != members.end(); mem_iter++) { write_comma_if_needed(); generate_field(*mem_iter); indicate_comma_needed(); } end_array(); write_key_and("exceptions"); start_array(); vector excepts = tfunc->get_xceptions()->get_members(); vector::iterator ex_iter = excepts.begin(); for (; ex_iter != excepts.end(); ex_iter++) { write_comma_if_needed(); generate_field(*ex_iter); indicate_comma_needed(); } end_array(); end_object(); } void t_json_generator::generate_field(t_field* field) { start_object(); write_key_and_integer("key", field->get_key()); write_key_and_string("name", field->get_name()); write_key_and_string("typeId", get_type_name(field->get_type())); write_type_spec_object("type", field->get_type()); if (field->has_doc()) { write_key_and_string("doc", field->get_doc()); } if (field->annotations_.size() > 0) { write_key_and("annotations"); start_object(); for (auto & annotation : field->annotations_) { write_key_and_string(annotation.first, annotation.second); } end_object(); } write_key_and("required"); switch (field->get_req()) { case t_field::T_REQUIRED: write_string("required"); break; case t_field::T_OPT_IN_REQ_OUT: write_string("req_out"); break; default: write_string("optional"); break; } if (field->get_value()) { write_key_and("default"); write_const_value(field->get_value()); } end_object(); } string t_json_generator::get_type_name(t_type* ttype) { ttype = ttype->get_true_type(); if (ttype->is_list()) { return "list"; } if (ttype->is_set()) { return "set"; } if (ttype->is_map()) { return "map"; } if (ttype->is_enum()) { return "i32"; } if (ttype->is_struct()) { return ((t_struct*)ttype)->is_union() ? "union" : "struct"; } if (ttype->is_xception()) { return "exception"; } if (ttype->is_base_type()) { t_base_type* tbasetype = (t_base_type*)ttype; return tbasetype->is_binary() ? "binary" : t_base_type::t_base_name(tbasetype->get_base()); } return "(unknown)"; } string t_json_generator::get_qualified_name(t_type* ttype) { if (should_merge_includes_ || ttype->get_program() == program_) { return ttype->get_name(); } return ttype->get_program()->get_name() + "." + ttype->get_name(); } THRIFT_REGISTER_GENERATOR(json, "JSON", " merge: Generate output with included files merged\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_lua_generator.cc000066400000000000000000001166251420101504100250330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::ostream; using std::string; using std::vector; using std::map; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * LUA code generator. * */ class t_lua_generator : public t_oop_generator { public: t_lua_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; gen_requires_ = true; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("omit_requires") == 0) { gen_requires_ = false; } else { throw "unknown option lua:" + iter->first; } } out_dir_base_ = "gen-lua"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; std::string render_const_value(t_type* type, t_const_value* value); private: /** * True iff we should generate lua require statements. */ bool gen_requires_; /** * Struct-level generation functions */ void generate_lua_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false); void generate_lua_struct_reader(std::ostream& out, t_struct* tstruct); void generate_lua_struct_writer(std::ostream& out, t_struct* tstruct); /** * Service-level generation functions */ void generate_service_client(std::ostream& out, t_service* tservice); void generate_service_interface(std::ostream& out, t_service* tservice); void generate_service_processor(std::ostream& out, t_service* tservice); void generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction); void generate_service_helpers(ostream& out, t_service* tservice); void generate_function_helpers(ostream& out, t_function* tfunction); /** * Deserialization (Read) */ void generate_deserialize_field(std::ostream& out, t_field* tfield, bool local, std::string prefix = ""); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, bool local, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, bool local, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); /** * Serialization (Write) */ void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); /** * Helper rendering functions */ std::string lua_includes(); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string argument_list(t_struct* tstruct, std::string prefix = ""); std::string type_to_enum(t_type* ttype); static std::string get_namespace(const t_program* program); std::string autogen_comment() override { return std::string("--\n") + "-- Autogenerated by Thrift\n" + "--\n" + "-- DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "-- @" "generated\n" + "--\n"; } /** * File streams */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_consts_; ofstream_with_content_based_conditional_update f_service_; }; /** * Init and close methods */ void t_lua_generator::init_generator() { // Make output directory string outdir = get_out_dir(); MKDIR(outdir.c_str()); // Make output files string cur_namespace = get_namespace(program_); string f_consts_name = outdir + cur_namespace + "constants.lua"; f_consts_.open(f_consts_name.c_str()); string f_types_name = outdir + cur_namespace + "ttypes.lua"; f_types_.open(f_types_name.c_str()); // Add headers f_consts_ << autogen_comment() << lua_includes(); f_types_ << autogen_comment() << lua_includes(); if (gen_requires_) { f_types_ << endl << "require '" << cur_namespace << "constants'"; } } void t_lua_generator::close_generator() { // Close types file f_types_.close(); f_consts_.close(); } /** * Generate a typedef (essentially a constant) */ void t_lua_generator::generate_typedef(t_typedef* ttypedef) { if (ttypedef->get_type()->get_name().empty()) { return; } f_types_ << endl << endl << indent() << ttypedef->get_symbolic() << " = " << ttypedef->get_type()->get_name(); } /** * Generates code for an enumerated type (table) */ void t_lua_generator::generate_enum(t_enum* tenum) { f_types_ << endl << endl << tenum->get_name() << " = {" << endl; vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end();) { int32_t value = (*c_iter)->get_value(); f_types_ << " " << (*c_iter)->get_name() << " = " << value; ++c_iter; if (c_iter != constants.end()) { f_types_ << ","; } f_types_ << endl; } f_types_ << "}"; } /** * Generate a constant (non-local) value */ void t_lua_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); f_consts_ << endl << endl << name << " = "; f_consts_ << render_const_value(type, value); } /** * Prints the value of a constant with the given type. */ string t_lua_generator::render_const_value(t_type* type, t_const_value* value) { std::ostringstream out; type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << "'" << value->get_string() << "'"; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: out << value->get_integer(); break; case t_base_type::TYPE_I64: out << "lualongnumber.new('" << value->get_integer() << "')"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << type->get_name() << " = {" << endl; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end();) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } indent(out); out << render_const_value(g_type_string, v_iter->first); out << " = "; out << render_const_value(field_type, v_iter->second); ++v_iter; if (v_iter != val.end()) { out << ","; } } out << "}"; indent_down(); } else if (type->is_map()) { out << type->get_name() << "{" << endl; indent_up(); t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end();) { indent(out) << "[" << render_const_value(ktype, v_iter->first) << "] = " << render_const_value(vtype, v_iter->second); ++v_iter; if (v_iter != val.end()) { out << ","; } out << endl; } indent_down(); indent(out) << "}"; } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } out << type->get_name() << " = {" << endl; const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end();) { indent(out); out << "[" << render_const_value(etype, *v_iter) << "]"; if (type->is_set()) { out << " = true"; } else { out << " = false"; } ++v_iter; if (v_iter != val.end()) { out << "," << endl; } } out << "}"; } return out.str(); } /** * Generate a thrift struct */ void t_lua_generator::generate_struct(t_struct* tstruct) { generate_lua_struct_definition(f_types_, tstruct, false); } /** * Generate a thrift exception */ void t_lua_generator::generate_xception(t_struct* txception) { generate_lua_struct_definition(f_types_, txception, true); } /** * Generate a thrift struct or exception (lua table) */ void t_lua_generator::generate_lua_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) { vector::const_iterator m_iter; const vector& members = tstruct->get_members(); indent(out) << endl << endl << tstruct->get_name(); if (is_exception) { out << " = TException:new{" << endl << indent() << " __type = '" << tstruct->get_name() << "'"; if (members.size() > 0) { out << ","; } out << endl; } else { out << " = __TObject:new{" << endl; } indent_up(); for (m_iter = members.begin(); m_iter != members.end();) { indent(out); out << (*m_iter)->get_name(); ++m_iter; if (m_iter != members.end()) { out << "," << endl; } } indent_down(); indent(out); out << endl << "}"; generate_lua_struct_reader(out, tstruct); generate_lua_struct_writer(out, tstruct); } /** * Generate a struct/exception reader */ void t_lua_generator::generate_lua_struct_reader(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // function indent(out) << endl << endl << "function " << tstruct->get_name() << ":read(iprot)" << endl; indent_up(); indent(out) << "iprot:readStructBegin()" << endl; // while: Read in fields indent(out) << "while true do" << endl; indent_up(); // if: Check what to read indent(out) << "local fname, ftype, fid = iprot:readFieldBegin()" << endl; indent(out) << "if ftype == TType.STOP then" << endl; indent_up(); indent(out) << "break" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent_down(); indent(out) << "elseif fid == " << (*f_iter)->get_key() << " then" << endl; indent_up(); indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << " then" << endl; indent_up(); // Read field contents generate_deserialize_field(out, *f_iter, false, "self."); indent_down(); indent(out) << "else" << endl; indent(out) << " iprot:skip(ftype)" << endl; indent(out) << "end" << endl; } // end if indent_down(); indent(out) << "else" << endl; indent(out) << " iprot:skip(ftype)" << endl; indent(out) << "end" << endl; indent(out) << "iprot:readFieldEnd()" << endl; // end while indent_down(); indent(out) << "end" << endl; indent(out) << "iprot:readStructEnd()" << endl; // end function indent_down(); indent(out); out << "end"; } /** * Generate a struct/exception writer */ void t_lua_generator::generate_lua_struct_writer(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // function indent(out) << endl << endl << "function " << tstruct->get_name() << ":write(oprot)" << endl; indent_up(); indent(out) << "oprot:writeStructBegin('" << tstruct->get_name() << "')" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { // To check element of self whether nil or not. // avoid the value(false) of BOOL is lost. indent(out) << "if self." << (*f_iter)->get_name() << " ~= nil then" << endl; indent_up(); indent(out) << "oprot:writeFieldBegin('" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ")" << endl; // Write field contents generate_serialize_field(out, *f_iter, "self."); indent(out) << "oprot:writeFieldEnd()" << endl; indent_down(); indent(out) << "end" << endl; } indent(out) << "oprot:writeFieldStop()" << endl; indent(out) << "oprot:writeStructEnd()" << endl; // end function indent_down(); indent(out); out << "end"; } /** * Generate a thrift service */ void t_lua_generator::generate_service(t_service* tservice) { // Get output directory string outdir = get_out_dir(); // Open the file for writing string cur_ns = get_namespace(program_); string f_service_name = outdir + cur_ns + tservice->get_name() + ".lua"; f_service_.open(f_service_name.c_str()); // Headers f_service_ << autogen_comment() << lua_includes(); if (gen_requires_) { f_service_ << endl << "require '" << cur_ns << "ttypes'" << endl; if (tservice->get_extends() != nullptr) { f_service_ << "require '" << get_namespace(tservice->get_extends()->get_program()) << tservice->get_extends()->get_name() << "'" << endl; } } f_service_ << endl; generate_service_client(f_service_, tservice); generate_service_interface(f_service_, tservice); generate_service_processor(f_service_, tservice); generate_service_helpers(f_service_, tservice); // Close the file f_service_.close(); } void t_lua_generator::generate_service_interface(ostream& out, t_service* tservice) { string classname = tservice->get_name() + "Iface"; t_service* extends_s = tservice->get_extends(); // Interface object definition out << classname << " = "; if (extends_s) { out << extends_s->get_name() << "Iface:new{" << endl; } else { out << "__TObject:new{" << endl; } out << " __type = '" << classname << "'" << endl << "}" << endl << endl; } void t_lua_generator::generate_service_client(ostream& out, t_service* tservice) { string classname = tservice->get_name() + "Client"; t_service* extends_s = tservice->get_extends(); // Client object definition out << classname << " = __TObject.new("; if (extends_s != nullptr) { out << extends_s->get_name() << "Client"; } else { out << "__TClient"; } out << ", {" << endl << " __type = '" << classname << "'" << endl << "})" << endl; // Send/Recv functions vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string sig = function_signature(*f_iter); string funcname = (*f_iter)->get_name(); // Wrapper function indent(out) << endl << "function " << classname << ":" << sig << endl; indent_up(); indent(out) << "self:send_" << sig << endl << indent(); if (!(*f_iter)->is_oneway()) { if (!(*f_iter)->get_returntype()->is_void()) { out << "return "; } out << "self:recv_" << sig << endl; } indent_down(); indent(out) << "end" << endl; // Send function indent(out) << endl << "function " << classname << ":send_" << sig << endl; indent_up(); indent(out) << "self.oprot:writeMessageBegin('" << funcname << "', " << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") << ", self._seqid)" << endl; indent(out) << "local args = " << funcname << "_args:new{}" << endl; // Set the args const vector& args = (*f_iter)->get_arglist()->get_members(); vector::const_iterator fld_iter; for (fld_iter = args.begin(); fld_iter != args.end(); ++fld_iter) { std::string argname = (*fld_iter)->get_name(); if ((*fld_iter)->get_value() != nullptr) { // Insert default value for nil arguments t_type* type = get_true_type((*fld_iter)->get_type()); indent(out) << "if " << argname << " ~= nil then" << endl; indent_up(); indent(out) << "args." << argname << " = " << argname << endl; indent_down(); indent(out) << "else" << endl; indent_up(); indent(out) << "args." << argname << " = " << render_const_value(type, (*fld_iter)->get_value()) << endl; indent_down(); indent(out) << "end" << endl; } else { indent(out) << "args." << argname << " = " << argname << endl; } } indent(out) << "args:write(self.oprot)" << endl; indent(out) << "self.oprot:writeMessageEnd()" << endl; indent(out) << "self.oprot.trans:flush()" << endl; indent_down(); indent(out) << "end" << endl; // Recv function if (!(*f_iter)->is_oneway()) { indent(out) << endl << "function " << classname << ":recv_" << sig << endl; indent_up(); out << indent() << "local fname, mtype, rseqid = self.iprot:" << "readMessageBegin()" << endl << indent() << "if mtype == TMessageType.EXCEPTION then" << endl << indent() << " local x = TApplicationException:new{}" << endl << indent() << " x:read(self.iprot)" << endl << indent() << " self.iprot:readMessageEnd()" << endl << indent() << " error(x)" << endl << indent() << "end" << endl << indent() << "local result = " << funcname << "_result:new{}" << endl << indent() << "result:read(self.iprot)" << endl << indent() << "self.iprot:readMessageEnd()" << endl; // Return the result if it's not a void function if (!(*f_iter)->get_returntype()->is_void()) { out << indent() << "if result.success ~= nil then" << endl << indent() << " return result.success" << endl; // Throw custom exceptions const std::vector& xf = (*f_iter)->get_xceptions()->get_members(); vector::const_iterator x_iter; for (x_iter = xf.begin(); x_iter != xf.end(); ++x_iter) { out << indent() << "elseif result." << (*x_iter)->get_name() << " then" << endl << indent() << " error(result." << (*x_iter)->get_name() << ")" << endl; } out << indent() << "end" << endl << indent() << "error(TApplicationException:new{errorCode = " << "TApplicationException.MISSING_RESULT})" << endl; } indent_down(); indent(out) << "end" << endl; } } } void t_lua_generator::generate_service_processor(ostream& out, t_service* tservice) { string classname = tservice->get_name() + "Processor"; t_service* extends_s = tservice->get_extends(); // Define processor table out << endl << classname << " = __TObject.new("; if (extends_s != nullptr) { out << extends_s->get_name() << "Processor" << endl; } else { out << "__TProcessor" << endl; } out << ", {" << endl << " __type = '" << classname << "'" << endl << "})" << endl; // Process function indent(out) << endl << "function " << classname << ":process(iprot, oprot, server_ctx)" << endl; indent_up(); indent(out) << "local name, mtype, seqid = iprot:readMessageBegin()" << endl; indent(out) << "local func_name = 'process_' .. name" << endl; indent(out) << "if not self[func_name] or ttype(self[func_name]) ~= 'function' then" << endl; indent_up(); indent(out) << "if oprot ~= nil then"; indent_up(); out << endl << indent() << "iprot:skip(TType.STRUCT)" << endl << indent() << "iprot:readMessageEnd()" << endl << indent() << "x = TApplicationException:new{" << endl << indent() << " errorCode = TApplicationException.UNKNOWN_METHOD" << endl << indent() << "}" << endl << indent() << "oprot:writeMessageBegin(name, TMessageType.EXCEPTION, " << "seqid)" << endl << indent() << "x:write(oprot)" << endl << indent() << "oprot:writeMessageEnd()" << endl << indent() << "oprot.trans:flush()" << endl; indent_down(); out << indent() << "end" << endl << indent() << "return false, 'Unknown function '..name" << endl; indent_down(); indent(out) << "else" << endl << indent() << " return self[func_name](self, seqid, iprot, oprot, server_ctx)" << endl << indent() << "end" << endl; indent_down(); indent(out) << "end" << endl; // Generate the process subfunctions vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(out, tservice, *f_iter); } } void t_lua_generator::generate_process_function(ostream& out, t_service* tservice, t_function* tfunction) { string classname = tservice->get_name() + "Processor"; string argsname = tfunction->get_name() + "_args"; string resultname = tfunction->get_name() + "_result"; string fn_name = tfunction->get_name(); indent(out) << endl << "function " << classname << ":process_" << fn_name << "(seqid, iprot, oprot, server_ctx)" << endl; indent_up(); // Read the request out << indent() << "local args = " << argsname << ":new{}" << endl << indent() << "local reply_type = TMessageType.REPLY" << endl << indent() << "args:read(iprot)" << endl << indent() << "iprot:readMessageEnd()" << endl; if (!tfunction->is_oneway()) { out << indent() << "local result = " << resultname << ":new{}" << endl; } out << indent() << "local status, res = pcall(self.handler." << fn_name << ", self.handler"; // Print arguments t_struct* args = tfunction->get_arglist(); if (args->get_members().size() > 0) { out << ", " << argument_list(args, "args."); } out << ")" << endl; if (!tfunction->is_oneway()) { // Check for errors out << indent() << "if not status then" << endl << indent() << " reply_type = TMessageType.EXCEPTION" << endl << indent() << " result = TApplicationException:new{message = res}" << endl; // Handle custom exceptions const std::vector& xf = tfunction->get_xceptions()->get_members(); if (xf.size() > 0) { vector::const_iterator x_iter; for (x_iter = xf.begin(); x_iter != xf.end(); ++x_iter) { out << indent() << "elseif ttype(res) == '" << (*x_iter)->get_type()->get_name() << "' then" << endl << indent() << " result." << (*x_iter)->get_name() << " = res" << endl; } } // Set the result and write the reply out << indent() << "else" << endl << indent() << " result.success = res" << endl << indent() << "end" << endl << indent() << "oprot:writeMessageBegin('" << fn_name << "', reply_type, " << "seqid)" << endl << indent() << "result:write(oprot)" << endl << indent() << "oprot:writeMessageEnd()" << endl << indent() << "oprot.trans:flush()" << endl; } out << indent() << "return status, res" << endl; indent_down(); indent(out) << "end" << endl; } // Service helpers void t_lua_generator::generate_service_helpers(ostream& out, t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; out << endl << "-- HELPER FUNCTIONS AND STRUCTURES"; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_lua_struct_definition(out, ts, false); generate_function_helpers(out, *f_iter); } } void t_lua_generator::generate_function_helpers(ostream& out, t_function* tfunction) { if (!tfunction->is_oneway()) { t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_lua_struct_definition(out, &result, false); } } /** * Deserialize (Read) */ void t_lua_generator::generate_deserialize_field(ostream& out, t_field* tfield, bool local, string prefix) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + tfield->get_name(); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, local, name); } else if (type->is_container()) { generate_deserialize_container(out, type, local, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << (local ? "local " : "") << name << " = iprot:"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << "readString()"; break; case t_base_type::TYPE_BOOL: out << "readBool()"; break; case t_base_type::TYPE_I8: out << "readByte()"; break; case t_base_type::TYPE_I16: out << "readI16()"; break; case t_base_type::TYPE_I32: out << "readI32()"; break; case t_base_type::TYPE_I64: out << "readI64()"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble()"; break; default: throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "readI32()"; } out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type->get_name().c_str()); } } void t_lua_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, bool local, string prefix) { indent(out) << (local ? "local " : "") << prefix << " = " << tstruct->get_name() << ":new{}" << endl << indent() << prefix << ":read(iprot)" << endl; } void t_lua_generator::generate_deserialize_container(ostream& out, t_type* ttype, bool local, string prefix) { string size = tmp("_size"); string ktype = tmp("_ktype"); string vtype = tmp("_vtype"); string etype = tmp("_etype"); t_field fsize(g_type_i32, size); t_field fktype(g_type_i8, ktype); t_field fvtype(g_type_i8, vtype); t_field fetype(g_type_i8, etype); // Declare variables, read header indent(out) << (local ? "local " : "") << prefix << " = {}" << endl; if (ttype->is_map()) { indent(out) << "local " << ktype << ", " << vtype << ", " << size << " = iprot:readMapBegin() " << endl; } else if (ttype->is_set()) { indent(out) << "local " << etype << ", " << size << " = iprot:readSetBegin()" << endl; } else if (ttype->is_list()) { indent(out) << "local " << etype << ", " << size << " = iprot:readListBegin()" << endl; } // Deserialize indent(out) << "for _i=1," << size << " do" << endl; indent_up(); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } indent_down(); indent(out) << "end" << endl; // Read container end if (ttype->is_map()) { indent(out) << "iprot:readMapEnd()" << endl; } else if (ttype->is_set()) { indent(out) << "iprot:readSetEnd()" << endl; } else if (ttype->is_list()) { indent(out) << "iprot:readListEnd()" << endl; } } void t_lua_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { // A map is represented by a table indexable by any lua type string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); generate_deserialize_field(out, &fkey, true); generate_deserialize_field(out, &fval, true); indent(out) << prefix << "[" << key << "] = " << val << endl; } void t_lua_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { // A set is represented by a table indexed by the value string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); generate_deserialize_field(out, &felem, true); indent(out) << prefix << "[" << elem << "] = " << elem << endl; } void t_lua_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { // A list is represented by a table indexed by integer values // LUA natively provides all of the functions required to maintain a list string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); generate_deserialize_field(out, &felem, true); indent(out) << "table.insert(" << prefix << ", " << elem << ")" << endl; } /** * Serialize (Write) */ void t_lua_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); string name = prefix + tfield->get_name(); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_serialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << "oprot:"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << "writeString(" << name << ")"; break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ")"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ")"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ")"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ")"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ")"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ")"; break; default: throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32(" << name << ")"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", name.c_str(), type->get_name().c_str()); } } void t_lua_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; indent(out) << prefix << ":write(oprot)" << endl; } void t_lua_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { // Begin writing if (ttype->is_map()) { indent(out) << "oprot:writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "ttable_size(" << prefix << "))" << endl; } else if (ttype->is_set()) { indent(out) << "oprot:writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << "ttable_size(" << prefix << "))" << endl; } else if (ttype->is_list()) { indent(out) << "oprot:writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << "#" << prefix << ")" << endl; } // Serialize if (ttype->is_map()) { string kiter = tmp("kiter"); string viter = tmp("viter"); indent(out) << "for " << kiter << "," << viter << " in pairs(" << prefix << ") do" << endl; indent_up(); generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); indent_down(); indent(out) << "end" << endl; } else if (ttype->is_set()) { string iter = tmp("iter"); indent(out) << "for " << iter << ",_ in pairs(" << prefix << ") do" << endl; indent_up(); generate_serialize_set_element(out, (t_set*)ttype, iter); indent_down(); indent(out) << "end" << endl; } else if (ttype->is_list()) { string iter = tmp("iter"); indent(out) << "for _," << iter << " in ipairs(" << prefix << ") do" << endl; indent_up(); generate_serialize_list_element(out, (t_list*)ttype, iter); indent_down(); indent(out) << "end" << endl; } // Finish writing if (ttype->is_map()) { indent(out) << "oprot:writeMapEnd()" << endl; } else if (ttype->is_set()) { indent(out) << "oprot:writeSetEnd()" << endl; } else if (ttype->is_list()) { indent(out) << "oprot:writeListEnd()" << endl; } } void t_lua_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter) { t_field kfield(tmap->get_key_type(), kiter); generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), viter); generate_serialize_field(out, &vfield, ""); } void t_lua_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } void t_lua_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Helper rendering functions */ string t_lua_generator::lua_includes() { if (gen_requires_) { return "\n\nrequire 'Thrift'"; } else { return ""; } } string t_lua_generator::get_namespace(const t_program* program) { std::string real_module = program->get_namespace("lua"); if (real_module.empty()) { return program->get_name() + "_"; } return real_module + "_"; } string t_lua_generator::function_signature(t_function* tfunction, string prefix) { (void)prefix; std::string ret = tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")"; return ret; } string t_lua_generator::argument_list(t_struct* tstruct, string prefix) { const vector& fields = tstruct->get_members(); vector::const_iterator fld_iter; std::string ret = ""; for (fld_iter = fields.begin(); fld_iter != fields.end();) { ret += prefix + (*fld_iter)->get_name(); ++fld_iter; if (fld_iter != fields.end()) { ret += ", "; } } return ret; } string t_lua_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.STRING"; case t_base_type::TYPE_BOOL: return "TType.BOOL"; case t_base_type::TYPE_I8: return "TType.BYTE"; case t_base_type::TYPE_I16: return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; } } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_list()) { return "TType.LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } THRIFT_REGISTER_GENERATOR( lua, "Lua", " omit_requires: Suppress generation of require 'somefile'.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_markdown_generator.cc000066400000000000000000001003631420101504100260640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostringstream; using std::pair; using std::string; using std::stringstream; using std::vector; static const char endl = '\n'; // avoid ostream << std::endl flushes /** * MARKDOWN code generator * * mostly copy/pasting/tweaking from t_html_generator's work. */ class t_markdown_generator : public t_generator { enum input_type { INPUT_UNKNOWN, INPUT_UTF8, INPUT_PLAIN }; public: t_markdown_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; unsafe_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("noescape") == 0) { unsafe_ = true; } else if( iter->first.compare("suffix") == 0 && !iter->second.empty()) { extension_ = "." + iter->second; } else { throw "unknown option markdown:" + iter->first; } } out_dir_base_ = "gen-markdown"; input_type_ = INPUT_UNKNOWN; escape_.clear(); escape_['&'] = "&"; escape_['<'] = "<"; escape_['>'] = ">"; escape_['"'] = """; escape_['\''] = "'"; init_allowed__markup(); } void generate_program() override; void generate_program_toc(); void generate_program_toc_row(t_program* tprog); void generate_program_toc_rows(t_program* tprog, std::vector& finished); void generate_index(); std::string escape_html(std::string const& str); std::string escape_html_tags(std::string const& str); std::string make_file_link(std::string name); std::string make_file_name(std::string name); bool is_utf8_sequence(std::string const& str, size_t firstpos); void detect_input_encoding(std::string const& str, size_t firstpos); void init_allowed__markup(); /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_service(t_service* tservice) override; void generate_xception(t_struct* txception) override; void print_doc(t_doc* tdoc); int print_type(t_type* ttype); void print_const_value(t_type* type, t_const_value* tvalue); void print_fn_args_doc(t_function* tfunction); std::string str_to_id(const std::string& s); private: ofstream_with_content_based_conditional_update f_out_; std::string current_file_; input_type input_type_; std::map allowed_markup; bool unsafe_; std::string extension_; }; /** * string to markdown-id link reference */ std::string t_markdown_generator::str_to_id(const std::string& s) { std::string id; for(auto chr=s.begin();chr<=s.end(); ++chr) { if(*chr == '.' || *chr == 0) continue; id += tolower(*chr); } return id; } /** * Emits the Table of Contents links at the top of the module's page */ void t_markdown_generator::generate_program_toc() { f_out_ << "| Module | Services & Functions | Data types | Constants |" << endl << "| --- | --- | --- | --- |" << endl; generate_program_toc_row(program_); f_out_ << endl; } /** * Recurses through from the provided program and generates a ToC row * for each discovered program exactly once by maintaining the list of * completed rows in 'finished' */ void t_markdown_generator::generate_program_toc_rows(t_program* tprog, std::vector& finished) { for (auto & iter : finished) { if (tprog->get_path() == iter->get_path()) { return; } } finished.push_back(tprog); generate_program_toc_row(tprog); vector includes = tprog->get_includes(); for (auto & include : includes) { generate_program_toc_rows(include, finished); } } /** * Emits the Table of Contents links at the top of the module's page */ void t_markdown_generator::generate_program_toc_row(t_program* tprog) { // "| Module | Services | Data types | Constants | vector> filling; string fname = make_file_name(tprog->get_name()); filling.emplace_back(); auto fill = &filling.back(); (*fill)[0] = tprog->get_name(); if (!tprog->get_services().empty()) { vector services = tprog->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { if(sv_iter != services.begin()) { filling.emplace_back(); fill = &filling.back(); } string name = get_service_name(*sv_iter); (*fill)[1] = "[" + name + "](" + make_file_link(fname) + "#service-" + str_to_id(name) + ")"; vector functions = (*sv_iter)->get_functions(); vector::iterator fn_iter; for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { string fn_name = (*fn_iter)->get_name(); filling.emplace_back(); fill = &filling.back(); (*fill)[1] = " [ • " + fn_name + "](" + make_file_link(fname) + "#function-" + str_to_id(name + fn_name) + ")"; } } } // Data Types Column auto it_fill = filling.begin(); if (!tprog->get_enums().empty()) { vector enums = tprog->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { if(it_fill == filling.end()) { filling.emplace_back(); fill = &filling.back(); it_fill = filling.end(); } else { fill = &*it_fill; ++it_fill; } string name = (*en_iter)->get_name(); (*fill)[2] = "[" + name + "](" + make_file_link(fname) + "#enumeration-" + str_to_id(name) + ")"; } } if (!tprog->get_typedefs().empty()) { vector typedefs = tprog->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { if(it_fill == filling.end()) { filling.emplace_back(); fill = &filling.back(); it_fill = filling.end(); } else { fill = &*it_fill; ++it_fill; } string name = (*td_iter)->get_symbolic(); (*fill)[2] = "[" + name + "](" + make_file_link(fname) + "#typedef-" + str_to_id(name) + ")"; } } if (!tprog->get_objects().empty()) { vector objects = tprog->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { if(it_fill == filling.end()) { filling.emplace_back(); fill = &filling.back(); it_fill = filling.end(); } else { fill = &*it_fill; ++it_fill; } string name = (*o_iter)->get_name(); (*fill)[2] = "[" + name + "](" + make_file_link(fname); if ((*o_iter)->is_xception()) { (*fill)[2] += "#exception-"; } else if ((*o_iter)->is_struct() && (*o_iter)->is_union()) { (*fill)[2] += "#union-"; } else { (*fill)[2] += "#struct-"; } (*fill)[2] += str_to_id(name) + ")"; } } // Constants Column it_fill = filling.begin(); if (!tprog->get_consts().empty()) { map const_markdown; vector consts = tprog->get_consts(); vector::iterator con_iter; for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) { if(it_fill == filling.end()) { filling.emplace_back(); fill = &filling.back(); it_fill = filling.end(); } else { fill = &*it_fill; ++it_fill; } string name = (*con_iter)->get_name(); (*fill)[3] = "[" + name + "](" + make_file_link(fname) + "#constant-" + str_to_id(name) + ")"; } } for(auto& fill : filling) { for(auto& c : fill) f_out_ << '|' << c; f_out_ << '|' << endl; } f_out_ << endl; } /** * Prepares for file generation by opening up the necessary file output * stream. */ void t_markdown_generator::generate_program() { // Make output directory MKDIR(get_out_dir().c_str()); string pname = program_->get_name(); current_file_ = make_file_name(pname); string fname = get_out_dir() + current_file_; f_out_.open(fname.c_str()); f_out_ << "# Thrift module: " << pname << endl << endl; print_doc(program_); f_out_ << endl << endl; generate_program_toc(); if (!program_->get_consts().empty()) { f_out_ << "***" << endl << "## Constants" << endl << endl; vector consts = program_->get_consts(); f_out_ << "|Constant|Type|Value||" << endl << "|---|---|---|---|" << endl; generate_consts(consts); f_out_ << endl; } if (!program_->get_enums().empty()) { f_out_ << "***" << endl << "## Enumerations" << endl << endl; // Generate enums vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } } if (!program_->get_typedefs().empty()) { f_out_ << "***" << endl << "## Type declarations" << endl << endl; // Generate typedefs vector typedefs = program_->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { generate_typedef(*td_iter); } } if (!program_->get_objects().empty()) { f_out_ << "***" << endl << "## Data structures" << endl << endl; // Generate structs and exceptions in declared order vector objects = program_->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { if ((*o_iter)->is_xception()) { generate_xception(*o_iter); } else { generate_struct(*o_iter); } } } if (!program_->get_services().empty()) { f_out_ << "***" << endl << "## Services" << endl << endl; // Generate services vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { service_name_ = get_service_name(*sv_iter); generate_service(*sv_iter); } } f_out_ << endl; f_out_.close(); generate_index(); } /** * Emits the index(.ext) file for the recursive set of Thrift programs */ void t_markdown_generator::generate_index() { current_file_ = make_file_name("index"); string index_fname = get_out_dir() + current_file_; f_out_.open(index_fname.c_str()); f_out_ << "# Thrift declarations" << endl; f_out_ << "| Module | Services & Functions | Data types | Constants |" << endl << "| --- | --- | --- | --- |" << endl; vector programs; generate_program_toc_rows(program_, programs); f_out_ << endl; f_out_.close(); } /** * Returns the target file for a link * The returned string is empty, whenever filename refers to the current file. */ std::string t_markdown_generator::make_file_link(std::string filename) { return (current_file_.compare(filename) != 0) ? filename : ""; } /** * Returns the target file for a link * The returned string is empty, whenever filename refers to the current file. */ std::string t_markdown_generator::make_file_name(std::string filename) { return extension_.empty() ? filename : (filename + extension_); } /** * If the provided documentable object has documentation attached, this * will emit it to the output stream in HTML format. */ void t_markdown_generator::print_doc(t_doc* tdoc) { if (tdoc->has_doc()) { if (unsafe_) { f_out_ << tdoc->get_doc(); } else { f_out_ << escape_html(tdoc->get_doc()); } } } bool t_markdown_generator::is_utf8_sequence(std::string const& str, size_t firstpos) { // leading char determines the length of the sequence unsigned char c = str.at(firstpos); int count = 0; if ((c & 0xE0) == 0xC0) { count = 1; } else if ((c & 0xF0) == 0xE0) { count = 2; } else if ((c & 0xF8) == 0xF0) { count = 3; } else if ((c & 0xFC) == 0xF8) { count = 4; } else if ((c & 0xFE) == 0xFC) { count = 5; } else { // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 leading byte", c, int(c)); return false; // no UTF-8 } // following chars size_t pos = firstpos + 1; while ((pos < str.length()) && (0 < count)) { c = str.at(pos); if ((c & 0xC0) != 0x80) { // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 following byte", c, int(c)); return false; // no UTF-8 } --count; ++pos; } // true if the sequence is complete return (0 == count); } void t_markdown_generator::detect_input_encoding(std::string const& str, size_t firstpos) { if (is_utf8_sequence(str, firstpos)) { pdebug("Input seems to be already UTF-8 encoded"); input_type_ = INPUT_UTF8; return; } // fallback pwarning(1, "Input is not UTF-8, treating as plain ANSI"); input_type_ = INPUT_PLAIN; } void t_markdown_generator::init_allowed__markup() { allowed_markup.clear(); // standalone tags allowed_markup["br"] = 1; allowed_markup["br/"] = 1; allowed_markup["img"] = 1; // paired tags allowed_markup["b"] = 1; allowed_markup["/b"] = 1; allowed_markup["u"] = 1; allowed_markup["/u"] = 1; allowed_markup["i"] = 1; allowed_markup["/i"] = 1; allowed_markup["s"] = 1; allowed_markup["/s"] = 1; allowed_markup["big"] = 1; allowed_markup["/big"] = 1; allowed_markup["small"] = 1; allowed_markup["/small"] = 1; allowed_markup["sup"] = 1; allowed_markup["/sup"] = 1; allowed_markup["sub"] = 1; allowed_markup["/sub"] = 1; allowed_markup["pre"] = 1; allowed_markup["/pre"] = 1; allowed_markup["tt"] = 1; allowed_markup["/tt"] = 1; allowed_markup["ul"] = 1; allowed_markup["/ul"] = 1; allowed_markup["ol"] = 1; allowed_markup["/ol"] = 1; allowed_markup["li"] = 1; allowed_markup["/li"] = 1; allowed_markup["a"] = 1; allowed_markup["/a"] = 1; allowed_markup["p"] = 1; allowed_markup["/p"] = 1; allowed_markup["code"] = 1; allowed_markup["/code"] = 1; allowed_markup["dl"] = 1; allowed_markup["/dl"] = 1; allowed_markup["dt"] = 1; allowed_markup["/dt"] = 1; allowed_markup["dd"] = 1; allowed_markup["/dd"] = 1; allowed_markup["h1"] = 1; allowed_markup["/h1"] = 1; allowed_markup["h2"] = 1; allowed_markup["/h2"] = 1; allowed_markup["h3"] = 1; allowed_markup["/h3"] = 1; allowed_markup["h4"] = 1; allowed_markup["/h4"] = 1; allowed_markup["h5"] = 1; allowed_markup["/h5"] = 1; allowed_markup["h6"] = 1; allowed_markup["/h6"] = 1; } std::string t_markdown_generator::escape_html_tags(std::string const& str) { std::ostringstream result; unsigned char c = '?'; size_t lastpos; size_t firstpos = 0; while (firstpos < str.length()) { // look for non-ASCII char lastpos = firstpos; while (lastpos < str.length()) { c = str.at(lastpos); if (('<' == c) || ('>' == c)) { break; } ++lastpos; } // copy what we got so far if (lastpos > firstpos) { result << str.substr(firstpos, lastpos - firstpos); firstpos = lastpos; } // reached the end? if (firstpos >= str.length()) { break; } // tag end without corresponding begin ++firstpos; if ('>' == c) { result << ">"; continue; } // extract the tag std::ostringstream tagstream; while (firstpos < str.length()) { c = str.at(firstpos); ++firstpos; if ('<' == c) { tagstream << "<"; // nested begin? } else if ('>' == c) { break; } else { tagstream << c; // not very efficient, but tags should be quite short } } // we allow for several markup in docstrings, all else will become escaped string tag_content = tagstream.str(); string tag_key = tag_content; size_t first_white = tag_key.find_first_of(" \t\f\v\n\r"); if (first_white != string::npos) { tag_key.erase(first_white); } for (char & i : tag_key) { i = tolower(i); } if (allowed_markup.find(tag_key) != allowed_markup.end()) { result << "<" << tag_content << ">"; } else { result << "<" << tagstream.str() << ">"; pverbose("illegal markup <%s> in doc-comment\n", tag_key.c_str()); } } return result.str(); } std::string t_markdown_generator::escape_html(std::string const& str) { // the generated HTML header says it is UTF-8 encoded // if UTF-8 input has been detected before, we don't need to change anything //if (input_type_ == INPUT_UTF8) { // return escape_html_tags(str); //} // convert unsafe chars to their &#; equivalent std::ostringstream result; unsigned char c = '?'; unsigned int ic = 0; size_t lastpos; size_t firstpos = 0; while (firstpos < str.length()) { // look for non-ASCII char lastpos = firstpos; while (lastpos < str.length()) { c = str.at(lastpos); ic = c; if ((32 > ic) || (127 < ic)) { break; } ++lastpos; } // copy what we got so far if (lastpos > firstpos) { result << str.substr(firstpos, lastpos - firstpos); firstpos = lastpos; } // reached the end? if (firstpos >= str.length()) { break; } // some control code? if (ic <= 31) { switch (c) { case '\r': case '\n': case '\t': result << ' '; break; default: // silently consume all other ctrl chars break; } ++firstpos; continue; } // reached the end? if (firstpos >= str.length()) { break; } // try to detect input encoding if (input_type_ == INPUT_UNKNOWN) { detect_input_encoding(str, firstpos); if (input_type_ == INPUT_UTF8) { lastpos = str.length(); result << str.substr(firstpos, lastpos - firstpos); break; } } // convert the character to something useful based on the detected encoding switch (input_type_) { case INPUT_PLAIN: result << "&#" << ic << ";"; ++firstpos; break; default: throw "Unexpected or unrecognized input encoding"; } } return escape_html_tags(result.str()); } /** * Prints out the provided type in Markdown */ int t_markdown_generator::print_type(t_type* ttype) { std::string::size_type len = 0; if (ttype->is_container()) { if (ttype->is_list()) { f_out_ << "list<"; len = 6 + print_type(((t_list*)ttype)->get_elem_type()); f_out_ << ">"; } else if (ttype->is_set()) { f_out_ << "set<"; len = 5 + print_type(((t_set*)ttype)->get_elem_type()); f_out_ << ">"; } else if (ttype->is_map()) { f_out_ << "map<"; len = 5 + print_type(((t_map*)ttype)->get_key_type()); f_out_ << ", "; len += print_type(((t_map*)ttype)->get_val_type()); f_out_ << ">"; } } else if (ttype->is_base_type()) { f_out_ << "```" << (ttype->is_binary() ? "binary" : ttype->get_name()) << "```"; len = ttype->get_name().size(); } else { string prog_name = ttype->get_program()->get_name(); string type_name = ttype->get_name(); f_out_ << "[```" << type_name << "```](" << make_file_link(make_file_name(prog_name)) << "#"; if (ttype->is_typedef()) { f_out_ << "typedef-"; } else if (ttype->is_xception()) { f_out_ << "exception-"; } else if (ttype->is_struct()) { if(((t_struct*)ttype)->is_union()) f_out_ << "union-"; else f_out_ << "struct-"; } else if (ttype->is_enum()) { f_out_ << "enumeration-"; } else if (ttype->is_service()) { f_out_ << "service-"; } len = type_name.size(); if (ttype->get_program() != program_) { f_out_ << str_to_id(prog_name); len += prog_name.size() + 1; } f_out_ << str_to_id(type_name) << ')'; } return (int)len; } /** * Prints out an Markdown representation of the provided constant value */ void t_markdown_generator::print_const_value(t_type* type, t_const_value* tvalue) { // if tvalue is an identifier, the constant content is already shown elsewhere if (tvalue->get_type() == t_const_value::CV_IDENTIFIER) { string fname = make_file_name(program_->get_name()); string name = escape_html(tvalue->get_identifier()); f_out_ << "[```" << name << "```](" + make_file_link(fname) + "#constant-" + str_to_id(name) + ")"; return; } t_type* truetype = type; while (truetype->is_typedef()) { truetype = ((t_typedef*)truetype)->get_type(); } bool first = true; if (truetype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base(); f_out_ << "```"; switch (tbase) { case t_base_type::TYPE_STRING: f_out_ << escape_html(get_escaped_string(tvalue)); break; case t_base_type::TYPE_BOOL: f_out_ << ((tvalue->get_integer() != 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I16: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I32: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_I64: f_out_ << tvalue->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (tvalue->get_type() == t_const_value::CV_INTEGER) { f_out_ << tvalue->get_integer(); } else { f_out_ << tvalue->get_double(); } break; default: f_out_ << "UNKNOWN BASE TYPE"; break; } f_out_ << "```"; } else if (truetype->is_enum()) { f_out_ << escape_html(truetype->get_name()) << "." << escape_html(tvalue->get_identifier_name()); } else if (truetype->is_struct() || truetype->is_xception()) { f_out_ << "{ "; const vector& fields = ((t_struct*)truetype)->get_members(); vector::const_iterator f_iter; const map& val = tvalue->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + truetype->get_name() + " has no field " + v_iter->first->get_string(); } if (!first) { f_out_ << ", "; } first = false; f_out_ << escape_html(v_iter->first->get_string()) << " = "; print_const_value(field_type, v_iter->second); } f_out_ << " }"; } else if (truetype->is_map()) { f_out_ << "{ "; map map_elems = tvalue->get_map(); map::iterator map_iter; for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_map*)truetype)->get_key_type(), map_iter->first); f_out_ << " = "; print_const_value(((t_map*)truetype)->get_val_type(), map_iter->second); } f_out_ << " }"; } else if (truetype->is_list()) { f_out_ << "{ "; vector list_elems = tvalue->get_list(); ; vector::iterator list_iter; for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_list*)truetype)->get_elem_type(), *list_iter); } f_out_ << " }"; } else if (truetype->is_set()) { f_out_ << "{ "; vector list_elems = tvalue->get_list(); ; vector::iterator list_iter; for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) { if (!first) { f_out_ << ", "; } first = false; print_const_value(((t_set*)truetype)->get_elem_type(), *list_iter); } f_out_ << " }"; } else { f_out_ << "UNKNOWN TYPE"; } } /** * Prints out documentation for arguments/exceptions of a function, if any documentation has been * supplied. */ void t_markdown_generator::print_fn_args_doc(t_function* tfunction) { bool has_docs = false; vector args = tfunction->get_arglist()->get_members(); vector::iterator arg_iter = args.begin(); if (arg_iter != args.end()) { for (; arg_iter != args.end(); arg_iter++) { if ((*arg_iter)->has_doc() && !(*arg_iter)->get_doc().empty()) { has_docs = true; break; } } if (has_docs) { arg_iter = args.begin(); f_out_ << endl << "* parameters:" << endl; for (int n = 1; arg_iter != args.end(); ++arg_iter, ++n ) { f_out_ << n << ". " << (*arg_iter)->get_name(); f_out_ << " - " << escape_html((*arg_iter)->get_doc()); f_out_ << endl; } f_out_ << endl; } } if(!has_docs) f_out_ << endl; has_docs = false; vector excepts = tfunction->get_xceptions()->get_members(); vector::iterator ex_iter = excepts.begin(); if (ex_iter != excepts.end()) { for (; ex_iter != excepts.end(); ++ex_iter) { if ((*ex_iter)->has_doc() && !(*ex_iter)->get_doc().empty()) { has_docs = true; break; } } if (has_docs) { ex_iter = excepts.begin(); f_out_ << "* exceptions:" << endl; for (; ex_iter != excepts.end(); ex_iter++) { f_out_ << " * " << (*ex_iter)->get_type()->get_name(); f_out_ << " - "; f_out_ << escape_html((*ex_iter)->get_doc()); f_out_ << endl; } f_out_ << endl; } } } /** * Generates a typedef. * * @param ttypedef The type definition */ void t_markdown_generator::generate_typedef(t_typedef* ttypedef) { string name = ttypedef->get_name(); f_out_ << "### Typedef: " << name << endl; print_doc(ttypedef); f_out_ << endl << endl; f_out_ << "_Base type_: **"; print_type(ttypedef->get_type()); f_out_ << "**" << endl << endl; f_out_ << endl; } /** * Generates code for an enumerated type. * * @param tenum The enumeration */ void t_markdown_generator::generate_enum(t_enum* tenum) { string name = tenum->get_name(); f_out_ << "### Enumeration: " << name << endl; print_doc(tenum); f_out_ << endl << endl << "|Name|Value|Description|" << endl << "|---|---|---|" << endl; vector values = tenum->get_constants(); vector::iterator val_iter; for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { f_out_ << "|```"; f_out_ << (*val_iter)->get_name(); f_out_ << "```|```"; f_out_ << (*val_iter)->get_value(); f_out_ << "```|"; print_doc((*val_iter)); f_out_ << "|" << endl; } f_out_ << endl; } /** * Generates a constant value */ void t_markdown_generator::generate_const(t_const* tconst) { // |Constant|Type|Value|HAS_DOC| string name = tconst->get_name(); f_out_ << "| ```" << name << "``` | "; print_type(tconst->get_type()); f_out_ << "| ```"; print_const_value(tconst->get_type(), tconst->get_value()); f_out_ << "``` |"; if (tconst->has_doc()) { print_doc(tconst); } f_out_ << '|' << endl; } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_markdown_generator::generate_struct(t_struct* tstruct) { string name = tstruct->get_name(); f_out_ << "### "; if (tstruct->is_xception()) { f_out_ << "Exception: "; } else if (tstruct->is_union()) { f_out_ << "Union: "; } else { f_out_ << "Struct: "; } f_out_ << name << endl; print_doc(tstruct); f_out_ << endl << endl; vector members = tstruct->get_members(); vector::iterator mem_iter = members.begin(); f_out_ << "| Key | Field | Type | Description | Requiredness " "| Default value |" << endl << "| --- | --- | --- | --- | --- | --- |" << endl; for (; mem_iter != members.end(); mem_iter++) { f_out_ << '|' << (*mem_iter)->get_key(); f_out_ << '|' << (*mem_iter)->get_name(); f_out_ << '|'; print_type((*mem_iter)->get_type()); f_out_ << '|' << escape_html((*mem_iter)->get_doc()) << '|'; if ((*mem_iter)->get_req() == t_field::T_OPTIONAL) { f_out_ << "optional"; } else if ((*mem_iter)->get_req() == t_field::T_REQUIRED) { f_out_ << "required"; } else { f_out_ << "default"; } f_out_ << '|'; t_const_value* default_val = (*mem_iter)->get_value(); if (default_val != nullptr) { f_out_ << "```"; print_const_value((*mem_iter)->get_type(), default_val); f_out_ << "```"; } f_out_ << '|' << endl; } f_out_ << endl; } /** * Exceptions are special structs * * @param tstruct The struct definition */ void t_markdown_generator::generate_xception(t_struct* txception) { generate_struct(txception); } /** * Generates the Markdown block for a Thrift service. * * @param tservice The service definition */ void t_markdown_generator::generate_service(t_service* tservice) { f_out_ << "### Service: " << service_name_ << endl; if (tservice->get_extends()) { f_out_ << "**extends ** _"; print_type(tservice->get_extends()); f_out_ << "_" << endl; } print_doc(tservice); f_out_ << endl; vector functions = tservice->get_functions(); vector::iterator fn_iter = functions.begin(); for (; fn_iter != functions.end(); fn_iter++) { string fn_name = (*fn_iter)->get_name(); f_out_ << "#### Function: " << service_name_ << "." << fn_name << endl; print_doc(*fn_iter); f_out_ << endl << endl; print_type((*fn_iter)->get_returntype()); bool first = true; f_out_ << endl << " _" << fn_name << "_("; vector args = (*fn_iter)->get_arglist()->get_members(); vector::iterator arg_iter = args.begin(); for (; arg_iter != args.end(); arg_iter++) { if (!first) { f_out_ << "," << endl; } first = false; print_type((*arg_iter)->get_type()); f_out_ << " " << (*arg_iter)->get_name(); if ((*arg_iter)->get_value() != nullptr) { f_out_ << " = "; print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value()); } } f_out_ << ")" << endl; first = true; vector excepts = (*fn_iter)->get_xceptions()->get_members(); vector::iterator ex_iter = excepts.begin(); if (ex_iter != excepts.end()) { f_out_ << "> throws "; for (; ex_iter != excepts.end(); ex_iter++) { if (!first) { f_out_ << ", "; } first = false; print_type((*ex_iter)->get_type()); } f_out_ << endl; } print_fn_args_doc(*fn_iter); f_out_ << endl; } } THRIFT_REGISTER_GENERATOR( markdown, "Markdown", " suffix: Create files/links with/out 'md|html' default None\n" " noescape: Do not escape with html-entities in doc text.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_netstd_generator.cc000066400000000000000000003610151420101504100255460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" #include "thrift/generate/t_netstd_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; //TODO: check for indentation //TODO: Do we need seqId_ in generation? t_netstd_generator::t_netstd_generator(t_program* program, const map& parsed_options, const string& option_string) : t_oop_generator(program) { (void)option_string; suppress_deepcopy = false; add_async_postfix = false; use_pascal_case_properties = false; union_ = false; serialize_ = false; wcf_ = false; wcf_namespace_.clear(); map::const_iterator iter; for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if (iter->first.compare("union") == 0) { union_ = true; } else if (iter->first.compare("serial") == 0) { serialize_ = true; wcf_namespace_ = iter->second; // since there can be only one namespace } else if (iter->first.compare("wcf") == 0) { wcf_ = true; wcf_namespace_ = iter->second; } else if (iter->first.compare("pascal") == 0) { use_pascal_case_properties = true; } else if (iter->first.compare("no_deepcopy") == 0) { suppress_deepcopy = true; } else if (iter->first.compare("async_postfix") == 0) { add_async_postfix = true; } else { throw "unknown option netstd:" + iter->first; } } out_dir_base_ = "gen-netstd"; } static bool field_has_default(t_field* tfield) { return tfield->get_value() != nullptr; } static bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; } static t_type* resolve_typedef(t_type* ttype) { while (ttype->is_typedef()) { ttype = static_cast(ttype)->get_type(); } return ttype; } static bool type_can_be_null(t_type* ttype) { ttype = resolve_typedef(ttype); return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string(); } bool t_netstd_generator::is_wcf_enabled() const { return wcf_; } bool t_netstd_generator::is_serialize_enabled() const { return serialize_; } bool t_netstd_generator::is_union_enabled() const { return union_; } map t_netstd_generator::get_keywords_list() const { return netstd_keywords; } void t_netstd_generator::init_generator() { MKDIR(get_out_dir().c_str()); namespace_name_ = program_->get_namespace("netstd"); string dir = namespace_name_; string subdir = get_out_dir().c_str(); string::size_type loc; while ((loc = dir.find(".")) != string::npos) { subdir = subdir + "/" + dir.substr(0, loc); MKDIR(subdir.c_str()); dir = dir.substr(loc + 1); } if (dir.size() > 0) { subdir = subdir + "/" + dir; MKDIR(subdir.c_str()); } namespace_dir_ = subdir; init_keywords(); while (!member_mapping_scopes.empty()) { cleanup_member_name_mapping(member_mapping_scopes.back().scope_member); } pverbose(".NET Standard options:\n"); pverbose("- union ........... %s\n", (is_union_enabled() ? "ON" : "off")); pverbose("- serialize ....... %s\n", (is_serialize_enabled() ? "ON" : "off")); pverbose("- wcf ............. %s\n", (is_wcf_enabled() ? "ON" : "off")); pverbose("- pascal .......... %s\n", (use_pascal_case_properties ? "ON" : "off")); pverbose("- no_deepcopy ..... %s\n", (suppress_deepcopy ? "ON" : "off")); pverbose("- async_postfix ... %s\n", (add_async_postfix ? "ON" : "off")); } string t_netstd_generator::normalize_name(string name, bool is_arg_name) { string tmp(name); transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast(tolower)); // check for reserved argument names if( is_arg_name && (CANCELLATION_TOKEN_NAME == name)) { name += "_"; } // un-conflict keywords by prefixing with "@" if (netstd_keywords.find(tmp) != netstd_keywords.end()) { return "@" + name; } // no changes necessary return name; } void t_netstd_generator::init_keywords() { netstd_keywords.clear(); // C# keywords netstd_keywords["abstract"] = 1; netstd_keywords["as"] = 1; netstd_keywords["base"] = 1; netstd_keywords["bool"] = 1; netstd_keywords["break"] = 1; netstd_keywords["byte"] = 1; netstd_keywords["case"] = 1; netstd_keywords["catch"] = 1; netstd_keywords["char"] = 1; netstd_keywords["checked"] = 1; netstd_keywords["class"] = 1; netstd_keywords["const"] = 1; netstd_keywords["continue"] = 1; netstd_keywords["decimal"] = 1; netstd_keywords["default"] = 1; netstd_keywords["delegate"] = 1; netstd_keywords["do"] = 1; netstd_keywords["double"] = 1; netstd_keywords["else"] = 1; netstd_keywords["enum"] = 1; netstd_keywords["event"] = 1; netstd_keywords["explicit"] = 1; netstd_keywords["extern"] = 1; netstd_keywords["false"] = 1; netstd_keywords["finally"] = 1; netstd_keywords["fixed"] = 1; netstd_keywords["float"] = 1; netstd_keywords["for"] = 1; netstd_keywords["foreach"] = 1; netstd_keywords["goto"] = 1; netstd_keywords["if"] = 1; netstd_keywords["implicit"] = 1; netstd_keywords["in"] = 1; netstd_keywords["int"] = 1; netstd_keywords["interface"] = 1; netstd_keywords["internal"] = 1; netstd_keywords["is"] = 1; netstd_keywords["lock"] = 1; netstd_keywords["long"] = 1; netstd_keywords["namespace"] = 1; netstd_keywords["new"] = 1; netstd_keywords["null"] = 1; netstd_keywords["object"] = 1; netstd_keywords["operator"] = 1; netstd_keywords["out"] = 1; netstd_keywords["override"] = 1; netstd_keywords["params"] = 1; netstd_keywords["private"] = 1; netstd_keywords["protected"] = 1; netstd_keywords["public"] = 1; netstd_keywords["readonly"] = 1; netstd_keywords["ref"] = 1; netstd_keywords["return"] = 1; netstd_keywords["sbyte"] = 1; netstd_keywords["sealed"] = 1; netstd_keywords["short"] = 1; netstd_keywords["sizeof"] = 1; netstd_keywords["stackalloc"] = 1; netstd_keywords["static"] = 1; netstd_keywords["string"] = 1; netstd_keywords["struct"] = 1; netstd_keywords["switch"] = 1; netstd_keywords["this"] = 1; netstd_keywords["throw"] = 1; netstd_keywords["true"] = 1; netstd_keywords["try"] = 1; netstd_keywords["typeof"] = 1; netstd_keywords["uint"] = 1; netstd_keywords["ulong"] = 1; netstd_keywords["unchecked"] = 1; netstd_keywords["unsafe"] = 1; netstd_keywords["ushort"] = 1; netstd_keywords["using"] = 1; netstd_keywords["virtual"] = 1; netstd_keywords["void"] = 1; netstd_keywords["volatile"] = 1; netstd_keywords["while"] = 1; // C# contextual keywords netstd_keywords["add"] = 1; netstd_keywords["alias"] = 1; netstd_keywords["ascending"] = 1; netstd_keywords["async"] = 1; netstd_keywords["await"] = 1; netstd_keywords["descending"] = 1; netstd_keywords["dynamic"] = 1; netstd_keywords["from"] = 1; netstd_keywords["get"] = 1; netstd_keywords["global"] = 1; netstd_keywords["group"] = 1; netstd_keywords["into"] = 1; netstd_keywords["join"] = 1; netstd_keywords["let"] = 1; netstd_keywords["orderby"] = 1; netstd_keywords["partial"] = 1; netstd_keywords["remove"] = 1; netstd_keywords["select"] = 1; netstd_keywords["set"] = 1; netstd_keywords["value"] = 1; netstd_keywords["var"] = 1; netstd_keywords["where"] = 1; netstd_keywords["yield"] = 1; netstd_keywords["when"] = 1; } void t_netstd_generator::reset_indent() { while( indent_count() > 0) { indent_down(); } } void t_netstd_generator::start_netstd_namespace(ostream& out) { out << "#nullable disable // suppress C# 8.0 nullable contexts (we still support earlier versions)" << endl << "#pragma warning disable IDE0079 // remove unnecessary pragmas" << endl << "#pragma warning disable IDE1006 // parts of the code use IDL spelling" << endl << "#pragma warning disable IDE0083 // pattern matching \"that is not SomeType\" requires net5.0 but we still support earlier versions" << endl << endl; if (!namespace_name_.empty()) { out << "namespace " << namespace_name_ << endl; scope_up(out); } } void t_netstd_generator::end_netstd_namespace(ostream& out) { if (!namespace_name_.empty()) { scope_down(out); } } string t_netstd_generator::netstd_type_usings() const { string namespaces = "using System;\n" "using System.Collections;\n" "using System.Collections.Generic;\n" "using System.Text;\n" "using System.IO;\n" "using System.Linq;\n" "using System.Threading;\n" "using System.Threading.Tasks;\n" "using Microsoft.Extensions.Logging;\n" "using Thrift;\n" "using Thrift.Collections;\n"; if (is_wcf_enabled()) { namespaces += "using System.ServiceModel;\n"; namespaces += "using System.Runtime.Serialization;\n"; } return namespaces + endl; } string t_netstd_generator::netstd_thrift_usings() const { string namespaces = "using Thrift.Protocol;\n" "using Thrift.Protocol.Entities;\n" "using Thrift.Protocol.Utilities;\n" "using Thrift.Transport;\n" "using Thrift.Transport.Client;\n" "using Thrift.Transport.Server;\n" "using Thrift.Processor;\n"; return namespaces + endl; } void t_netstd_generator::close_generator() { // right at the end, after everything else generate_extensions_file(); } void t_netstd_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } void t_netstd_generator::generate_enum(t_enum* tenum) { int ic = indent_count(); string f_enum_name = namespace_dir_ + "/" + tenum->get_name() + ".cs"; ofstream_with_content_based_conditional_update f_enum; f_enum.open(f_enum_name.c_str()); generate_enum(f_enum, tenum); f_enum.close(); indent_validate(ic, "generate_enum"); } void t_netstd_generator::generate_enum(ostream& out, t_enum* tenum) { reset_indent(); out << autogen_comment() << endl; start_netstd_namespace(out); generate_netstd_doc(out, tenum); out << indent() << "public enum " << type_name(tenum,false) << endl; scope_up(out); vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { generate_netstd_doc(out, *c_iter); int value = (*c_iter)->get_value(); out << indent() << (*c_iter)->get_name() << " = " << value << "," << endl; } scope_down(out); end_netstd_namespace(out); } void t_netstd_generator::generate_consts(vector consts) { if (consts.empty()) { return; } string f_consts_name = namespace_dir_ + '/' + program_name_ + ".Constants.cs"; ofstream_with_content_based_conditional_update f_consts; f_consts.open(f_consts_name.c_str()); generate_consts(f_consts, consts); f_consts.close(); } void t_netstd_generator::generate_consts(ostream& out, vector consts) { if (consts.empty()) { return; } reset_indent(); out << autogen_comment() << netstd_type_usings() << endl; start_netstd_namespace(out); out << indent() << "public static class " << make_valid_csharp_identifier(program_name_) << "Constants" << endl; scope_up(out); vector::iterator c_iter; bool need_static_constructor = false; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { generate_netstd_doc(out, *c_iter); if (print_const_value(out, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false)) { need_static_constructor = true; } } if (need_static_constructor) { print_const_constructor(out, consts); } scope_down(out); end_netstd_namespace(out); } void t_netstd_generator::print_const_def_value(ostream& out, string name, t_type* type, t_const_value* value) { if (type->is_struct() || type->is_xception()) { const vector& fields = static_cast(type)->get_members(); const map& val = value->get_map(); vector::const_iterator f_iter; map::const_iterator v_iter; collect_extensions_types(static_cast(type)); prepare_member_name_mapping(static_cast(type)); for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_field* field = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field = *f_iter; } } if (field == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } t_type* field_type = field->get_type(); string val = render_const_value(out, name, field_type, v_iter->second); out << indent() << name << "." << prop_name(field) << " = " << val << ";" << endl; } cleanup_member_name_mapping(static_cast(type)); } else if (type->is_map()) { t_type* ktype = static_cast(type)->get_key_type(); t_type* vtype = static_cast(type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(out, name, ktype, v_iter->first); string val = render_const_value(out, name, vtype, v_iter->second); out << indent() << name << "[" << key << "]" << " = " << val << ";" << endl; } } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = static_cast(type)->get_elem_type(); } else { etype = static_cast(type)->get_elem_type(); } const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(out, name, etype, *v_iter); out << indent() << name << ".Add(" << val << ");" << endl; } } } void t_netstd_generator::print_const_constructor(ostream& out, vector consts) { out << indent() << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()" << endl; scope_up(out); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { string name = (*c_iter)->get_name(); t_type* type = (*c_iter)->get_type(); t_const_value* value = (*c_iter)->get_value(); print_const_def_value(out, name, type, value); } scope_down(out); } bool t_netstd_generator::print_const_value(ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval, bool needtype) { out << indent(); bool need_static_construction = !in_static; type = resolve_typedef( type); if (!defval || needtype) { out << (in_static ? "" : type->is_base_type() ? "public const " : "public static ") << type_name(type) << " "; } if (type->is_base_type()) { string v2 = render_const_value(out, name, type, value); out << normalize_name(name) << " = " << v2 << ";" << endl; need_static_construction = false; } else if (type->is_enum()) { out << name << " = " << type_name(type) << "." << value->get_identifier_name() << ";" << endl; need_static_construction = false; } else if (type->is_struct() || type->is_xception()) { out << name << " = new " << type_name(type) << "();" << endl; } else if (type->is_map()) { out << name << " = new " << type_name(type) << "();" << endl; } else if (type->is_list() || type->is_set()) { out << name << " = new " << type_name(type) << "();" << endl; } if (defval && !type->is_base_type() && !type->is_enum()) { print_const_def_value(out, name, type, value); } return need_static_construction; } string t_netstd_generator::render_const_value(ostream& out, string name, t_type* type, t_const_value* value) { (void)name; ostringstream render; if (type->is_base_type()) { t_base_type::t_base tbase = static_cast(type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: if (type->is_binary()) { render << "System.Text.Encoding.UTF8.GetBytes(\"" << get_escaped_string(value) << "\")"; } else { render << '"' << get_escaped_string(value) << '"'; } break; case t_base_type::TYPE_BOOL: render << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: render << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { render << value->get_integer(); } else { render << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { render << type_name(type) << "." << value->get_identifier_name(); } else { string t = tmp("tmp"); print_const_value(out, t, type, value, true, true, true); render << t; } return render.str(); } void t_netstd_generator::collect_extensions_types(t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; // make private members with public Properties for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { collect_extensions_types((*m_iter)->get_type()); } } void t_netstd_generator::collect_extensions_types(t_type* ttype) { ttype = resolve_typedef( ttype); string key = type_name(ttype); if (ttype->is_struct() || ttype->is_xception()) { if( checked_extension_types.find(key) == checked_extension_types.end()) { checked_extension_types[key] = ttype; // prevent recursion t_struct* tstruct = static_cast(ttype); collect_extensions_types(tstruct); } return; } if (ttype->is_map() || ttype->is_set() || ttype->is_list()) { if( collected_extension_types.find(key) == collected_extension_types.end()) { collected_extension_types[key] = ttype; // prevent recursion if( ttype->is_map()) { t_map* tmap = static_cast(ttype); collect_extensions_types(tmap->get_key_type()); collect_extensions_types(tmap->get_val_type()); } else if (ttype->is_set()) { t_set* tset = static_cast(ttype); collect_extensions_types(tset->get_elem_type()); } else if (ttype->is_list()) { t_list* tlist = static_cast(ttype); collect_extensions_types(tlist->get_elem_type()); } } return; } } void t_netstd_generator::generate_extensions_file() { if (collected_extension_types.empty()) { return; } string f_exts_name = namespace_dir_ + '/' + program_name_ + ".Extensions.cs"; ofstream_with_content_based_conditional_update f_exts; f_exts.open(f_exts_name.c_str()); generate_extensions(f_exts, collected_extension_types); f_exts.close(); } void t_netstd_generator::generate_extensions(ostream& out, map types) { if (types.empty()) { return; } reset_indent(); out << autogen_comment() << netstd_type_usings() << endl; start_netstd_namespace(out); out << indent() << "public static class " << make_valid_csharp_identifier(program_name_) << "Extensions" << endl; scope_up(out); bool needs_typecast = false; std::map::const_iterator iter; for( iter = types.begin(); iter != types.end(); ++iter) { out << indent() << "public static bool Equals(this " << iter->first << " instance, object that)" << endl; scope_up(out); out << indent() << "if (!(that is " << iter->first << " other)) return false;" << endl; out << indent() << "if (ReferenceEquals(instance, other)) return true;" << endl; out << endl; out << indent() << "return TCollections.Equals(instance, other);" << endl; scope_down(out); out << endl << endl; out << indent() << "public static int GetHashCode(this " << iter->first << " instance)" << endl; scope_up(out); out << indent() << "return TCollections.GetHashCode(instance);" << endl; scope_down(out); out << endl << endl; if(! suppress_deepcopy) { out << indent() << "public static " << iter->first << " " << DEEP_COPY_METHOD_NAME << "(this " << iter->first << " source)" << endl; scope_up(out); out << indent() << "if (source == null)" << endl; indent_up(); out << indent() << "return null;" << endl << endl; indent_down(); string tmp_instance = tmp("tmp"); out << indent() << "var " << tmp_instance << " = new " << iter->first << "(source.Count);" << endl; if( iter->second->is_map()) { t_map* tmap = static_cast(iter->second); string copy_key = get_deep_copy_method_call(tmap->get_key_type(), needs_typecast); string copy_val = get_deep_copy_method_call(tmap->get_val_type(), needs_typecast); bool null_key = type_can_be_null(tmap->get_key_type()); bool null_val = type_can_be_null(tmap->get_val_type()); out << indent() << "foreach (var pair in source)" << endl; indent_up(); out << indent() << tmp_instance << ".Add("; if( null_key) { out << "(pair.Key != null) ? pair.Key" << copy_key << " : null"; } else { out << "pair.Key" << copy_key; } out << ", "; if( null_val) { out << "(pair.Value != null) ? pair.Value" << copy_val << " : null"; } else { out << "pair.Value" << copy_val; } out << ");" << endl; indent_down(); } else if( iter->second->is_set() || iter->second->is_list()) { string copy_elm; bool null_elm = false; if (iter->second->is_set()) { t_set* tset = static_cast(iter->second); copy_elm = get_deep_copy_method_call(tset->get_elem_type(), needs_typecast); null_elm = type_can_be_null(tset->get_elem_type()); } else // list { t_list* tlist = static_cast(iter->second); copy_elm = get_deep_copy_method_call(tlist->get_elem_type(), needs_typecast); null_elm = type_can_be_null(tlist->get_elem_type()); } out << indent() << "foreach (var elem in source)" << endl; indent_up(); out << indent() << tmp_instance << ".Add("; if( null_elm) { out << "(elem != null) ? elem" << copy_elm << " : null"; } else { out << "elem" << copy_elm; } out << ");" << endl; indent_down(); } out << indent() << "return " << tmp_instance << ";" << endl; scope_down(out); out << endl << endl; } } scope_down(out); end_netstd_namespace(out); } void t_netstd_generator::generate_struct(t_struct* tstruct) { collect_extensions_types(tstruct); if (is_union_enabled() && tstruct->is_union()) { generate_netstd_union(tstruct); } else { generate_netstd_struct(tstruct, false); } } void t_netstd_generator::generate_xception(t_struct* txception) { generate_netstd_struct(txception, true); } void t_netstd_generator::generate_netstd_struct(t_struct* tstruct, bool is_exception) { int ic = indent_count(); string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs"; ofstream_with_content_based_conditional_update f_struct; f_struct.open(f_struct_name.c_str()); reset_indent(); f_struct << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl; generate_netstd_struct_definition(f_struct, tstruct, is_exception); f_struct.close(); indent_validate(ic, "generate_netstd_struct"); } void t_netstd_generator::generate_netstd_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result) { if (!in_class) { start_netstd_namespace(out); } out << endl; generate_netstd_doc(out, tstruct); collect_extensions_types(tstruct); prepare_member_name_mapping(tstruct); if ((is_serialize_enabled() || is_wcf_enabled()) && !is_exception) { out << indent() << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; } bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end(); string sharp_struct_name = type_name(tstruct, false); out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << sharp_struct_name << " : "; if (is_exception) { out << "TException, "; } out << "TBase" << endl << indent() << "{" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; // make private members with public Properties for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { // if the field is required, then we use auto-properties if (!field_is_required((*m_iter))) { out << indent() << "private " << declare_field(*m_iter, false, "_") << endl; } } out << endl; bool has_non_required_fields = false; bool has_required_fields = false; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_netstd_doc(out, *m_iter); generate_property(out, *m_iter, true, true); bool is_required = field_is_required((*m_iter)); if (is_required) { has_required_fields = true; } else { has_non_required_fields = true; } } bool generate_isset = has_non_required_fields; if (generate_isset) { out << endl; if (is_serialize_enabled() || is_wcf_enabled()) { out << indent() << "[DataMember(Order = 1)]" << endl; } out << indent() << "public Isset __isset;" << endl; if (is_serialize_enabled() || is_wcf_enabled()) { out << indent() << "[DataContract]" << endl; } out << indent() << "public struct Isset" << endl << indent() << "{" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { bool is_required = field_is_required((*m_iter)); // if it is required, don't need Isset for that variable // if it is not required, if it has a default value, we need to generate Isset if (!is_required) { if (is_serialize_enabled() || is_wcf_enabled()) { out << indent() << "[DataMember]" << endl; } out << indent() << "public bool " << get_isset_name(normalize_name((*m_iter)->get_name())) << ";" << endl; } } indent_down(); out << indent() << "}" << endl << endl; if (generate_isset && (is_serialize_enabled() || is_wcf_enabled())) { out << indent() << "#region XmlSerializer support" << endl << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { bool is_required = field_is_required(*m_iter); // if it is required, don't need Isset for that variable // if it is not required, if it has a default value, we need to generate Isset if (!is_required) { out << indent() << "public bool ShouldSerialize" << prop_name(*m_iter) << "()" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return __isset." << get_isset_name(normalize_name((*m_iter)->get_name())) << ";" << endl; indent_down(); out << indent() << "}" << endl << endl; } } out << indent() << "#endregion XmlSerializer support" << endl << endl; } } // We always want a default, no argument constructor for Reading out << indent() << "public " << sharp_struct_name << "()" << endl << indent() << "{" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = (*m_iter)->get_type(); t = resolve_typedef(t); if ((*m_iter)->get_value() != nullptr) { if (field_is_required((*m_iter))) { print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true); } else { print_const_value(out, "this._" + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true); // Optionals with defaults are marked set out << indent() << "this.__isset." << get_isset_name(normalize_name((*m_iter)->get_name())) << " = true;" << endl; } } } indent_down(); out << indent() << "}" << endl << endl; // if we have required fields, we add that CTOR too if (has_required_fields) { out << indent() << "public " << sharp_struct_name << "("; bool first = true; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (field_is_required(*m_iter)) { if (first) { first = false; } else { out << ", "; } out << type_name((*m_iter)->get_type()) << " " << normalize_name((*m_iter)->get_name()); } } out << ") : this()" << endl << indent() << "{" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (field_is_required(*m_iter)) { out << indent() << "this." << prop_name(*m_iter) << " = " << normalize_name((*m_iter)->get_name()) << ";" << endl; } } indent_down(); out << indent() << "}" << endl << endl; } // DeepCopy() generate_netstd_deepcopy_method(out, tstruct, sharp_struct_name); generate_netstd_struct_reader(out, tstruct); if (is_result) { generate_netstd_struct_result_writer(out, tstruct); } else { generate_netstd_struct_writer(out, tstruct); } generate_netstd_struct_equals(out, tstruct); generate_netstd_struct_hashcode(out, tstruct); generate_netstd_struct_tostring(out, tstruct); indent_down(); out << indent() << "}" << endl << endl; // generate a corresponding WCF fault to wrap the exception if ((is_serialize_enabled() || is_wcf_enabled()) && is_exception) { generate_netstd_wcffault(out, tstruct); } cleanup_member_name_mapping(tstruct); if (!in_class) { end_netstd_namespace(out); } } void t_netstd_generator::generate_netstd_wcffault(ostream& out, t_struct* tstruct) { out << endl; out << indent() << "[DataContract]" << endl; bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end(); out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << type_name(tstruct,false) << "Fault" << endl << indent() << "{" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; // make private members with public Properties for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { // if the field is required, then we use auto-properties if (!field_is_required((*m_iter))) { out << indent() << "private " << declare_field(*m_iter, false, "_") << endl; } } out << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_property(out, *m_iter, true, false); } indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_netstd_deepcopy_method(ostream& out, t_struct* tstruct, std::string sharp_struct_name) { if( suppress_deepcopy) { return; // feature disabled } const vector& members = tstruct->get_members(); vector::const_iterator m_iter; out << indent() << "public " << sharp_struct_name << " " << DEEP_COPY_METHOD_NAME << "()" << endl; out << indent() << "{" << endl; indent_up(); // return directly if there are only required fields string tmp_instance = tmp("tmp"); out << indent() << "var " << tmp_instance << " = new " << sharp_struct_name << "();" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { bool needs_typecast = false; t_type* ttype = (*m_iter)->get_type(); string copy_op = get_deep_copy_method_call(ttype, needs_typecast); bool is_required = field_is_required(*m_iter); generate_null_check_begin( out, *m_iter); out << indent() << tmp_instance << "." << prop_name(*m_iter) << " = "; if( needs_typecast) { out << "(" << type_name(ttype) << ")"; } out << "this." << prop_name(*m_iter) << copy_op << ";" << endl; generate_null_check_end( out, *m_iter); if( !is_required) { out << indent() << tmp_instance << ".__isset." << get_isset_name(normalize_name((*m_iter)->get_name())) << " = this.__isset." << get_isset_name(normalize_name((*m_iter)->get_name())) << ";" << endl; } } out << indent() << "return " << tmp_instance << ";" << endl; indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_netstd_struct_reader(ostream& out, t_struct* tstruct) { out << indent() << "public async global::System.Threading.Tasks.Task ReadAsync(TProtocol iprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "iprot.IncrementRecursionDepth();" << endl << indent() << "try" << endl << indent() << "{" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; // Required variables aren't in __isset, so we need tmp vars to check them for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (field_is_required(*f_iter)) { out << indent() << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl; } } out << indent() << "TField field;" << endl << indent() << "await iprot.ReadStructBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "while (true)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "field = await iprot.ReadFieldBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "if (field.Type == TType.Stop)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "break;" << endl; indent_down(); out << indent() << "}" << endl << endl << indent() << "switch (field.ID)" << endl << indent() << "{" << endl; indent_up(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool is_required = field_is_required(*f_iter); out << indent() << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ")" << endl << indent() << "{" << endl; indent_up(); generate_deserialize_field(out, *f_iter); if (is_required) { out << indent() << "isset_" << (*f_iter)->get_name() << " = true;" << endl; } indent_down(); out << indent() << "}" << endl << indent() << "else" << endl << indent() << "{" << endl; indent_up(); out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, " << CANCELLATION_TOKEN_NAME << ");" << endl; indent_down(); out << indent() << "}" << endl << indent() << "break;" << endl; indent_down(); } out << indent() << "default: " << endl; indent_up(); out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "break;" << endl; indent_down(); indent_down(); out << indent() << "}" << endl << endl << indent() << "await iprot.ReadFieldEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; indent_down(); out << indent() << "}" << endl << endl << indent() << "await iprot.ReadStructEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (field_is_required((*f_iter))) { out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl; indent_down(); out << indent() << "}" << endl; } } indent_down(); out << indent() << "}" << endl; out << indent() << "finally" << endl << indent() << "{" << endl; indent_up(); out << indent() << "iprot.DecrementRecursionDepth();" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_null_check_begin(ostream& out, t_field* tfield) { bool is_required = field_is_required(tfield); bool null_allowed = type_can_be_null(tfield->get_type()); if( null_allowed || (!is_required)) { bool first = true; out << indent() << "if("; if( null_allowed) { out << "(" << prop_name(tfield) << " != null)"; first = false; } if( !is_required) { if( !first) { out << " && "; } out << "__isset." << get_isset_name(normalize_name(tfield->get_name())); } out << ")" << endl << indent() << "{" << endl; indent_up(); } } void t_netstd_generator::generate_null_check_end(ostream& out, t_field* tfield) { bool is_required = field_is_required(tfield); bool null_allowed = type_can_be_null(tfield->get_type()); if( null_allowed || (!is_required)) { indent_down(); out << indent() << "}" << endl; } } void t_netstd_generator::generate_netstd_struct_writer(ostream& out, t_struct* tstruct) { out << indent() << "public async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "oprot.IncrementRecursionDepth();" << endl << indent() << "try" << endl << indent() << "{" << endl; indent_up(); string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; string tmpvar = tmp("tmp"); out << indent() << "var " << tmpvar << " = new TStruct(\"" << name << "\");" << endl << indent() << "await oprot.WriteStructBeginAsync(" << tmpvar << ", " << CANCELLATION_TOKEN_NAME << ");" << endl; if (fields.size() > 0) { tmpvar = tmp("tmp"); out << indent() << "var " << tmpvar << " = new TField();" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { generate_null_check_begin( out, *f_iter); out << indent() << tmpvar << ".Name = \"" << (*f_iter)->get_name() << "\";" << endl << indent() << tmpvar << ".Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl << indent() << tmpvar << ".ID = " << (*f_iter)->get_key() << ";" << endl << indent() << "await oprot.WriteFieldBeginAsync(" << tmpvar << ", " << CANCELLATION_TOKEN_NAME << ");" << endl; generate_serialize_field(out, *f_iter); out << indent() << "await oprot.WriteFieldEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; generate_null_check_end(out, *f_iter); } } out << indent() << "await oprot.WriteFieldStopAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await oprot.WriteStructEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; indent_down(); out << indent() << "}" << endl << indent() << "finally" << endl << indent() << "{" << endl; indent_up(); out << indent() << "oprot.DecrementRecursionDepth();" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_netstd_struct_result_writer(ostream& out, t_struct* tstruct) { out << indent() << "public async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "oprot.IncrementRecursionDepth();" << endl << indent() << "try" << endl << indent() << "{" << endl; indent_up(); string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; string tmpvar = tmp("tmp"); out << indent() << "var " << tmpvar << " = new TStruct(\"" << name << "\");" << endl << indent() << "await oprot.WriteStructBeginAsync(" << tmpvar << ", " << CANCELLATION_TOKEN_NAME << ");" << endl; if (fields.size() > 0) { tmpvar = tmp("tmp"); out << indent() << "var " << tmpvar << " = new TField();" << endl; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; out << endl << indent() << "if"; } else { out << indent() << "else if"; } out << "(this.__isset." << get_isset_name(normalize_name((*f_iter)->get_name())) << ")" << endl << indent() << "{" << endl; indent_up(); bool null_allowed = type_can_be_null((*f_iter)->get_type()); if (null_allowed) { out << indent() << "if (" << prop_name(*f_iter) << " != null)" << endl << indent() << "{" << endl; indent_up(); } out << indent() << tmpvar << ".Name = \"" << prop_name(*f_iter) << "\";" << endl << indent() << tmpvar << ".Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl << indent() << tmpvar << ".ID = " << (*f_iter)->get_key() << ";" << endl << indent() << "await oprot.WriteFieldBeginAsync(" << tmpvar << ", " << CANCELLATION_TOKEN_NAME << ");" << endl; generate_serialize_field(out, *f_iter); out << indent() << "await oprot.WriteFieldEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; if (null_allowed) { indent_down(); out << indent() << "}" << endl; } indent_down(); out << indent() << "}" << endl; } } out << indent() << "await oprot.WriteFieldStopAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await oprot.WriteStructEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; indent_down(); out << indent() << "}" << endl << indent() << "finally" << endl << indent() << "{" << endl; indent_up(); out << indent() << "oprot.DecrementRecursionDepth();" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_netstd_struct_tostring(ostream& out, t_struct* tstruct) { string tmpvar = tmp("tmp"); out << indent() << "public override string ToString()" << endl << indent() << "{" << endl; indent_up(); out << indent() << "var " << tmpvar << " = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool useFirstFlag = false; string tmp_count = tmp("tmp"); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (!field_is_required((*f_iter))) { out << indent() << "int " << tmp_count.c_str() << " = 0;" << endl; useFirstFlag = true; } break; } bool had_required = false; // set to true after first required field has been processed for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool is_required = field_is_required(*f_iter); generate_null_check_begin(out, *f_iter); if (useFirstFlag && (!had_required)) { out << indent() << "if(0 < " << tmp_count.c_str() << (is_required ? "" : "++") << ") { " << tmpvar << ".Append(\", \"); }" << endl; out << indent() << tmpvar << ".Append(\"" << prop_name(*f_iter) << ": \");" << endl; } else { out << indent() << tmpvar << ".Append(\", " << prop_name(*f_iter) << ": \");" << endl; } out << indent() << prop_name(*f_iter) << ".ToString(" << tmpvar << ");" << endl; generate_null_check_end(out, *f_iter); if (is_required) { had_required = true; // now __count must be > 0, so we don't need to check it anymore } } out << indent() << tmpvar << ".Append(')');" << endl << indent() << "return " << tmpvar << ".ToString();" << endl; indent_down(); out << indent() << "}" << endl; } void t_netstd_generator::generate_netstd_union(t_struct* tunion) { int ic = indent_count(); string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs"; ofstream_with_content_based_conditional_update f_union; f_union.open(f_union_name.c_str()); reset_indent(); f_union << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl; generate_netstd_union_definition(f_union, tunion); f_union.close(); indent_validate(ic, "generate_netstd_union."); } void t_netstd_generator::generate_netstd_union_definition(ostream& out, t_struct* tunion) { // Let's define the class first start_netstd_namespace(out); out << indent() << "public abstract partial class " << tunion->get_name() << " : TUnionBase" << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "public abstract global::System.Threading.Tasks.Task WriteAsync(TProtocol tProtocol, CancellationToken " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "public readonly int Isset;" << endl << indent() << "public abstract object Data { get; }" << endl << indent() << "protected " << tunion->get_name() << "(int isset)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "Isset = isset;" << endl; indent_down(); out << indent() << "}" << endl << endl; const vector& fields = tunion->get_members(); vector::const_iterator f_iter; out << indent() << "public override bool Equals(object that)" << endl; scope_up(out); out << indent() << "if (!(that is " << tunion->get_name() << " other)) return false;" << endl; out << indent() << "if (ReferenceEquals(this, other)) return true;" << endl; out << endl; out << indent() << "if(this.Isset != other.Isset) return false;" << endl; out << endl; out << indent() << "switch (Isset)" << endl; scope_up(out); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool needs_typecast = false; string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), needs_typecast); out << indent() << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); out << indent() << "return Equals(As_" << (*f_iter)->get_name() << ", other.As_" << (*f_iter)->get_name() << ");" << endl; indent_down(); } out << indent() << "default:" << endl; indent_up(); out << indent() << "return true;" << endl; indent_down(); indent_down(); scope_down(out); scope_down(out); out << endl; out << indent() << "public override int GetHashCode()" << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "switch (Isset)" << endl; out << indent() << "{" << endl; indent_up(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool needs_typecast = false; string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), needs_typecast); out << indent() << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); out << indent() << "return As_" << (*f_iter)->get_name() << ".GetHashCode();" << endl; indent_down(); } out << indent() << "default:" << endl; indent_up(); out << indent() << "return (new ___undefined()).GetHashCode();" << endl; indent_down(); indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl << endl; if( ! suppress_deepcopy) { out << indent() << "public " << tunion->get_name() << " DeepCopy()" << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "switch (Isset)" << endl; out << indent() << "{" << endl; indent_up(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool needs_typecast = false; string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), needs_typecast); out << indent() << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); out << indent() << "return new " << (*f_iter)->get_name() << "(As_" << (*f_iter)->get_name() << copy_op << ");" << endl; indent_down(); } out << indent() << "default:" << endl; indent_up(); out << indent() << "return new ___undefined();" << endl; indent_down(); indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl << endl; } out << indent() << "public class ___undefined : " << tunion->get_name() << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "public override object Data { get { return null; } }" << endl << indent() << "public ___undefined() : base(0) {}" << endl << endl; if( ! suppress_deepcopy) { out << indent() << "public new ___undefined DeepCopy()" << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "return new ___undefined();" << endl; indent_down(); out << indent() << "}" << endl << endl; } t_struct undefined_struct(program_,"___undefined"); generate_netstd_struct_equals(out, &undefined_struct); generate_netstd_struct_hashcode(out, &undefined_struct); out << indent() << "public override global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist an union type which is not set.\");" << endl; indent_down(); out << indent() << "}" << endl << endl; indent_down(); out << indent() << "}" << endl << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { generate_netstd_union_class(out, tunion, (*f_iter)); } generate_netstd_union_reader(out, tunion); indent_down(); out << indent() << "}" << endl << endl; end_netstd_namespace(out); } void t_netstd_generator::generate_netstd_union_class(ostream& out, t_struct* tunion, t_field* tfield) { out << indent() << "public " << type_name(tfield->get_type()) << " As_" << tfield->get_name() << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "get" << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "return (" << tfield->get_key() << " == Isset) ? (" << type_name(tfield->get_type()) << ")Data : default(" << type_name(tfield->get_type()) << ");" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl << endl; out << indent() << "public class " << tfield->get_name() << " : " << tunion->get_name() << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "private " << type_name(tfield->get_type()) << " _data;" << endl << indent() << "public override object Data { get { return _data; } }" << endl << indent() << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) << " data) : base("<< tfield->get_key() <<")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "this._data = data;" << endl; indent_down(); out << indent() << "}" << endl; if( ! suppress_deepcopy) { out << indent() << "public new " << tfield->get_name() << " DeepCopy()" << endl; out << indent() << "{" << endl; indent_up(); bool needs_typecast = false; string copy_op = get_deep_copy_method_call(tfield->get_type(), needs_typecast); out << indent() << "return new " << tfield->get_name() << "(_data" << copy_op << ");" << endl; indent_down(); out << indent() << "}" << endl << endl; } out << indent() << "public override bool Equals(object that)" << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "if (!(that is " << tunion->get_name() << " other)) return false;" << endl; out << indent() << "if (ReferenceEquals(this, other)) return true;" << endl; out << endl; out << indent() << "return Equals( _data, other.As_" << tfield->get_name() << ");" << endl; indent_down(); out << indent() << "}" << endl << endl; out << indent() << "public override int GetHashCode()" << endl; out << indent() << "{" << endl; indent_up(); out << indent() << "return _data.GetHashCode();" << endl; indent_down(); out << indent() << "}" << endl << endl; out << indent() << "public override async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ") {" << endl; indent_up(); out << indent() << "oprot.IncrementRecursionDepth();" << endl << indent() << "try" << endl << indent() << "{" << endl; indent_up(); out << indent() << "var struc = new TStruct(\"" << tunion->get_name() << "\");" << endl << indent() << "await oprot.WriteStructBeginAsync(struc, " << CANCELLATION_TOKEN_NAME << ");" << endl; out << indent() << "var field = new TField();" << endl << indent() << "field.Name = \"" << tfield->get_name() << "\";" << endl << indent() << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl << indent() << "field.ID = " << tfield->get_key() << ";" << endl << indent() << "await oprot.WriteFieldBeginAsync(field, " << CANCELLATION_TOKEN_NAME << ");" << endl; generate_serialize_field(out, tfield, "_data", true); out << indent() << "await oprot.WriteFieldEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await oprot.WriteFieldStopAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await oprot.WriteStructEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; indent_down(); out << indent() << "}" << endl << indent() << "finally" << endl << indent() << "{" << endl; indent_up(); out << indent() << "oprot.DecrementRecursionDepth();" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_netstd_struct_equals(ostream& out, t_struct* tstruct) { out << indent() << "public override bool Equals(object that)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "if (!(that is " << type_name(tstruct,false) << " other)) return false;" << endl << indent() << "if (ReferenceEquals(this, other)) return true;" << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; out << indent() << "return "; indent_up(); } else { out << endl; out << indent() << "&& "; } if (!field_is_required((*f_iter))) { out << "((__isset." << get_isset_name(normalize_name((*f_iter)->get_name())) << " == other.__isset." << get_isset_name(normalize_name((*f_iter)->get_name())) << ") && ((!__isset." << get_isset_name(normalize_name((*f_iter)->get_name())) << ") || ("; } t_type* ttype = (*f_iter)->get_type(); if (ttype->is_container() || ttype->is_binary()) { out << "TCollections.Equals("; } else { out << "global::System.Object.Equals("; } out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")"; if (!field_is_required((*f_iter))) { out << ")))"; } } if (first) { out << indent() << "return true;" << endl; } else { out << ";" << endl; indent_down(); } indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_netstd_struct_hashcode(ostream& out, t_struct* tstruct) { out << indent() << "public override int GetHashCode() {" << endl; indent_up(); out << indent() << "int hashcode = 157;" << endl; out << indent() << "unchecked {" << endl; indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_type* ttype = (*f_iter)->get_type(); generate_null_check_begin(out, *f_iter); out << indent() << "hashcode = (hashcode * 397) + "; if (ttype->is_container()) { out << "TCollections.GetHashCode(" << prop_name((*f_iter)) << ")"; } else { out << prop_name((*f_iter)) << ".GetHashCode()"; } out << ";" << endl; generate_null_check_end(out, *f_iter); } indent_down(); out << indent() << "}" << endl; out << indent() << "return hashcode;" << endl; indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_service(t_service* tservice) { int ic = indent_count(); string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs"; ofstream_with_content_based_conditional_update f_service; f_service.open(f_service_name.c_str()); reset_indent(); f_service << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl; start_netstd_namespace(f_service); f_service << indent() << "public partial class " << normalize_name(service_name_) << endl << indent() << "{" << endl; indent_up(); generate_service_interface(f_service, tservice); generate_service_client(f_service, tservice); generate_service_server(f_service, tservice); generate_service_helpers(f_service, tservice); indent_down(); f_service << indent() << "}" << endl; end_netstd_namespace(f_service); f_service.close(); indent_validate(ic, "generate_service."); } void t_netstd_generator::generate_service_interface(ostream& out, t_service* tservice) { string extends = ""; string extends_iface = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_iface = " : " + extends + ".IAsync"; } //out << endl << endl; generate_netstd_doc(out, tservice); if (is_wcf_enabled()) { out << indent() << "[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; } prepare_member_name_mapping(tservice); out << indent() << "public interface IAsync" << extends_iface << endl << indent() << "{" << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_netstd_doc(out, *f_iter); // if we're using WCF, add the corresponding attributes if (is_wcf_enabled()) { out << indent() << "[OperationContract]" << endl; const vector& xceptions = (*f_iter)->get_xceptions()->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << indent() << "[FaultContract(typeof(" + type_name((*x_iter)->get_type()) + "Fault))]" << endl; } } generate_deprecation_attribute(out, *f_iter); out << indent() << function_signature_async(*f_iter) << ";" << endl << endl; } indent_down(); out << indent() << "}" << endl << endl; cleanup_member_name_mapping(tservice); } void t_netstd_generator::generate_deprecation_attribute(ostream& out, t_function* func) { auto iter = func->annotations_.find("deprecated"); if( func->annotations_.end() != iter) { out << indent() << "[Obsolete"; // empty annotation values end up with "1" somewhere, ignore these as well if ((iter->second.length() > 0) && (iter->second != "1")) { out << "(" << make_csharp_string_literal(iter->second) << ")"; } out << "]" << endl; } } void t_netstd_generator::generate_service_helpers(ostream& out, t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; prepare_member_name_mapping(tservice); out << indent() << "public class InternalStructs" << endl; out << indent() << "{" << endl; indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); collect_extensions_types(ts); generate_netstd_struct_definition(out, ts, false, true); generate_function_helpers(out, *f_iter); } indent_down(); out << indent() << "}" << endl << endl; cleanup_member_name_mapping(tservice); } void t_netstd_generator::generate_service_client(ostream& out, t_service* tservice) { string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_client = extends + ".Client, "; } else { extends_client = "TBaseClient, IDisposable, "; } out << endl; generate_netstd_doc(out, tservice); prepare_member_name_mapping(tservice); out << indent() << "public class Client : " << extends_client << "IAsync" << endl << indent() << "{" << endl; indent_up(); out << indent() << "public Client(TProtocol protocol) : this(protocol, protocol)" << endl << indent() << "{" << endl << indent() << "}" << endl << endl << indent() << "public Client(TProtocol inputProtocol, TProtocol outputProtocol) : base(inputProtocol, outputProtocol)" << endl << indent() << "{" << endl << indent() << "}" << endl << endl; vector functions = tservice->get_functions(); vector::const_iterator functions_iterator; for (functions_iterator = functions.begin(); functions_iterator != functions.end(); ++functions_iterator) { string raw_func_name = (*functions_iterator)->get_name(); string function_name = raw_func_name + (add_async_postfix ? "Async" : ""); // async generate_deprecation_attribute(out, *functions_iterator); out << indent() << "public async " << function_signature_async(*functions_iterator, "") << endl << indent() << "{" << endl; indent_up(); out << indent() << "await send_" << function_name << "("; string call_args = argument_list((*functions_iterator)->get_arglist(),false); if(! call_args.empty()) { out << call_args << ", "; } out << CANCELLATION_TOKEN_NAME << ");" << endl; if(! (*functions_iterator)->is_oneway()) { out << indent() << ((*functions_iterator)->get_returntype()->is_void() ? "" : "return ") << "await recv_" << function_name << "(" << CANCELLATION_TOKEN_NAME << ");" << endl; } indent_down(); out << indent() << "}" << endl << endl; // async send generate_deprecation_attribute(out, *functions_iterator); out << indent() << "public async " << function_signature_async(*functions_iterator, "send_", MODE_NO_RETURN) << endl << indent() << "{" << endl; indent_up(); string tmpvar = tmp("tmp"); string argsname = (*functions_iterator)->get_name() + "_args"; out << indent() << "await OutputProtocol.WriteMessageBeginAsync(new TMessage(\"" << raw_func_name << "\", TMessageType." << ((*functions_iterator)->is_oneway() ? "Oneway" : "Call") << ", SeqId), " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << endl << indent() << "var " << tmpvar << " = new InternalStructs." << argsname << "() {" << endl; indent_up(); t_struct* arg_struct = (*functions_iterator)->get_arglist(); collect_extensions_types(arg_struct); prepare_member_name_mapping(arg_struct); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { out << indent() << prop_name(*fld_iter) << " = " << normalize_name((*fld_iter)->get_name(),true) << "," << endl; } indent_down(); out << indent() << "};" << endl; out << indent() << endl << indent() << "await " << tmpvar << ".WriteAsync(OutputProtocol, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await OutputProtocol.WriteMessageEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await OutputProtocol.Transport.FlushAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; indent_down(); out << indent() << "}" << endl << endl; if (!(*functions_iterator)->is_oneway()) { // async recv generate_deprecation_attribute(out, *functions_iterator); out << indent() << "public async " << function_signature_async(*functions_iterator, "recv_", MODE_NO_ARGS) << endl << indent() << "{" << endl; indent_up(); string resultname = (*functions_iterator)->get_name() + "_result"; t_struct noargs(program_); t_struct* xs = (*functions_iterator)->get_xceptions(); collect_extensions_types(xs); prepare_member_name_mapping(xs, xs->get_members(), resultname); tmpvar = tmp("tmp"); out << indent() << endl << indent() << "var " << tmpvar << " = await InputProtocol.ReadMessageBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "if (" << tmpvar << ".Type == TMessageType.Exception)" << endl << indent() << "{" << endl; indent_up(); tmpvar = tmp("tmp"); out << indent() << "var " << tmpvar << " = await TApplicationException.ReadAsync(InputProtocol, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await InputProtocol.ReadMessageEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "throw " << tmpvar << ";" << endl; indent_down(); tmpvar = tmp("tmp"); out << indent() << "}" << endl << endl << indent() << "var " << tmpvar << " = new InternalStructs." << resultname << "();" << endl << indent() << "await " << tmpvar << ".ReadAsync(InputProtocol, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await InputProtocol.ReadMessageEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; if (!(*functions_iterator)->get_returntype()->is_void()) { out << indent() << "if (" << tmpvar << ".__isset.success)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return " << tmpvar << ".Success;" << endl; indent_down(); out << indent() << "}" << endl; } const vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << indent() << "if (" << tmpvar << ".__isset." << get_isset_name(normalize_name((*x_iter)->get_name())) << ")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "throw " << tmpvar << "." << prop_name(*x_iter) << ";" << endl; indent_down(); out << indent() << "}" << endl; } if (!(*functions_iterator)->get_returntype()->is_void()) { out << indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \"" << function_name << " failed: unknown result\");" << endl; } cleanup_member_name_mapping(xs); indent_down(); out << indent() << "}" << endl << endl; } cleanup_member_name_mapping(arg_struct); } indent_down(); out << indent() << "}" << endl << endl; cleanup_member_name_mapping(tservice); } void t_netstd_generator::generate_service_server(ostream& out, t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_processor = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_processor = extends + ".AsyncProcessor, "; } prepare_member_name_mapping(tservice); out << indent() << "public class AsyncProcessor : " << extends_processor << "ITAsyncProcessor" << endl << indent() << "{" << endl; indent_up(); out << indent() << "private readonly IAsync _iAsync;" << endl << indent() << "private readonly ILogger _logger;" << endl << endl << indent() << "public AsyncProcessor(IAsync iAsync, ILogger logger = default)"; if (!extends.empty()) { out << " : base(iAsync)"; } out << endl << indent() << "{" << endl; indent_up(); out << indent() << "_iAsync = iAsync ?? throw new ArgumentNullException(nameof(iAsync));" << endl; out << indent() << "_logger = logger;" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string raw_func_name = (*f_iter)->get_name(); out << indent() << "processMap_[\"" << raw_func_name << "\"] = " << raw_func_name << "_ProcessAsync;" << endl; } indent_down(); out << indent() << "}" << endl << endl; if (extends.empty()) { out << indent() << "protected delegate global::System.Threading.Tasks.Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ");" << endl; } if (extends.empty()) { out << indent() << "protected Dictionary processMap_ = new Dictionary();" << endl; } out << endl; if (extends.empty()) { out << indent() << "public async Task ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl; indent_down(); out << indent() << "}" << endl << endl; out << indent() << "public async Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl; } else { out << indent() << "public new async Task ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl; indent_down(); out << indent() << "}" << endl << endl; out << indent() << "public new async Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl; } out << indent() << "{" << endl; indent_up(); out << indent() << "try" << endl << indent() << "{" << endl; indent_up(); out << indent() << "var msg = await iprot.ReadMessageBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << endl << indent() << "processMap_.TryGetValue(msg.Name, out ProcessFunction fn);" << endl << endl << indent() << "if (fn == null)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "await TProtocolUtil.SkipAsync(iprot, TType.Struct, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await iprot.ReadMessageEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "var x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + msg.Name + \"'\");" << endl << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID), " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await x.WriteAsync(oprot, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await oprot.WriteMessageEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await oprot.Transport.FlushAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "return true;" << endl; indent_down(); out << indent() << "}" << endl << endl << indent() << "await fn(msg.SeqID, iprot, oprot, " << CANCELLATION_TOKEN_NAME << ");" << endl << endl; indent_down(); out << indent() << "}" << endl; out << indent() << "catch (IOException)" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return false;" << endl; indent_down(); out << indent() << "}" << endl << endl << indent() << "return true;" << endl; indent_down(); out << indent() << "}" << endl << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function_async(out, tservice, *f_iter); } indent_down(); out << indent() << "}" << endl << endl; cleanup_member_name_mapping(tservice); } void t_netstd_generator::generate_function_helpers(ostream& out, t_function* tfunction) { if (tfunction->is_oneway()) { return; } t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } collect_extensions_types(&result); generate_netstd_struct_definition(out, &result, false, true, true); } void t_netstd_generator::generate_process_function_async(ostream& out, t_service* tservice, t_function* tfunction) { (void)tservice; out << indent() << "public async global::System.Threading.Tasks.Task " << tfunction->get_name() << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl << indent() << "{" << endl; indent_up(); string argsname = tfunction->get_name() + "_args"; string resultname = tfunction->get_name() + "_result"; string args = tmp("tmp"); out << indent() << "var " << args << " = new InternalStructs." << argsname << "();" << endl << indent() << "await " << args << ".ReadAsync(iprot, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await iprot.ReadMessageEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; string tmpResult = tmp("tmp"); if (!tfunction->is_oneway()) { out << indent() << "var " << tmpResult << " = new InternalStructs." << resultname << "();" << endl; } out << indent() << "try" << endl << indent() << "{" << endl; indent_up(); t_struct* xs = tfunction->get_xceptions(); const vector& xceptions = xs->get_members(); if (xceptions.size() > 0) { out << indent() << "try" << endl << indent() << "{" << endl; indent_up(); } t_struct* arg_struct = tfunction->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; bool is_deprecated = (tfunction->annotations_.end() != tfunction->annotations_.find("deprecated")); if( is_deprecated) { out << indent() << "#pragma warning disable CS0618,CS0612" << endl; } out << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { out << tmpResult << ".Success = "; } out << "await _iAsync." << func_name(normalize_name(tfunction->get_name()) + (add_async_postfix ? "Async" : "")) << "("; bool first = true; collect_extensions_types(arg_struct); prepare_member_name_mapping(arg_struct); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { out << ", "; } out << args << "." << prop_name(*f_iter); } cleanup_member_name_mapping(arg_struct); if (!first) { out << ", "; } out << "" << CANCELLATION_TOKEN_NAME << ");" << endl; if( is_deprecated) { out << indent() << "#pragma warning restore CS0618,CS0612" << endl; } vector::const_iterator x_iter; collect_extensions_types(xs); prepare_member_name_mapping(xs, xs->get_members(), resultname); if (xceptions.size() > 0) { indent_down(); out << indent() << "}" << endl; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { string tmpex = tmp("tmp"); out << indent() << "catch (" << type_name((*x_iter)->get_type()) << " " << tmpex << ")" << endl << indent() << "{" << endl; if (!tfunction->is_oneway()) { indent_up(); out << indent() << tmpResult << "." << prop_name(*x_iter) << " = " << tmpex << ";" << endl; indent_down(); } out << indent() << "}" << endl; } } if (!tfunction->is_oneway()) { out << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.Reply, seqid), " << CANCELLATION_TOKEN_NAME << "); " << endl << indent() << "await " << tmpResult << ".WriteAsync(oprot, " << CANCELLATION_TOKEN_NAME << ");" << endl; } indent_down(); cleanup_member_name_mapping(xs); string tmpex = tmp("tmp"); out << indent() << "}" << endl << indent() << "catch (TTransportException)" << endl << indent() << "{" << endl << indent() << " throw;" << endl << indent() << "}" << endl << indent() << "catch (Exception " << tmpex << ")" << endl << indent() << "{" << endl; indent_up(); string tmpvar = tmp("tmp"); out << indent() << "var " << tmpvar << " = $\"Error occurred in {GetType().FullName}: {" << tmpex << ".Message}\";" << endl; out << indent() << "if(_logger != null)" << endl; indent_up(); out << indent() << "_logger.LogError(\"{Exception}, {Message}\", " << tmpex << ", " << tmpvar << ");" << endl; indent_down(); out << indent() << "else" << endl; indent_up(); out << indent() << "Console.Error.WriteLine(" << tmpvar << ");" << endl; indent_down(); if (tfunction->is_oneway()) { indent_down(); out << indent() << "}" << endl; } else { tmpvar = tmp("tmp"); out << indent() << "var " << tmpvar << " = new TApplicationException(TApplicationException.ExceptionType.InternalError,\" Internal error.\");" << endl << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.Exception, seqid), " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await " << tmpvar << ".WriteAsync(oprot, " << CANCELLATION_TOKEN_NAME << ");" << endl; indent_down(); out << indent() << "}" << endl << indent() << "await oprot.WriteMessageEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << "await oprot.Transport.FlushAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } indent_down(); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_netstd_union_reader(ostream& out, t_struct* tunion) { // Thanks to THRIFT-1768, we don't need to check for required fields in the union const vector& fields = tunion->get_members(); vector::const_iterator f_iter; out << indent() << "public static async Task<" << tunion->get_name() << "> ReadAsync(TProtocol iprot, CancellationToken " << CANCELLATION_TOKEN_NAME << ")" << endl; scope_up(out); out << indent() << "iprot.IncrementRecursionDepth();" << endl; out << indent() << "try" << endl; scope_up(out); string tmpRetval = tmp("tmp"); out << indent() << tunion->get_name() << " " << tmpRetval << ";" << endl; out << indent() << "await iprot.ReadStructBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; out << indent() << "TField field = await iprot.ReadFieldBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; // we cannot have the first field be a stop -- we must have a single field defined out << indent() << "if (field.Type == TType.Stop)" << endl; scope_up(out); out << indent() << "await iprot.ReadFieldEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; out << indent() << "" << tmpRetval << " = new ___undefined();" << endl; scope_down(out); out << indent() << "else" << endl; scope_up(out); out << indent() << "switch (field.ID)" << endl; scope_up(out); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { out << indent() << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); string tmpvar = tmp("tmp"); out << indent() << type_name((*f_iter)->get_type()) << " " << tmpvar << ";" << endl; generate_deserialize_field(out, (*f_iter), tmpvar, true); out << indent() << tmpRetval << " = new " << (*f_iter)->get_name() << "(" << tmpvar << ");" << endl; indent_down(); out << indent() << "} else { " << endl << indent() << " await TProtocolUtil.SkipAsync(iprot, field.Type, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << " " << tmpRetval << " = new ___undefined();" << endl << indent() << "}" << endl << indent() << "break;" << endl; indent_down(); } out << indent() << "default: " << endl; indent_up(); out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, " << CANCELLATION_TOKEN_NAME << ");" << endl << indent() << tmpRetval << " = new ___undefined();" << endl; out << indent() << "break;" << endl; indent_down(); scope_down(out); out << indent() << "await iprot.ReadFieldEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; out << indent() << "if ((await iprot.ReadFieldBeginAsync(" << CANCELLATION_TOKEN_NAME << ")).Type != TType.Stop)" << endl; scope_up(out); out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl; scope_down(out); // end of else for TStop scope_down(out); out << indent() << "await iprot.ReadStructEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; out << indent() << "return " << tmpRetval << ";" << endl; indent_down(); scope_down(out); out << indent() << "finally" << endl; scope_up(out); out << indent() << "iprot.DecrementRecursionDepth();" << endl; scope_down(out); out << indent() << "}" << endl << endl; } void t_netstd_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, bool is_propertyless) { t_type* type = tfield->get_type(); type = resolve_typedef( type); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + (is_propertyless ? "" : prop_name(tfield)); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, static_cast(type), name); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { out << indent() << name << " = "; if (type->is_enum()) { out << "(" << type_name(type) << ")"; } out << "await iprot."; if (type->is_base_type()) { t_base_type::t_base tbase = static_cast(type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "ReadBinaryAsync(" << CANCELLATION_TOKEN_NAME << ");"; } else { out << "ReadStringAsync(" << CANCELLATION_TOKEN_NAME << ");"; } break; case t_base_type::TYPE_BOOL: out << "ReadBoolAsync(" << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I8: out << "ReadByteAsync(" << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I16: out << "ReadI16Async(" << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I32: out << "ReadI32Async(" << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I64: out << "ReadI64Async(" << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_DOUBLE: out << "ReadDoubleAsync(" << CANCELLATION_TOKEN_NAME << ");"; break; default: throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "ReadI32Async(" << CANCELLATION_TOKEN_NAME << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str()); } } void t_netstd_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { if (is_union_enabled() && tstruct->is_union()) { out << indent() << prefix << " = await " << type_name(tstruct) << ".ReadAsync(iprot, " << CANCELLATION_TOKEN_NAME << ");" << endl; } else { out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent() << "await " << prefix << ".ReadAsync(iprot, " << CANCELLATION_TOKEN_NAME << ");" << endl; } } void t_netstd_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { out << indent() << "{" << endl; indent_up(); string obj; if (ttype->is_map()) { obj = tmp("_map"); } else if (ttype->is_set()) { obj = tmp("_set"); } else if (ttype->is_list()) { obj = tmp("_list"); } if (ttype->is_map()) { out << indent() << "TMap " << obj << " = await iprot.ReadMapBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_set()) { out << indent() << "TSet " << obj << " = await iprot.ReadSetBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_list()) { out << indent() << "TList " << obj << " = await iprot.ReadListBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } out << indent() << prefix << " = new " << type_name(ttype) << "(" << obj << ".Count);" << endl; string i = tmp("_i"); out << indent() << "for(int " << i << " = 0; " << i << " < " << obj << ".Count; ++" << i << ")" << endl << indent() << "{" << endl; indent_up(); if (ttype->is_map()) { generate_deserialize_map_element(out, static_cast(ttype), prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, static_cast(ttype), prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, static_cast(ttype), prefix); } indent_down(); out << indent() << "}" << endl; if (ttype->is_map()) { out << indent() << "await iprot.ReadMapEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_set()) { out << indent() << "await iprot.ReadSetEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_list()) { out << indent() << "await iprot.ReadListEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } indent_down(); out << indent() << "}" << endl; } void t_netstd_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); out << indent() << declare_field(&fkey) << endl; out << indent() << declare_field(&fval) << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); out << indent() << prefix << "[" << key << "] = " << val << ";" << endl; } void t_netstd_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); out << indent() << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); out << indent() << prefix << ".Add(" << elem << ");" << endl; } void t_netstd_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); out << indent() << declare_field(&felem) << endl; generate_deserialize_field(out, &felem); out << indent() << prefix << ".Add(" << elem << ");" << endl; } void t_netstd_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, bool is_propertyless) { t_type* type = tfield->get_type(); type = resolve_typedef( type); string name = prefix + (is_propertyless ? "" : prop_name(tfield)); if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, static_cast(type), name); } else if (type->is_container()) { generate_serialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { out << indent() << "await oprot."; string nullable_name = name; if (type->is_base_type()) { t_base_type::t_base tbase = static_cast(type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "WriteBinaryAsync("; } else { out << "WriteStringAsync("; } out << name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_BOOL: out << "WriteBoolAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I8: out << "WriteByteAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I16: out << "WriteI16Async(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I32: out << "WriteI32Async(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_I64: out << "WriteI64Async(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; case t_base_type::TYPE_DOUBLE: out << "WriteDoubleAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; break; default: throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "WriteI32Async((int)" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str()); } } void t_netstd_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; out << indent() << "await " << prefix << ".WriteAsync(oprot, " << CANCELLATION_TOKEN_NAME << ");" << endl; } void t_netstd_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { out << indent() << "{" << endl; indent_up(); if (ttype->is_map()) { out << indent() << "await oprot.WriteMapBeginAsync(new TMap(" << type_to_enum(static_cast(ttype)->get_key_type()) << ", " << type_to_enum(static_cast(ttype)->get_val_type()) << ", " << prefix << ".Count), " << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_set()) { out << indent() << "await oprot.WriteSetBeginAsync(new TSet(" << type_to_enum(static_cast(ttype)->get_elem_type()) << ", " << prefix << ".Count), " << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_list()) { out << indent() << "await oprot.WriteListBeginAsync(new TList(" << type_to_enum(static_cast(ttype)->get_elem_type()) << ", " << prefix << ".Count), " << CANCELLATION_TOKEN_NAME << ");" << endl; } string iter = tmp("_iter"); if (ttype->is_map()) { out << indent() << "foreach (" << type_name(static_cast(ttype)->get_key_type()) << " " << iter << " in " << prefix << ".Keys)"; } else if (ttype->is_set()) { out << indent() << "foreach (" << type_name(static_cast(ttype)->get_elem_type()) << " " << iter << " in " << prefix << ")"; } else if (ttype->is_list()) { out << indent() << "foreach (" << type_name(static_cast(ttype)->get_elem_type()) << " " << iter << " in " << prefix << ")"; } out << endl; out << indent() << "{" << endl; indent_up(); if (ttype->is_map()) { generate_serialize_map_element(out, static_cast(ttype), iter, prefix); } else if (ttype->is_set()) { generate_serialize_set_element(out, static_cast(ttype), iter); } else if (ttype->is_list()) { generate_serialize_list_element(out, static_cast(ttype), iter); } indent_down(); out << indent() << "}" << endl; if (ttype->is_map()) { out << indent() << "await oprot.WriteMapEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_set()) { out << indent() << "await oprot.WriteSetEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } else if (ttype->is_list()) { out << indent() << "await oprot.WriteListEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl; } indent_down(); out << indent() << "}" << endl; } void t_netstd_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map) { t_field kfield(tmap->get_key_type(), iter); generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); generate_serialize_field(out, &vfield, ""); } void t_netstd_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } void t_netstd_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } void t_netstd_generator::generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset) { generate_netstd_property(out, tfield, isPublic, generateIsset, "_"); } void t_netstd_generator::generate_netstd_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset, string fieldPrefix) { if ((is_serialize_enabled() || is_wcf_enabled()) && isPublic) { out << indent() << "[DataMember(Order = 0)]" << endl; } out << indent() << (isPublic ? "public " : "private ") << type_name(tfield->get_type()) << " " << prop_name(tfield); bool is_required = field_is_required(tfield); if (is_required) { out << " { get; set; }" << endl; } else { out << endl << indent() << "{" << endl; indent_up(); out << indent() << "get" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return " << fieldPrefix + tfield->get_name() << ";" << endl; indent_down(); out << indent() << "}" << endl << indent() << "set" << endl << indent() << "{" << endl; indent_up(); if (generateIsset) { out << indent() << "__isset." << get_isset_name(normalize_name(tfield->get_name())) << " = true;" << endl; } out << indent() << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl; indent_down(); out << indent() << "}" << endl; indent_down(); out << indent() << "}" << endl; } out << endl; } string t_netstd_generator::make_csharp_string_literal( string const& value) { if (value.length() == 0) { return ""; } std::stringstream result; result << "\""; for (signed char const c: value) { if( (c >= 0) && (c < 32)) { // convert ctrl chars, but leave UTF-8 alone int width = std::max( (int)sizeof(c), 4); result << "\\x" << std::hex << std::setw(width) << std::setfill('0') << (int)c; } else if ((c == '\\') || (c == '"')) { result << "\\" << c; } else { result << c; // anything else "as is" } } result << "\""; return result.str(); } string t_netstd_generator::make_valid_csharp_identifier(string const& fromName) { string str = fromName; if (str.empty()) { return str; } // tests rely on this assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); // if the first letter is a number, we add an additional underscore in front of it char c = str.at(0); if (('0' <= c) && (c <= '9')) { str = "_" + str; } // following chars: letter, number or underscore for (size_t i = 0; i < str.size(); ++i) { c = str.at(i); if (('A' > c || c > 'Z') && ('a' > c || c > 'z') && ('0' > c || c > '9') && '_' != c) { str.replace(i, 1, "_"); } } return str; } void t_netstd_generator::cleanup_member_name_mapping(void* scope) { if (member_mapping_scopes.empty()) { throw "internal error: cleanup_member_name_mapping() no scope active"; } member_mapping_scope& active = member_mapping_scopes.back(); if (active.scope_member != scope) { throw "internal error: cleanup_member_name_mapping() called for wrong struct"; } member_mapping_scopes.pop_back(); } string t_netstd_generator::get_mapped_member_name(string name) { if (!member_mapping_scopes.empty()) { member_mapping_scope& active = member_mapping_scopes.back(); map::iterator iter = active.mapping_table.find(name); if (active.mapping_table.end() != iter) { return iter->second; } } pverbose("no mapping for member %s\n", name.c_str()); return name; } void t_netstd_generator::prepare_member_name_mapping(t_service* tservice) { prepare_member_name_mapping(tservice, tservice->get_functions(), tservice->get_name()); } void t_netstd_generator::prepare_member_name_mapping(t_struct* tstruct) { prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name()); } void t_netstd_generator::prepare_member_name_mapping(t_struct* scope, const vector& members, const string& structname) { // begin new scope member_mapping_scopes.emplace_back(); member_mapping_scope& active = member_mapping_scopes.back(); active.scope_member = scope; // current C# generator policy: // - prop names are always rendered with an Uppercase first letter // - struct names are used as given std::set used_member_names; vector::const_iterator iter; // prevent name conflicts with struct (CS0542 error + THRIFT-2942) used_member_names.insert(structname); used_member_names.insert("Isset"); used_member_names.insert("Read"); used_member_names.insert("Write"); for (iter = members.begin(); iter != members.end(); ++iter) { string oldname = (*iter)->get_name(); string newname = prop_name(*iter, true); while (true) { // new name conflicts with another member if (used_member_names.find(newname) != used_member_names.end()) { pverbose("struct %s: member %s conflicts with another member\n", structname.c_str(), newname.c_str()); newname += '_'; continue; } // add always, this helps us to detect edge cases like // different spellings ("foo" and "Foo") within the same struct pverbose("struct %s: member mapping %s => %s\n", structname.c_str(), oldname.c_str(), newname.c_str()); active.mapping_table[oldname] = newname; used_member_names.insert(newname); break; } } } void t_netstd_generator::prepare_member_name_mapping(t_service* scope, const vector& members, const string& structname) { // begin new scope member_mapping_scopes.emplace_back(); member_mapping_scope& active = member_mapping_scopes.back(); active.scope_member = scope; // current C# generator policy: // - prop names are always rendered with an Uppercase first letter // - struct names are used as given std::set used_member_names; vector::const_iterator iter; // prevent name conflicts with service/intf used_member_names.insert(structname); used_member_names.insert("Client"); used_member_names.insert("IAsync"); used_member_names.insert("AsyncProcessor"); used_member_names.insert("InternalStructs"); for (iter = members.begin(); iter != members.end(); ++iter) { string oldname = (*iter)->get_name(); string newname = func_name(*iter, true); while (true) { // new name conflicts with another method if (used_member_names.find(newname) != used_member_names.end()) { pverbose("service %s: method %s conflicts with another method\n", structname.c_str(), newname.c_str()); newname += '_'; continue; } // add always, this helps us to detect edge cases like // different spellings ("foo" and "Foo") within the same service pverbose("service %s: method mapping %s => %s\n", structname.c_str(), oldname.c_str(), newname.c_str()); active.mapping_table[oldname] = newname; used_member_names.insert(newname); break; } } } string t_netstd_generator::convert_to_pascal_case(const string& str) { string out; bool must_capitalize = true; bool first_character = true; for (auto it = str.begin(); it != str.end(); ++it) { if (std::isalnum(*it)) { if (must_capitalize) { out.append(1, (char)::toupper(*it)); must_capitalize = false; } else { out.append(1, *it); } } else { if (first_character) //this is a private variable and should not be PascalCased return str; must_capitalize = true; } first_character = false; } return out; } string t_netstd_generator::get_isset_name(const string& str) { return ("Isset" != str) ? str : str + "_"; } string t_netstd_generator::prop_name(t_field* tfield, bool suppress_mapping) { string name(tfield->get_name()); if (suppress_mapping) { name[0] = toupper(name[0]); if (use_pascal_case_properties) name = t_netstd_generator::convert_to_pascal_case(name); } else { name = get_mapped_member_name(name); } return name; } string t_netstd_generator::func_name(t_function* tfunc, bool suppress_mapping) { return func_name(tfunc->get_name(), suppress_mapping); } string t_netstd_generator::func_name(std::string fname, bool suppress_mapping) { if (suppress_mapping) { return fname; } return get_mapped_member_name(fname); } string t_netstd_generator::type_name(t_type* ttype, bool with_namespace) { ttype = resolve_typedef(ttype); if (ttype->is_base_type()) { return base_type_name(static_cast(ttype)); } if (ttype->is_map()) { t_map* tmap = static_cast(ttype); return "Dictionary<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type()) + ">"; } if (ttype->is_set()) { t_set* tset = static_cast(ttype); return "THashSet<" + type_name(tset->get_elem_type()) + ">"; } if (ttype->is_list()) { t_list* tlist = static_cast(ttype); return "List<" + type_name(tlist->get_elem_type()) + ">"; } string the_name = normalize_name(ttype->get_name()); if(with_namespace) { t_program* program = ttype->get_program(); if (program != nullptr)// && program != program_) { string ns = program->get_namespace("netstd"); if (!ns.empty()) { return "global::" + ns + "." + the_name; } } } return the_name; } string t_netstd_generator::base_type_name(t_base_type* tbase) { switch (tbase->get_base()) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: if (tbase->is_binary()) { return "byte[]"; } else { return "string"; } case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: return "sbyte"; case t_base_type::TYPE_I16: return "short"; case t_base_type::TYPE_I32: return "int"; case t_base_type::TYPE_I64: return "long"; case t_base_type::TYPE_DOUBLE: return "double"; default: throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base()); } } string t_netstd_generator::get_deep_copy_method_call(t_type* ttype, bool& needs_typecast) { ttype = resolve_typedef(ttype); needs_typecast = false; if (ttype->is_base_type()) { t_base_type::t_base tbase = static_cast(ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: if (ttype->is_binary()) { return ".ToArray()"; } else { return ""; // simple assignment will do, strings are immutable in C# } break; default: return ""; // simple assignment will do } } else if (ttype->is_enum()) { return ""; // simple assignment will do } else { needs_typecast = (! ttype->is_container()); return "." + DEEP_COPY_METHOD_NAME + "()"; } } string t_netstd_generator::declare_field(t_field* tfield, bool init, string prefix) { string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name(); if (init) { t_type* ttype = tfield->get_type(); ttype = resolve_typedef(ttype); if (ttype->is_base_type() && field_has_default(tfield)) { std::ofstream dummy; result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); } else if (ttype->is_base_type()) { t_base_type::t_base tbase = static_cast(ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: result += " = null"; break; case t_base_type::TYPE_BOOL: result += " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = (double)0"; break; } } else if (ttype->is_enum()) { result += " = (" + type_name(ttype) + ")0"; } else if (ttype->is_container()) { result += " = new " + type_name(ttype) + "()"; } else { result += " = new " + type_name(ttype) + "()"; } } return result + ";"; } string t_netstd_generator::function_signature(t_function* tfunction, string prefix) { t_type* ttype = tfunction->get_returntype(); return type_name(ttype) + " " + func_name(normalize_name(prefix + tfunction->get_name())) + "(" + argument_list(tfunction->get_arglist()) + ")"; } string t_netstd_generator::function_signature_async(t_function* tfunction, string prefix, int mode) { t_type* ttype = tfunction->get_returntype(); string task = "global::System.Threading.Tasks.Task"; if ((!ttype->is_void()) && ((mode & MODE_NO_RETURN) == 0)) { task += "<" + type_name(ttype) + ">"; } string result = task + " " + func_name(normalize_name(prefix + tfunction->get_name()) + (add_async_postfix ? "Async" : "")) + "("; if((mode & MODE_NO_ARGS) == 0) { string args = argument_list(tfunction->get_arglist()); result += args; if (!args.empty()) { result += ", "; } } result += "CancellationToken " + CANCELLATION_TOKEN_NAME + " = default)"; return result; } string t_netstd_generator::argument_list(t_struct* tstruct, bool with_types) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } if( with_types) { result += type_name((*f_iter)->get_type()) + " "; } result += normalize_name((*f_iter)->get_name(),true); } return result; } string t_netstd_generator::type_to_enum(t_type* type) { type = resolve_typedef( type); if (type->is_base_type()) { t_base_type::t_base tbase = static_cast(type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.String"; case t_base_type::TYPE_BOOL: return "TType.Bool"; case t_base_type::TYPE_I8: return "TType.Byte"; case t_base_type::TYPE_I16: return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.Double"; } } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "TType.Struct"; } else if (type->is_map()) { return "TType.Map"; } else if (type->is_set()) { return "TType.Set"; } else if (type->is_list()) { return "TType.List"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } void t_netstd_generator::generate_netstd_docstring_comment(ostream& out, string contents) { docstring_comment(out, "/// " + endl, "/// ", contents, "/// " + endl); } void t_netstd_generator::generate_netstd_doc(ostream& out, t_field* field) { if (field->get_type()->is_enum()) { string combined_message = field->get_doc() + endl + "get_type()) + "\"/>"; generate_netstd_docstring_comment(out, combined_message); } else { generate_netstd_doc(out, static_cast(field)); } } void t_netstd_generator::generate_netstd_doc(ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_netstd_docstring_comment(out, tdoc->get_doc()); } } void t_netstd_generator::generate_netstd_doc(ostream& out, t_function* tfunction) { if (tfunction->has_doc()) { stringstream ps; const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; ps << endl << "get_name() << "\">"; if (p->has_doc()) { string str = p->get_doc(); str.erase(remove(str.begin(), str.end(), '\n'), str.end()); ps << str; } ps << ""; } docstring_comment(out, "", "/// ", "" + endl + tfunction->get_doc() + "" + ps.str(), ""); } } void t_netstd_generator::docstring_comment(ostream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end) { if (comment_start != "") { out << indent() << comment_start; } stringstream docs(contents, std::ios_base::in); while (!(docs.eof() || docs.fail())) { char line[1024]; docs.getline(line, 1024); // Just prnt a newline when the line & prefix are empty. if (strlen(line) == 0 && line_prefix == "" && !docs.eof()) { out << endl; } else if (strlen(line) > 0 || !docs.eof()) { // skip the empty last line out << indent() << line_prefix << line << endl; } } if (comment_end != "") { out << indent() << comment_end; } } string t_netstd_generator::get_enum_class_name(t_type* type) { string package = ""; t_program* program = type->get_program(); if (program != nullptr) // && program != program_) { package = program->get_namespace("netstd") + "."; } return "global::" + package + type->get_name(); } THRIFT_REGISTER_GENERATOR( netstd, "C#", " wcf: Adds bindings for WCF to generated classes.\n" " serial: Add serialization support to generated classes.\n" " union: Use new union typing, which includes a static read function for union types.\n" " pascal: Generate Pascal Case property names according to Microsoft naming convention.\n" " no_deepcopy: Suppress generation of DeepCopy() method.\n" " async_postfix: Append \"Async\" to all service methods (maintains compatibility with existing code).\n" ) thrift-0.16.0/compiler/cpp/src/thrift/generate/t_netstd_generator.h000066400000000000000000000221011420101504100253760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes static const string DEEP_COPY_METHOD_NAME = "DeepCopy"; static const string CANCELLATION_TOKEN_NAME = "cancellationToken"; class t_netstd_generator : public t_oop_generator { struct member_mapping_scope { public: member_mapping_scope() : scope_member(0) { } void* scope_member; map mapping_table; }; public: t_netstd_generator(t_program* program, const map& parsed_options, const string& option_string); bool is_wcf_enabled() const; bool is_hashcode_enabled() const; bool is_serialize_enabled() const; bool is_union_enabled() const; map get_keywords_list() const; // overrides void init_generator(); void close_generator(); void generate_consts(vector consts); void generate_consts(ostream& out, vector consts); void generate_typedef(t_typedef* ttypedef); void generate_enum(t_enum* tenum); void generate_enum(ostream& out, t_enum* tenum); void generate_struct(t_struct* tstruct); void generate_xception(t_struct* txception); void generate_service(t_service* tservice); // additional files void generate_extensions_file(); void generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset); void generate_netstd_property(ostream& out, t_field* tfield, bool isPublic, bool includeIsset = true, string fieldPrefix = ""); bool print_const_value(ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval = false, bool needtype = false); string render_const_value(ostream& out, string name, t_type* type, t_const_value* value); void print_const_constructor(ostream& out, vector consts); void print_const_def_value(ostream& out, string name, t_type* type, t_const_value* value); void generate_netstd_struct(t_struct* tstruct, bool is_exception); void generate_netstd_union(t_struct* tunion); void generate_netstd_struct_definition(ostream& out, t_struct* tstruct, bool is_xception = false, bool in_class = false, bool is_result = false); void generate_netstd_union_definition(ostream& out, t_struct* tunion); void generate_netstd_union_class(ostream& out, t_struct* tunion, t_field* tfield); void generate_netstd_wcffault(ostream& out, t_struct* tstruct); void generate_netstd_deepcopy_method(ostream& out, t_struct* tstruct, std::string sharp_struct_name); void generate_netstd_struct_reader(ostream& out, t_struct* tstruct); void generate_netstd_struct_result_writer(ostream& out, t_struct* tstruct); void generate_netstd_struct_writer(ostream& out, t_struct* tstruct); void generate_netstd_struct_tostring(ostream& out, t_struct* tstruct); void generate_netstd_struct_equals(ostream& out, t_struct* tstruct); void generate_netstd_struct_hashcode(ostream& out, t_struct* tstruct); void generate_netstd_union_reader(ostream& out, t_struct* tunion); void generate_function_helpers(ostream& out, t_function* tfunction); void generate_service_interface(ostream& out, t_service* tservice); void generate_deprecation_attribute(ostream& out, t_function* func); void generate_service_helpers(ostream& out, t_service* tservice); void generate_service_client(ostream& out, t_service* tservice); void generate_service_server(ostream& out, t_service* tservice); void generate_process_function_async(ostream& out, t_service* tservice, t_function* function); void generate_deserialize_field(ostream& out, t_field* tfield, string prefix = "", bool is_propertyless = false); void generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix = ""); void generate_deserialize_container(ostream& out, t_type* ttype, string prefix = ""); void generate_deserialize_set_element(ostream& out, t_set* tset, string prefix = ""); void generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix = ""); void generate_deserialize_list_element(ostream& out, t_list* list, string prefix = ""); void generate_serialize_field(ostream& out, t_field* tfield, string prefix = "", bool is_propertyless = false); void generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix = ""); void generate_serialize_container(ostream& out, t_type* ttype, string prefix = ""); void generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map); void generate_serialize_set_element(ostream& out, t_set* tmap, string iter); void generate_serialize_list_element(ostream& out, t_list* tlist, string iter); void generate_netstd_doc(ostream& out, t_field* field); void generate_netstd_doc(ostream& out, t_doc* tdoc); void generate_netstd_doc(ostream& out, t_function* tdoc); void generate_netstd_docstring_comment(ostream& out, string contents); void docstring_comment(ostream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end); void start_netstd_namespace(ostream& out); void end_netstd_namespace(ostream& out); string netstd_type_usings() const; string netstd_thrift_usings() const; static const int MODE_FULL_DECL = 0x00; static const int MODE_NO_RETURN = 0x01; static const int MODE_NO_ARGS = 0x02; string type_name(t_type* ttype, bool with_namespace = true); string base_type_name(t_base_type* tbase); string declare_field(t_field* tfield, bool init = false, string prefix = ""); string function_signature_async(t_function* tfunction, string prefix = "", int mode = MODE_FULL_DECL); string function_signature(t_function* tfunction, string prefix = ""); string argument_list(t_struct* tstruct, bool with_types = true); string type_to_enum(t_type* ttype); string prop_name(t_field* tfield, bool suppress_mapping = false); string func_name(t_function* tfunc, bool suppress_mapping = false); string func_name(std::string fname, bool suppress_mapping = false); string convert_to_pascal_case(const string& str); string get_enum_class_name(t_type* type); protected: std::string autogen_comment() override { return std::string("/**\n") + " * \n" + " * " + autogen_summary() + "\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + " * \n" " */\n" ; } private: string namespace_name_; string namespace_dir_; bool union_; bool hashcode_; bool serialize_; bool wcf_; bool use_pascal_case_properties; bool suppress_deepcopy; bool add_async_postfix; string wcf_namespace_; map netstd_keywords; vector member_mapping_scopes; map collected_extension_types; map checked_extension_types; void init_keywords(); string normalize_name(string name, bool is_arg_name = false); string make_valid_csharp_identifier(string const& fromName); string make_csharp_string_literal( string const& value); void prepare_member_name_mapping(t_service* tservice); void prepare_member_name_mapping(t_struct* tstruct); void prepare_member_name_mapping(t_struct* scope, const vector& members, const string& structname); void prepare_member_name_mapping(t_service* scope, const vector& members, const string& structname); void cleanup_member_name_mapping(void* scope); string get_mapped_member_name(string oldname); string get_isset_name(const string& str); string get_deep_copy_method_call(t_type* ttype, bool& needs_typecast); void collect_extensions_types(t_struct* tstruct); void collect_extensions_types(t_type* ttype); void generate_extensions(ostream& out, map types); void reset_indent(); void generate_null_check_begin(ostream& out, t_field* tfield); void generate_null_check_end(ostream& out, t_field* tfield); }; thrift-0.16.0/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc000066400000000000000000001670141420101504100253430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" #include "thrift/generate/t_oop_generator.h" using std::ios; using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * OCaml code generator. * */ class t_ocaml_generator : public t_oop_generator { public: t_ocaml_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option ocaml:" + iter->first; } out_dir_base_ = "gen-ocaml"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_program() override; void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; std::string render_const_value(t_type* type, t_const_value* value); bool struct_member_persistent(t_field* tmember); bool struct_member_omitable(t_field* tmember); bool struct_member_default_cheaply_comparable(t_field* tmember); std::string struct_member_copy_of(t_type* type, string what); /** * Struct generation code */ void generate_ocaml_struct(t_struct* tstruct, bool is_exception); void generate_ocaml_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false); void generate_ocaml_struct_member(std::ostream& out, string tname, t_field* tmember); void generate_ocaml_struct_sig(std::ostream& out, t_struct* tstruct, bool is_exception); void generate_ocaml_struct_reader(std::ostream& out, t_struct* tstruct); void generate_ocaml_struct_writer(std::ostream& out, t_struct* tstruct); void generate_ocaml_function_helpers(t_function* tfunction); void generate_ocaml_method_copy(std::ostream& out, const vector& members); void generate_ocaml_member_copy(std::ostream& out, t_field* member); /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct); void generate_deserialize_container(std::ostream& out, t_type* ttype); void generate_deserialize_set_element(std::ostream& out, t_set* tset); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_deserialize_type(std::ostream& out, t_type* type); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string name = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); /** * Helper rendering functions */ std::string ocaml_autogen_comment(); std::string ocaml_imports(); std::string type_name(t_type* ttype); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string function_type(t_function* tfunc, bool method = false, bool options = false); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string render_ocaml_type(t_type* type); private: /** * File streams */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_consts_; ofstream_with_content_based_conditional_update f_service_; ofstream_with_content_based_conditional_update f_types_i_; ofstream_with_content_based_conditional_update f_service_i_; }; /* * This is necessary because we want typedefs to appear later, * after all the types have been declared. */ void t_ocaml_generator::generate_program() { // Initialize the generator init_generator(); // Generate enums vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } // Generate structs vector structs = program_->get_structs(); vector::iterator st_iter; for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) { generate_struct(*st_iter); } // Generate xceptions vector xceptions = program_->get_xceptions(); vector::iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { generate_xception(*x_iter); } // Generate typedefs vector typedefs = program_->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { generate_typedef(*td_iter); } // Generate services vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { service_name_ = get_service_name(*sv_iter); generate_service(*sv_iter); } // Generate constants vector consts = program_->get_consts(); generate_consts(consts); // Close the generator close_generator(); } /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_ocaml_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); // Make output file string f_types_name = get_out_dir() + program_name_ + "_types.ml"; f_types_.open(f_types_name.c_str()); string f_types_i_name = get_out_dir() + program_name_ + "_types.mli"; f_types_i_.open(f_types_i_name.c_str()); string f_consts_name = get_out_dir() + program_name_ + "_consts.ml"; f_consts_.open(f_consts_name.c_str()); // Print header f_types_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; f_types_i_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; f_consts_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl << "open " << capitalize(program_name_) << "_types" << endl; } /** * Autogen'd comment */ string t_ocaml_generator::ocaml_autogen_comment() { return std::string("(*\n") + " Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "\n" + " DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING\n" + "*)\n"; } /** * Prints standard thrift imports */ string t_ocaml_generator::ocaml_imports() { return "open Thrift"; } /** * Closes the type files */ void t_ocaml_generator::close_generator() { // Close types file f_types_.close(); } /** * Generates a typedef. Ez. * * @param ttypedef The type definition */ void t_ocaml_generator::generate_typedef(t_typedef* ttypedef) { f_types_ << indent() << "type " << decapitalize(ttypedef->get_symbolic()) << " = " << render_ocaml_type(ttypedef->get_type()) << endl << endl; f_types_i_ << indent() << "type " << decapitalize(ttypedef->get_symbolic()) << " = " << render_ocaml_type(ttypedef->get_type()) << endl << endl; } /** * Generates code for an enumerated type. * the values. * * @param tenum The enumeration */ void t_ocaml_generator::generate_enum(t_enum* tenum) { indent(f_types_) << "module " << capitalize(tenum->get_name()) << " = " << endl << "struct" << endl; indent(f_types_i_) << "module " << capitalize(tenum->get_name()) << " : " << endl << "sig" << endl; indent_up(); indent(f_types_) << "type t = " << endl; indent(f_types_i_) << "type t = " << endl; indent_up(); vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { string name = capitalize((*c_iter)->get_name()); indent(f_types_) << "| " << name << endl; indent(f_types_i_) << "| " << name << endl; } indent_down(); indent(f_types_) << "let to_i = function" << endl; indent(f_types_i_) << "val to_i : t -> Int32.t" << endl; indent_up(); for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); string name = capitalize((*c_iter)->get_name()); indent(f_types_) << "| " << name << " -> " << value << "l" << endl; } indent_down(); indent(f_types_) << "let of_i = function" << endl; indent(f_types_i_) << "val of_i : Int32.t -> t" << endl; indent_up(); for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); string name = capitalize((*c_iter)->get_name()); indent(f_types_) << "| " << value << "l -> " << name << endl; } indent(f_types_) << "| _ -> raise Thrift_error" << endl; indent_down(); indent_down(); indent(f_types_) << "end" << endl; indent(f_types_i_) << "end" << endl; } /** * Generate a constant value */ void t_ocaml_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = decapitalize(tconst->get_name()); t_const_value* value = tconst->get_value(); indent(f_consts_) << "let " << name << " = " << render_const_value(type, value) << endl << endl; } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_ocaml_generator::render_const_value(t_type* type, t_const_value* value) { type = get_true_type(type); std::ostringstream out; // OCaml requires all floating point numbers contain a decimal point out.setf(ios::showpoint); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: out << value->get_integer(); break; case t_base_type::TYPE_I32: out << value->get_integer() << "l"; break; case t_base_type::TYPE_I64: out << value->get_integer() << "L"; break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer() << ".0"; } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { t_enum* tenum = (t_enum*)type; vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int val = (*c_iter)->get_value(); if (val == value->get_integer()) { indent(out) << capitalize(tenum->get_name()) << "." << capitalize((*c_iter)->get_name()); break; } } } else if (type->is_struct() || type->is_xception()) { string cname = type_name(type); string ct = tmp("_c"); out << endl; indent_up(); indent(out) << "(let " << ct << " = new " << cname << " in" << endl; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } string fname = v_iter->first->get_string(); out << indent(); out << ct << "#set_" << fname << " "; out << render_const_value(field_type, v_iter->second); out << ";" << endl; } indent(out) << ct << ")"; indent_down(); indent_down(); } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; string hm = tmp("_hm"); out << endl; indent_up(); indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl; indent_up(); for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string key = render_const_value(ktype, v_iter->first); string val = render_const_value(vtype, v_iter->second); indent(out) << "Hashtbl.add " << hm << " " << key << " " << val << ";" << endl; } indent(out) << hm << ")"; indent_down(); indent_down(); } else if (type->is_list()) { t_type* etype; etype = ((t_list*)type)->get_elem_type(); out << "[" << endl; indent_up(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent(); out << render_const_value(etype, *v_iter); out << ";" << endl; } indent_down(); indent(out) << "]"; } else if (type->is_set()) { t_type* etype = ((t_set*)type)->get_elem_type(); const vector& val = value->get_list(); vector::const_iterator v_iter; string hm = tmp("_hm"); indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl; indent_up(); for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { string val = render_const_value(etype, *v_iter); indent(out) << "Hashtbl.add " << hm << " " << val << " true;" << endl; } indent(out) << hm << ")" << endl; indent_down(); out << endl; } else { throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); } return out.str(); } /** * Generates a "struct" */ void t_ocaml_generator::generate_struct(t_struct* tstruct) { generate_ocaml_struct(tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct, but also has an exception declaration. * * @param txception The struct definition */ void t_ocaml_generator::generate_xception(t_struct* txception) { generate_ocaml_struct(txception, true); } /** * Generates an OCaml struct */ void t_ocaml_generator::generate_ocaml_struct(t_struct* tstruct, bool is_exception) { generate_ocaml_struct_definition(f_types_, tstruct, is_exception); generate_ocaml_struct_sig(f_types_i_, tstruct, is_exception); } void t_ocaml_generator::generate_ocaml_method_copy(ostream& out, const vector& members) { vector::const_iterator m_iter; /* Create a copy of the current object */ indent(out) << "method copy =" << endl; indent_up(); indent_up(); indent(out) << "let _new = Oo.copy self in" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) generate_ocaml_member_copy(out, *m_iter); indent_down(); indent(out) << "_new" << endl; indent_down(); } string t_ocaml_generator::struct_member_copy_of(t_type* type, string what) { if (type->is_struct() || type->is_xception()) { return what + string("#copy"); } if (type->is_map()) { string copy_of_k = struct_member_copy_of(((t_map*)type)->get_key_type(), "k"); string copy_of_v = struct_member_copy_of(((t_map*)type)->get_val_type(), "v"); if (copy_of_k == "k" && copy_of_v == "v") { return string("(Hashtbl.copy ") + what + string(")"); } else { return string( "((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v " "-> Hashtbl.add nh ") + copy_of_k + string(" ") + copy_of_v + string(") oh; nh) ") + what + ")"; } } if (type->is_set()) { string copy_of = struct_member_copy_of(((t_set*)type)->get_elem_type(), "k"); if (copy_of == "k") { return string("(Hashtbl.copy ") + what + string(")"); } else { return string( "((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v " "-> Hashtbl.add nh ") + copy_of + string(" true") + string(") oh; nh) ") + what + ")"; } } if (type->is_list()) { string copy_of = struct_member_copy_of(((t_list*)type)->get_elem_type(), "x"); if (copy_of != "x") { return string("(List.map (fun x -> ") + copy_of + string(") ") + what + string(")"); } else { return what; } } return what; } void t_ocaml_generator::generate_ocaml_member_copy(ostream& out, t_field* tmember) { string mname = decapitalize(tmember->get_name()); t_type* type = get_true_type(tmember->get_type()); string grab_field = string("self#grab_") + mname; string copy_of = struct_member_copy_of(type, grab_field); if (copy_of != grab_field) { indent(out); if (!struct_member_persistent(tmember)) { out << "if _" << mname << " <> None then" << endl; indent(out) << " "; } out << "_new#set_" << mname << " " << copy_of << ";" << endl; } } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_ocaml_generator::generate_ocaml_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; string tname = type_name(tstruct); indent(out) << "class " << tname << " =" << endl; indent(out) << "object (self)" << endl; indent_up(); if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_ocaml_struct_member(out, tname, (*m_iter)); out << endl; } } generate_ocaml_method_copy(out, members); generate_ocaml_struct_writer(out, tstruct); indent_down(); indent(out) << "end" << endl; if (is_exception) { indent(out) << "exception " << capitalize(tname) << " of " << tname << endl; } generate_ocaml_struct_reader(out, tstruct); } /** * Generates a structure member for a thrift data type. * * @param tname Name of the parent structure for the member * @param tmember Member definition */ void t_ocaml_generator::generate_ocaml_struct_member(ostream& out, string tname, t_field* tmember) { string x = tmp("_x"); string mname = decapitalize(tmember->get_name()); indent(out) << "val mutable _" << mname << " : " << render_ocaml_type(tmember->get_type()); t_const_value* val = tmember->get_value(); if (val) { if (struct_member_persistent(tmember)) out << " = " << render_const_value(tmember->get_type(), tmember->get_value()) << endl; else out << " option = Some " << render_const_value(tmember->get_type(), tmember->get_value()) << endl; } else { // assert(!struct_member_persistent(tmember)) out << " option = None" << endl; } if (struct_member_persistent(tmember)) { indent(out) << "method get_" << mname << " = Some _" << mname << endl; indent(out) << "method grab_" << mname << " = _" << mname << endl; indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- " << x << endl; } else { indent(out) << "method get_" << mname << " = _" << mname << endl; indent(out) << "method grab_" << mname << " = match _" << mname << " with None->raise (Field_empty \"" << tname << "." << mname << "\") | Some " << x << " -> " << x << endl; indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- Some " << x << endl; indent(out) << "method unset_" << mname << " = _" << mname << " <- None" << endl; } indent(out) << "method reset_" << mname << " = _" << mname << " <- "; if (val) { if (struct_member_persistent(tmember)) out << render_const_value(tmember->get_type(), tmember->get_value()) << endl; else out << "Some " << render_const_value(tmember->get_type(), tmember->get_value()) << endl; } else { out << "None" << endl; } } /** * Check whether a member of the structure can not have undefined value * * @param tmember Member definition */ bool t_ocaml_generator::struct_member_persistent(t_field* tmember) { t_const_value* val = tmember->get_value(); return (val ? true : false); } /** * Check whether a member of the structure can be skipped during encoding * * @param tmember Member definition */ bool t_ocaml_generator::struct_member_omitable(t_field* tmember) { return (tmember->get_req() != t_field::T_REQUIRED); } /** * Figure out whether a member of the structure has * a cheaply comparable default value. * * @param tmember Member definition */ bool t_ocaml_generator::struct_member_default_cheaply_comparable(t_field* tmember) { t_type* type = get_true_type(tmember->get_type()); t_const_value* val = tmember->get_value(); if (!val) { return false; } else if (type->is_base_type()) { // Base types are generally cheaply compared for structural equivalence. switch (((t_base_type*)type)->get_base()) { case t_base_type::TYPE_DOUBLE: if (val->get_double() == 0.0) return true; else return false; default: return true; } } else if (type->is_list()) { // Empty lists are cheaply compared for structural equivalence. // Is empty list? if (val->get_list().size() == 0) return true; else return false; } else { return false; } } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_ocaml_generator::generate_ocaml_struct_sig(ostream& out, t_struct* tstruct, bool is_exception) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; string tname = type_name(tstruct); indent(out) << "class " << tname << " :" << endl; indent(out) << "object ('a)" << endl; indent_up(); string x = tmp("_x"); if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { string mname = decapitalize((*m_iter)->get_name()); string type = render_ocaml_type((*m_iter)->get_type()); indent(out) << "method get_" << mname << " : " << type << " option" << endl; indent(out) << "method grab_" << mname << " : " << type << endl; indent(out) << "method set_" << mname << " : " << type << " -> unit" << endl; if (!struct_member_persistent(*m_iter)) indent(out) << "method unset_" << mname << " : unit" << endl; indent(out) << "method reset_" << mname << " : unit" << endl; } } indent(out) << "method copy : 'a" << endl; indent(out) << "method write : Protocol.t -> unit" << endl; indent_down(); indent(out) << "end" << endl; if (is_exception) { indent(out) << "exception " << capitalize(tname) << " of " << tname << endl; } indent(out) << "val read_" << tname << " : Protocol.t -> " << tname << endl; } /** * Generates the read method for a struct */ void t_ocaml_generator::generate_ocaml_struct_reader(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; string sname = type_name(tstruct); string str = tmp("_str"); string t = tmp("_t"); string id = tmp("_id"); indent(out) << "let rec read_" << sname << " (iprot : Protocol.t) =" << endl; indent_up(); indent(out) << "let " << str << " = new " << sname << " in" << endl; indent_up(); indent(out) << "ignore(iprot#readStructBegin);" << endl; // Loop over reading in fields indent(out) << "(try while true do" << endl; indent_up(); indent_up(); // Read beginning field marker indent(out) << "let (_," << t << "," << id << ") = iprot#readFieldBegin in" << endl; // Check for field STOP marker and break indent(out) << "if " << t << " = Protocol.T_STOP then" << endl; indent_up(); indent(out) << "raise Break" << endl; indent_down(); indent(out) << "else ();" << endl; indent(out) << "(match " << id << " with " << endl; indent_up(); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "| " << (*f_iter)->get_key() << " -> ("; out << "if " << t << " = " << type_to_enum((*f_iter)->get_type()) << " then" << endl; indent_up(); indent_up(); generate_deserialize_field(out, *f_iter, str); indent_down(); out << indent() << "else" << endl << indent() << " iprot#skip " << t << ")" << endl; indent_down(); } // In the default case we skip the field out << indent() << "| _ -> " << "iprot#skip " << t << ");" << endl; indent_down(); // Read field end marker indent(out) << "iprot#readFieldEnd;" << endl; indent_down(); indent(out) << "done; ()" << endl; indent_down(); indent(out) << "with Break -> ());" << endl; indent(out) << "iprot#readStructEnd;" << endl; indent(out) << str << endl << endl; indent_down(); indent_down(); } void t_ocaml_generator::generate_ocaml_struct_writer(ostream& out, t_struct* tstruct) { string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; string str = tmp("_str"); string f = tmp("_f"); indent(out) << "method write (oprot : Protocol.t) =" << endl; indent_up(); indent(out) << "oprot#writeStructBegin \"" << name << "\";" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* tmember = (*f_iter); string mname = "_" + decapitalize(tmember->get_name()); string _v; if (struct_member_persistent(tmember)) { if (struct_member_omitable(tmember) && struct_member_default_cheaply_comparable(tmember)) { _v = "_v"; // Avoid redundant encoding of members having default values. indent(out) << "(match " << mname << " with " << render_const_value(tmember->get_type(), tmember->get_value()) << " -> () | " << _v << " -> " << endl; } else { _v = mname; indent(out) << "(" << endl; } } else { indent(out) << "(match " << mname << " with "; if (struct_member_omitable(tmember)) { out << "None -> ()"; if (struct_member_default_cheaply_comparable(tmember)) { // Avoid redundant encoding of members having default values. out << " | Some " << render_const_value(tmember->get_type(), tmember->get_value()) << " -> ()"; } out << " | Some _v -> " << endl; } else { out << endl; indent(out) << "| None -> raise (Field_empty \"" << type_name(tstruct) << "." << mname << "\")" << endl; indent(out) << "| Some _v -> " << endl; } _v = "_v"; } indent_up(); // Write field header indent(out) << "oprot#writeFieldBegin(\"" << tmember->get_name() << "\"," << type_to_enum(tmember->get_type()) << "," << tmember->get_key() << ");" << endl; // Write field contents generate_serialize_field(out, tmember, _v); // Write field closer indent(out) << "oprot#writeFieldEnd" << endl; indent_down(); indent(out) << ");" << endl; } // Write the struct map out << indent() << "oprot#writeFieldStop;" << endl << indent() << "oprot#writeStructEnd" << endl; indent_down(); } /** * Generates a thrift service. * * @param tservice The service definition */ void t_ocaml_generator::generate_service(t_service* tservice) { string f_service_name = get_out_dir() + capitalize(service_name_) + ".ml"; f_service_.open(f_service_name.c_str()); string f_service_i_name = get_out_dir() + capitalize(service_name_) + ".mli"; f_service_i_.open(f_service_i_name.c_str()); f_service_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; f_service_i_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl; /* if (tservice->get_extends() != nullptr) { f_service_ << "open " << capitalize(tservice->get_extends()->get_name()) << endl; f_service_i_ << "open " << capitalize(tservice->get_extends()->get_name()) << endl; } */ f_service_ << "open " << capitalize(program_name_) << "_types" << endl << endl; f_service_i_ << "open " << capitalize(program_name_) << "_types" << endl << endl; // Generate the three main parts of the service generate_service_helpers(tservice); generate_service_interface(tservice); generate_service_client(tservice); generate_service_server(tservice); // Close service file f_service_.close(); f_service_i_.close(); } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_ocaml_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; indent(f_service_) << "(* HELPER FUNCTIONS AND STRUCTURES *)" << endl << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_ocaml_struct_definition(f_service_, ts, false); generate_ocaml_function_helpers(*f_iter); } } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_ocaml_generator::generate_ocaml_function_helpers(t_function* tfunction) { t_struct result(program_, decapitalize(tfunction->get_name()) + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_ocaml_struct_definition(f_service_, &result, false); } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_ocaml_generator::generate_service_interface(t_service* tservice) { f_service_ << indent() << "class virtual iface =" << endl << "object (self)" << endl; f_service_i_ << indent() << "class virtual iface :" << endl << "object" << endl; indent_up(); if (tservice->get_extends() != nullptr) { string extends = type_name(tservice->get_extends()); indent(f_service_) << "inherit " << extends << ".iface" << endl; indent(f_service_i_) << "inherit " << extends << ".iface" << endl; } vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string ft = function_type(*f_iter, true, true); f_service_ << indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " << ft << endl; f_service_i_ << indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " << ft << endl; } indent_down(); indent(f_service_) << "end" << endl << endl; indent(f_service_i_) << "end" << endl << endl; } /** * Generates a service client definition. Note that in OCaml, the client doesn't implement iface. *This is because * The client does not (and should not have to) deal with arguments being None. * * @param tservice The service to generate a server for. */ void t_ocaml_generator::generate_service_client(t_service* tservice) { string extends = ""; indent(f_service_) << "class client (iprot : Protocol.t) (oprot : Protocol.t) =" << endl << "object (self)" << endl; indent(f_service_i_) << "class client : Protocol.t -> Protocol.t -> " << endl << "object" << endl; indent_up(); if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); indent(f_service_) << "inherit " << extends << ".client iprot oprot as super" << endl; indent(f_service_i_) << "inherit " << extends << ".client" << endl; } indent(f_service_) << "val mutable seqid = 0" << endl; // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = (*f_iter)->get_name(); // Open function indent(f_service_) << "method " << function_signature(*f_iter) << " = " << endl; indent(f_service_i_) << "method " << decapitalize((*f_iter)->get_name()) << " : " << function_type(*f_iter, true, false) << endl; indent_up(); indent(f_service_) << "self#send_" << funname; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << " " << decapitalize((*fld_iter)->get_name()); } f_service_ << ";" << endl; if (!(*f_iter)->is_oneway()) { f_service_ << indent(); f_service_ << "self#recv_" << funname << endl; } indent_down(); indent(f_service_) << "method private send_" << function_signature(*f_iter) << " = " << endl; indent_up(); std::string argsname = decapitalize((*f_iter)->get_name() + "_args"); // Serialize the request header f_service_ << indent() << "oprot#writeMessageBegin (\"" << (*f_iter)->get_name() << "\", " << ((*f_iter)->is_oneway() ? "Protocol.ONEWAY" : "Protocol.CALL") << ", seqid);" << endl; f_service_ << indent() << "let args = new " << argsname << " in" << endl; indent_up(); for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << indent() << "args#set_" << (*fld_iter)->get_name() << " " << (*fld_iter)->get_name() << ";" << endl; } // Write to the stream f_service_ << indent() << "args#write oprot;" << endl << indent() << "oprot#writeMessageEnd;" << endl << indent() << "oprot#getTransport#flush" << endl; indent_down(); indent_down(); if (!(*f_iter)->is_oneway()) { std::string resultname = decapitalize((*f_iter)->get_name() + "_result"); t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); // Open function f_service_ << indent() << "method private " << function_signature(&recv_function) << " =" << endl; indent_up(); // TODO(mcslee): Validate message reply here, seq ids etc. f_service_ << indent() << "let (fname, mtype, rseqid) = iprot#readMessageBegin in" << endl; indent_up(); f_service_ << indent() << "(if mtype = Protocol.EXCEPTION then" << endl << indent() << " let x = Application_Exn.read iprot in" << endl; indent_up(); f_service_ << indent() << " (iprot#readMessageEnd;" << indent() << " raise (Application_Exn.E x))" << endl; indent_down(); f_service_ << indent() << "else ());" << endl; string res = "_"; t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); if (!(*f_iter)->get_returntype()->is_void() || xceptions.size() > 0) { res = "result"; } f_service_ << indent() << "let " << res << " = read_" << resultname << " iprot in" << endl; indent_up(); f_service_ << indent() << "iprot#readMessageEnd;" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << "match result#get_success with Some v -> v | None -> (" << endl; indent_up(); } vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << "(match result#get_" << (*x_iter)->get_name() << " with None -> () | Some _v ->" << endl; indent(f_service_) << " raise (" << capitalize(type_name((*x_iter)->get_type())) << " _v));" << endl; } // Careful, only return _result if not a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "()" << endl; } else { f_service_ << indent() << "raise (Application_Exn.E (Application_Exn.create Application_Exn.MISSING_RESULT \"" << (*f_iter)->get_name() << " failed: unknown result\")))" << endl; indent_down(); } // Close function indent_down(); indent_down(); indent_down(); } } indent_down(); indent(f_service_) << "end" << endl << endl; indent(f_service_i_) << "end" << endl << endl; } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_ocaml_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; // Generate the header portion indent(f_service_) << "class processor (handler : iface) =" << endl << indent() << "object (self)" << endl; indent(f_service_i_) << "class processor : iface ->" << endl << indent() << "object" << endl; indent_up(); f_service_ << indent() << "inherit Processor.t" << endl << endl; f_service_i_ << indent() << "inherit Processor.t" << endl << endl; string extends = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); indent(f_service_) << "inherit " + extends + ".processor (handler :> " + extends + ".iface)" << endl; indent(f_service_i_) << "inherit " + extends + ".processor" << endl; } if (extends.empty()) { indent(f_service_) << "val processMap = Hashtbl.create " << functions.size() << endl; } indent(f_service_i_) << "val processMap : (string, int * Protocol.t * Protocol.t -> unit) Hashtbl.t" << endl; // Generate the server implementation indent(f_service_) << "method process iprot oprot =" << endl; indent(f_service_i_) << "method process : Protocol.t -> Protocol.t -> bool" << endl; indent_up(); f_service_ << indent() << "let (name, typ, seqid) = iprot#readMessageBegin in" << endl; indent_up(); // TODO(mcslee): validate message // HOT: dictionary function lookup f_service_ << indent() << "if Hashtbl.mem processMap name then" << endl << indent() << " (Hashtbl.find processMap name) (seqid, iprot, oprot)" << endl << indent() << "else (" << endl << indent() << " iprot#skip(Protocol.T_STRUCT);" << endl << indent() << " iprot#readMessageEnd;" << endl << indent() << " let x = Application_Exn.create Application_Exn.UNKNOWN_METHOD (\"Unknown " "function \"^name) in" << endl << indent() << " oprot#writeMessageBegin(name, Protocol.EXCEPTION, seqid);" << endl << indent() << " x#write oprot;" << endl << indent() << " oprot#writeMessageEnd;" << endl << indent() << " oprot#getTransport#flush" << endl << indent() << ");" << endl; // Read end of args field, the T_STOP, and the struct close f_service_ << indent() << "true" << endl; indent_down(); indent_down(); // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } indent(f_service_) << "initializer" << endl; indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << indent() << "Hashtbl.add processMap \"" << (*f_iter)->get_name() << "\" self#process_" << (*f_iter)->get_name() << ";" << endl; } indent_down(); indent_down(); indent(f_service_) << "end" << endl << endl; indent(f_service_i_) << "end" << endl << endl; } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_ocaml_generator::generate_process_function(t_service* tservice, t_function* tfunction) { (void)tservice; // Open function indent(f_service_) << "method private process_" << tfunction->get_name() << " (seqid, iprot, oprot) =" << endl; indent_up(); string argsname = decapitalize(tfunction->get_name()) + "_args"; string resultname = decapitalize(tfunction->get_name()) + "_result"; // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; string args = "args"; if (fields.size() == 0) { args = "_"; } f_service_ << indent() << "let " << args << " = read_" << argsname << " iprot in" << endl; indent_up(); f_service_ << indent() << "iprot#readMessageEnd;" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Declare result for non oneway function if (!tfunction->is_oneway()) { f_service_ << indent() << "let result = new " << resultname << " in" << endl; indent_up(); } // Try block for a function with exceptions if (xceptions.size() > 0) { f_service_ << indent() << "(try" << endl; indent_up(); } f_service_ << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_service_ << "result#set_success "; } f_service_ << "(handler#" << tfunction->get_name(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { f_service_ << " args#get_" << (*f_iter)->get_name(); } f_service_ << ");" << endl; if (xceptions.size() > 0) { indent_down(); indent(f_service_) << "with" << endl; indent_up(); for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << "| " << capitalize(type_name((*x_iter)->get_type())) << " " << (*x_iter)->get_name() << " -> " << endl; indent_up(); indent_up(); if (!tfunction->is_oneway()) { f_service_ << indent() << "result#set_" << (*x_iter)->get_name() << " " << (*x_iter)->get_name() << endl; } else { indent(f_service_) << "()"; } indent_down(); indent_down(); } indent_down(); f_service_ << indent() << ");" << endl; } // Shortcut out here for oneway functions if (tfunction->is_oneway()) { f_service_ << indent() << "()" << endl; indent_down(); indent_down(); return; } f_service_ << indent() << "oprot#writeMessageBegin (\"" << tfunction->get_name() << "\", Protocol.REPLY, seqid);" << endl << indent() << "result#write oprot;" << endl << indent() << "oprot#writeMessageEnd;" << endl << indent() << "oprot#getTransport#flush" << endl; // Close function indent_down(); indent_down(); indent_down(); } /** * Deserializes a field of any type. */ void t_ocaml_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = tfield->get_type(); string name = decapitalize(tfield->get_name()); indent(out) << prefix << "#set_" << name << " "; generate_deserialize_type(out, type); out << endl; } /** * Deserializes a field of any type. */ void t_ocaml_generator::generate_deserialize_type(ostream& out, t_type* type) { type = get_true_type(type); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE"; } if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type); } else if (type->is_container()) { generate_deserialize_container(out, type); } else if (type->is_base_type()) { out << "iprot#"; t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct"; break; case t_base_type::TYPE_STRING: out << "readString"; break; case t_base_type::TYPE_BOOL: out << "readBool"; break; case t_base_type::TYPE_I8: out << "readByte"; break; case t_base_type::TYPE_I16: out << "readI16"; break; case t_base_type::TYPE_I32: out << "readI32"; break; case t_base_type::TYPE_I64: out << "readI64"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble"; break; default: throw "compiler error: no ocaml name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { string ename = capitalize(type->get_name()); out << "(" << ename << ".of_i iprot#readI32)"; } else { printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n", type->get_name().c_str()); } } /** * Generates an unserializer for a struct, calling read() */ void t_ocaml_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct) { string prefix = ""; t_program* program = tstruct->get_program(); if (program != nullptr && program != program_) { prefix = capitalize(program->get_name()) + "_types."; } string name = decapitalize(tstruct->get_name()); out << "(" << prefix << "read_" << name << " iprot)"; } /** * Serialize a container by writing out the header followed by * data and then a footer. */ void t_ocaml_generator::generate_deserialize_container(ostream& out, t_type* ttype) { string size = tmp("_size"); string ktype = tmp("_ktype"); string vtype = tmp("_vtype"); string etype = tmp("_etype"); string con = tmp("_con"); t_field fsize(g_type_i32, size); t_field fktype(g_type_i8, ktype); t_field fvtype(g_type_i8, vtype); t_field fetype(g_type_i8, etype); out << endl; indent_up(); // Declare variables, read header if (ttype->is_map()) { indent(out) << "(let (" << ktype << "," << vtype << "," << size << ") = iprot#readMapBegin in" << endl; indent(out) << "let " << con << " = Hashtbl.create " << size << " in" << endl; indent_up(); indent(out) << "for i = 1 to " << size << " do" << endl; indent_up(); indent(out) << "let _k = "; generate_deserialize_type(out, ((t_map*)ttype)->get_key_type()); out << " in" << endl; indent(out) << "let _v = "; generate_deserialize_type(out, ((t_map*)ttype)->get_val_type()); out << " in" << endl; indent_up(); indent(out) << "Hashtbl.add " << con << " _k _v" << endl; indent_down(); indent_down(); indent(out) << "done; iprot#readMapEnd; " << con << ")"; indent_down(); } else if (ttype->is_set()) { indent(out) << "(let (" << etype << "," << size << ") = iprot#readSetBegin in" << endl; indent(out) << "let " << con << " = Hashtbl.create " << size << " in" << endl; indent_up(); indent(out) << "for i = 1 to " << size << " do" << endl; indent_up(); indent(out) << "Hashtbl.add " << con << " "; generate_deserialize_type(out, ((t_set*)ttype)->get_elem_type()); out << " true" << endl; indent_down(); indent(out) << "done; iprot#readSetEnd; " << con << ")"; indent_down(); } else if (ttype->is_list()) { indent(out) << "(let (" << etype << "," << size << ") = iprot#readListBegin in" << endl; indent_up(); indent(out) << "let " << con << " = (Array.to_list (Array.init " << size << " (fun _ -> "; generate_deserialize_type(out, ((t_list*)ttype)->get_elem_type()); out << "))) in" << endl; indent_up(); indent(out) << "iprot#readListEnd; " << con << ")"; indent_down(); indent_down(); } indent_down(); } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_ocaml_generator::generate_serialize_field(ostream& out, t_field* tfield, string name) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name(); } if (name.length() == 0) { name = decapitalize(tfield->get_name()); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_serialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << "oprot#"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << "writeString(" << name << ")"; break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ")"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ")"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ")"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ")"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ")"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ")"; break; default: throw "compiler error: no ocaml name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { string ename = capitalize(type->get_name()); out << "writeI32(" << ename << ".to_i " << name << ")"; } } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type->get_name().c_str()); } out << ";" << endl; } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_ocaml_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; indent(out) << prefix << "#write(oprot)"; } void t_ocaml_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { if (ttype->is_map()) { indent(out) << "oprot#writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ","; out << type_to_enum(((t_map*)ttype)->get_val_type()) << ","; out << "Hashtbl.length " << prefix << ");" << endl; } else if (ttype->is_set()) { indent(out) << "oprot#writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ","; out << "Hashtbl.length " << prefix << ");" << endl; } else if (ttype->is_list()) { indent(out) << "oprot#writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ","; out << "List.length " << prefix << ");" << endl; } if (ttype->is_map()) { string kiter = tmp("_kiter"); string viter = tmp("_viter"); indent(out) << "Hashtbl.iter (fun " << kiter << " -> fun " << viter << " -> " << endl; indent_up(); generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); indent_down(); indent(out) << ") " << prefix << ";" << endl; } else if (ttype->is_set()) { string iter = tmp("_iter"); indent(out) << "Hashtbl.iter (fun " << iter << " -> fun _ -> "; indent_up(); generate_serialize_set_element(out, (t_set*)ttype, iter); indent_down(); indent(out) << ") " << prefix << ";" << endl; } else if (ttype->is_list()) { string iter = tmp("_iter"); indent(out) << "List.iter (fun " << iter << " -> "; indent_up(); generate_serialize_list_element(out, (t_list*)ttype, iter); indent_down(); indent(out) << ") " << prefix << ";" << endl; } if (ttype->is_map()) { indent(out) << "oprot#writeMapEnd"; } else if (ttype->is_set()) { indent(out) << "oprot#writeSetEnd"; } else if (ttype->is_list()) { indent(out) << "oprot#writeListEnd"; } } /** * Serializes the members of a map. * */ void t_ocaml_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter) { t_field kfield(tmap->get_key_type(), kiter); generate_serialize_field(out, &kfield); t_field vfield(tmap->get_val_type(), viter); generate_serialize_field(out, &vfield); } /** * Serializes the members of a set. */ void t_ocaml_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield); } /** * Serializes the members of a list. */ void t_ocaml_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield); } /** * Renders a function signature of the form 'name args' * * @param tfunction Function definition * @return String of rendered function definition */ string t_ocaml_generator::function_signature(t_function* tfunction, string prefix) { return prefix + decapitalize(tfunction->get_name()) + " " + argument_list(tfunction->get_arglist()); } string t_ocaml_generator::function_type(t_function* tfunc, bool method, bool options) { string result = ""; const vector& fields = tfunc->get_arglist()->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result += render_ocaml_type((*f_iter)->get_type()); if (options) result += " option"; result += " -> "; } if (fields.empty() && !method) { result += "unit -> "; } result += render_ocaml_type(tfunc->get_returntype()); return result; } /** * Renders a field list */ string t_ocaml_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += " "; } result += (*f_iter)->get_name(); } return result; } string t_ocaml_generator::type_name(t_type* ttype) { string prefix = ""; t_program* program = ttype->get_program(); if (program != nullptr && program != program_) { if (!ttype->is_service()) { prefix = capitalize(program->get_name()) + "_types."; } } string name = ttype->get_name(); if (ttype->is_service()) { name = capitalize(name); } else { name = decapitalize(name); } return prefix + name; } /** * Converts the parse type to a Protocol.t_type enum */ string t_ocaml_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "Protocol.T_VOID"; case t_base_type::TYPE_STRING: return "Protocol.T_STRING"; case t_base_type::TYPE_BOOL: return "Protocol.T_BOOL"; case t_base_type::TYPE_I8: return "Protocol.T_BYTE"; case t_base_type::TYPE_I16: return "Protocol.T_I16"; case t_base_type::TYPE_I32: return "Protocol.T_I32"; case t_base_type::TYPE_I64: return "Protocol.T_I64"; case t_base_type::TYPE_DOUBLE: return "Protocol.T_DOUBLE"; } } else if (type->is_enum()) { return "Protocol.T_I32"; } else if (type->is_struct() || type->is_xception()) { return "Protocol.T_STRUCT"; } else if (type->is_map()) { return "Protocol.T_MAP"; } else if (type->is_set()) { return "Protocol.T_SET"; } else if (type->is_list()) { return "Protocol.T_LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Converts the parse type to an ocaml type */ string t_ocaml_generator::render_ocaml_type(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "unit"; case t_base_type::TYPE_STRING: return "string"; case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: return "int"; case t_base_type::TYPE_I16: return "int"; case t_base_type::TYPE_I32: return "Int32.t"; case t_base_type::TYPE_I64: return "Int64.t"; case t_base_type::TYPE_DOUBLE: return "float"; } } else if (type->is_enum()) { return capitalize(((t_enum*)type)->get_name()) + ".t"; } else if (type->is_struct() || type->is_xception()) { return type_name((t_struct*)type); } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); return "(" + render_ocaml_type(ktype) + "," + render_ocaml_type(vtype) + ") Hashtbl.t"; } else if (type->is_set()) { t_type* etype = ((t_set*)type)->get_elem_type(); return "(" + render_ocaml_type(etype) + ",bool) Hashtbl.t"; } else if (type->is_list()) { t_type* etype = ((t_list*)type)->get_elem_type(); return render_ocaml_type(etype) + " list"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_oop_generator.h000066400000000000000000000066331420101504100247060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_OOP_GENERATOR_H #define T_OOP_GENERATOR_H #include #include #include "thrift/common.h" #include "thrift/generate/t_generator.h" #include /** * Class with utility methods shared across common object oriented languages. * Specifically, most of this stuff is for C++/Java. * */ class t_oop_generator : public t_generator { public: t_oop_generator(t_program* program) : t_generator(program) {} /** * Scoping, using curly braces! */ void scope_up(std::ostream& out) { indent(out) << "{" << std::endl; indent_up(); } void scope_down(std::ostream& out) { indent_down(); indent(out) << "}" << std::endl; } std::string upcase_string(std::string original) { std::transform(original.begin(), original.end(), original.begin(), (int (*)(int))toupper); return original; } virtual std::string get_enum_class_name(t_type* type) { std::string package = ""; t_program* program = type->get_program(); if (program != nullptr && program != program_) { package = program->get_namespace("java") + "."; } return package + type->get_name(); } virtual void generate_java_docstring_comment(std::ostream& out, std::string contents) { generate_docstring_comment(out, "/**\n", " * ", contents, " */\n"); } virtual void generate_java_doc(std::ostream& out, t_field* field) { if (field->get_type()->is_enum()) { std::string combined_message = field->get_doc() + "\n@see " + get_enum_class_name(field->get_type()); generate_java_docstring_comment(out, combined_message); } else { generate_java_doc(out, (t_doc*)field); } } /** * Emits a JavaDoc comment if the provided object has a doc in Thrift */ virtual void generate_java_doc(std::ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_java_docstring_comment(out, tdoc->get_doc()); } } /** * Emits a JavaDoc comment if the provided function object has a doc in Thrift */ virtual void generate_java_doc(std::ostream& out, t_function* tfunction) { if (tfunction->has_doc()) { std::stringstream ss; ss << tfunction->get_doc(); const std::vector& fields = tfunction->get_arglist()->get_members(); std::vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; ss << "\n@param " << p->get_name(); if (p->has_doc()) { ss << " " << p->get_doc(); } } generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); } } }; #endif thrift-0.16.0/compiler/cpp/src/thrift/generate/t_perl_generator.cc000066400000000000000000001565221420101504100252140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * PERL code generator. * */ class t_perl_generator : public t_oop_generator { public: t_perl_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program), f_types_use_includes_emitted_(false) { (void)option_string; std::map::const_iterator iter; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option perl:" + iter->first; } out_dir_base_ = "gen-perl"; escape_['$'] = "\\$"; escape_['@'] = "\\@"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; std::string render_const_value(t_type* type, t_const_value* value); /** * Structs! */ void generate_perl_struct(t_struct* tstruct, bool is_exception); void generate_perl_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false); void generate_perl_struct_reader(std::ostream& out, t_struct* tstruct); void generate_perl_struct_writer(std::ostream& out, t_struct* tstruct); void generate_perl_function_helpers(t_function* tfunction); /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_rest(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_processor(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); void generate_use_includes(std::ostream& os, bool& done, t_type *type, bool selfish); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", bool inclass = false); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); /** * Helper rendering functions */ std::string perl_includes(); std::string declare_field(t_field* tfield, bool init = false, bool obj = false); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string autogen_comment() override { return std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n"; } void perl_namespace_dirs(t_program* p, std::list& dirs) { std::string ns = p->get_namespace("perl"); std::string::size_type loc; if (ns.size() > 0) { while ((loc = ns.find(".")) != std::string::npos) { dirs.push_back(ns.substr(0, loc)); ns = ns.substr(loc + 1); } } if (ns.size() > 0) { dirs.push_back(ns); } } std::string perl_namespace(t_program* p) { std::string ns = p->get_namespace("perl"); std::string result = ""; std::string::size_type loc; if (ns.size() > 0) { while ((loc = ns.find(".")) != std::string::npos) { result += ns.substr(0, loc); result += "::"; ns = ns.substr(loc + 1); } if (ns.size() > 0) { result += ns + "::"; } } return result; } std::string get_namespace_out_dir() { std::string outdir = get_out_dir(); std::list dirs; perl_namespace_dirs(program_, dirs); std::list::iterator it; for (it = dirs.begin(); it != dirs.end(); it++) { outdir += *it + "/"; } return outdir; } private: /** * File streams */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_consts_; ofstream_with_content_based_conditional_update f_helpers_; ofstream_with_content_based_conditional_update f_service_; bool f_types_use_includes_emitted_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_perl_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); string outdir = get_out_dir(); std::list dirs; perl_namespace_dirs(program_, dirs); std::list::iterator it; for (it = dirs.begin(); it != dirs.end(); it++) { outdir += *it + "/"; MKDIR(outdir.c_str()); } // Make output file string f_types_name = outdir + "Types.pm"; f_types_.open(f_types_name.c_str()); string f_consts_name = outdir + "Constants.pm"; f_consts_.open(f_consts_name.c_str()); // Print header f_types_ << autogen_comment() << perl_includes(); // Print header f_consts_ << autogen_comment() << "package " << perl_namespace(program_) << "Constants;" << endl << perl_includes() << endl; } /** * Prints standard java imports */ string t_perl_generator::perl_includes() { string inc; inc = "use 5.10.0;\n"; inc += "use strict;\n"; inc += "use warnings;\n"; inc += "use Thrift::Exception;\n"; inc += "use Thrift::MessageType;\n"; inc += "use Thrift::Type;\n\n"; return inc; } /** * Close up (or down) some filez. */ void t_perl_generator::close_generator() { // Close types file f_types_ << "1;" << endl; f_types_.close(); f_consts_ << "1;" << endl; f_consts_.close(); } /** * Generates a typedef. This is not done in PERL, types are all implicit. * * @param ttypedef The type definition */ void t_perl_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Generates code for an enumerated type. Since define is expensive to lookup * in PERL, we use a global array for this. * * @param tenum The enumeration */ void t_perl_generator::generate_enum(t_enum* tenum) { f_types_ << "package " << perl_namespace(program_) << tenum->get_name() << ";" << endl; vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); f_types_ << "use constant " << (*c_iter)->get_name() << " => " << value << ";" << endl; } } /** * Generate a constant value */ void t_perl_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); f_consts_ << "use constant " << name << " => "; f_consts_ << render_const_value(type, value); f_consts_ << ";" << endl << endl; } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_perl_generator::render_const_value(t_type* type, t_const_value* value) { std::ostringstream out; type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "1" : "0"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << perl_namespace(type->get_program()) << type->get_name() << "->new({" << endl; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } indent(out) << render_const_value(g_type_string, v_iter->first); out << " => "; out << render_const_value(field_type, v_iter->second); out << ","; out << endl; } indent_down(); indent(out) << "})"; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); out << "{" << endl; indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { indent(out) << render_const_value(ktype, v_iter->first); out << " => "; out << render_const_value(vtype, v_iter->second); out << "," << endl; } indent_down(); indent(out) << "}"; } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } out << "[" << endl; indent_up(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { indent(out) << render_const_value(etype, *v_iter); if (type->is_set()) { out << " => 1"; } out << "," << endl; } indent_down(); indent(out) << "]"; } return out.str(); } /** * Make a struct */ void t_perl_generator::generate_struct(t_struct* tstruct) { generate_perl_struct(tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_perl_generator::generate_xception(t_struct* txception) { generate_perl_struct(txception, true); } /** * Structs can be normal or exceptions. */ void t_perl_generator::generate_perl_struct(t_struct* tstruct, bool is_exception) { generate_use_includes(f_types_, f_types_use_includes_emitted_, tstruct, false); generate_perl_struct_definition(f_types_, tstruct, is_exception); } /** * Generates a struct definition for a thrift data type. This is nothing in PERL * where the objects are all just associative arrays (unless of course we * decide to start using objects for them...) * * @param tstruct The struct definition */ void t_perl_generator::generate_perl_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; out << "package " << perl_namespace(tstruct->get_program()) << tstruct->get_name() << ";\n"; if (is_exception) { out << "use base qw(Thrift::TException);\n"; } // Create simple acessor methods out << "use base qw(Class::Accessor);\n"; if (members.size() > 0) { out << perl_namespace(tstruct->get_program()) << tstruct->get_name() << "->mk_accessors( qw( "; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if (!t->is_xception()) { out << (*m_iter)->get_name() << " "; } } out << ") );\n"; } out << endl; // new() indent_up(); out << "sub new {" << endl << indent() << "my $classname = shift;" << endl << indent() << "my $self = {};" << endl << indent() << "my $vals = shift || {};" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { string dval = "undef"; t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr && !(t->is_struct() || t->is_xception())) { dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value()); } out << indent() << "$self->{" << (*m_iter)->get_name() << "} = " << dval << ";" << endl; } // Generate constructor from array if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr && (t->is_struct() || t->is_xception())) { indent(out) << "$self->{" << (*m_iter)->get_name() << "} = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl; } } out << indent() << "if (UNIVERSAL::isa($vals,'HASH')) {" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << indent() << "if (defined $vals->{" << (*m_iter)->get_name() << "}) {" << endl << indent() << " $self->{" << (*m_iter)->get_name() << "} = $vals->{" << (*m_iter)->get_name() << "};" << endl << indent() << "}" << endl; } indent_down(); out << indent() << "}" << endl; } out << indent() << "return bless ($self, $classname);" << endl; indent_down(); out << "}\n\n"; out << "sub getName {" << endl << indent() << " return '" << tstruct->get_name() << "';" << endl << indent() << "}" << endl << endl; generate_perl_struct_reader(out, tstruct); generate_perl_struct_writer(out, tstruct); } /** * Generates the read() method for a struct */ void t_perl_generator::generate_perl_struct_reader(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; out << "sub read {" << endl; indent_up(); out << indent() << "my ($self, $input) = @_;" << endl << indent() << "my $xfer = 0;" << endl << indent() << "my $fname;" << endl << indent() << "my $ftype = 0;" << endl << indent() << "my $fid = 0;" << endl; indent(out) << "$xfer += $input->readStructBegin(\\$fname);" << endl; // Loop over reading in fields indent(out) << "while (1)" << endl; scope_up(out); indent(out) << "$xfer += $input->readFieldBegin(\\$fname, \\$ftype, \\$fid);" << endl; // Check for field STOP marker and break indent(out) << "if ($ftype == Thrift::TType::STOP) {" << endl; indent_up(); indent(out) << "last;" << endl; indent_down(); indent(out) << "}" << endl; // Switch statement on the field we are reading indent(out) << "SWITCH: for($fid)" << endl; scope_up(out); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "/^" << (*f_iter)->get_key() << "$/ && do{"; indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); generate_deserialize_field(out, *f_iter, "self->"); indent_down(); indent(out) << "} else {" << endl; indent(out) << " $xfer += $input->skip($ftype);" << endl; out << indent() << "}" << endl << indent() << "last; };" << endl; } // In the default case we skip the field indent(out) << " $xfer += $input->skip($ftype);" << endl; scope_down(out); indent(out) << "$xfer += $input->readFieldEnd();" << endl; scope_down(out); indent(out) << "$xfer += $input->readStructEnd();" << endl; indent(out) << "return $xfer;" << endl; indent_down(); out << indent() << "}" << endl << endl; } /** * Generates the write() method for a struct */ void t_perl_generator::generate_perl_struct_writer(ostream& out, t_struct* tstruct) { string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; out << "sub write {" << endl; indent_up(); indent(out) << "my ($self, $output) = @_;" << endl; indent(out) << "my $xfer = 0;" << endl; indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { out << indent() << "if (defined $self->{" << (*f_iter)->get_name() << "}) {" << endl; indent_up(); indent(out) << "$xfer += $output->writeFieldBegin(" << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ");" << endl; // Write field contents generate_serialize_field(out, *f_iter, "self->"); indent(out) << "$xfer += $output->writeFieldEnd();" << endl; indent_down(); indent(out) << "}" << endl; } out << indent() << "$xfer += $output->writeFieldStop();" << endl << indent() << "$xfer += $output->writeStructEnd();" << endl; out << indent() << "return $xfer;" << endl; indent_down(); out << indent() << "}" << endl << endl; } /** * Generates use clauses for included entities * * @param os The output stream * @param done A flag reference to debounce the action * @param type The type being processed * @param selfish Flag to indicate if the current namespace types should be "use"d as well. */ void t_perl_generator::generate_use_includes(std::ostream& os, bool& done, t_type *type, bool selfish) { t_program *current = type->get_program(); if (current && !done) { std::vector& currInc = current->get_includes(); std::vector::size_type numInc = currInc.size(); if (selfish) { os << "use " << perl_namespace(current) << "Types;" << endl; } for (std::vector::size_type i = 0; i < numInc; ++i) { t_program* incProgram = currInc.at(i); os << "use " << perl_namespace(incProgram) << "Types;" << endl; } os << endl; done = true; } } /** * Generates a thrift service. * * @param tservice The service definition */ void t_perl_generator::generate_service(t_service* tservice) { string f_service_name = get_namespace_out_dir() + service_name_ + ".pm"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << perl_includes(); bool done = false; generate_use_includes(f_service_, done, tservice, true); t_service* extends_s = tservice->get_extends(); if (extends_s != nullptr) { f_service_ << "use " << perl_namespace(extends_s->get_program()) << extends_s->get_name() << ";" << endl; } f_service_ << endl; // Generate the three main parts of the service (well, two for now in PERL) generate_service_helpers(tservice); generate_service_interface(tservice); generate_service_rest(tservice); generate_service_client(tservice); generate_service_processor(tservice); // Close service file f_service_ << "1;" << endl; f_service_.close(); } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_perl_generator::generate_service_processor(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_processor = ""; t_service* extends_s = tservice->get_extends(); if (extends_s != nullptr) { extends = perl_namespace(extends_s->get_program()) + extends_s->get_name(); extends_processor = "use base qw(" + extends + "Processor);"; } indent_up(); // Generate the header portion f_service_ << "package " << perl_namespace(program_) << service_name_ << "Processor;" << endl << endl << "use strict;" << endl << extends_processor << endl << endl; if (extends.empty()) { f_service_ << "sub new {" << endl; indent_up(); f_service_ << indent() << "my ($classname, $handler) = @_;" << endl << indent() << "my $self = {};" << endl; f_service_ << indent() << "$self->{handler} = $handler;" << endl; f_service_ << indent() << "return bless ($self, $classname);" << endl; indent_down(); f_service_ << "}" << endl << endl; } // Generate the server implementation f_service_ << "sub process {" << endl; indent_up(); f_service_ << indent() << "my ($self, $input, $output) = @_;" << endl; f_service_ << indent() << "my $rseqid = 0;" << endl << indent() << "my $fname = undef;" << endl << indent() << "my $mtype = 0;" << endl << endl; f_service_ << indent() << "$input->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl; // HOT: check for method implementation f_service_ << indent() << "my $methodname = 'process_'.$fname;" << endl << indent() << "if (!$self->can($methodname)) {" << endl; indent_up(); f_service_ << indent() << "$input->skip(Thrift::TType::STRUCT);" << endl << indent() << "$input->readMessageEnd();" << endl << indent() << "my $x = Thrift::TApplicationException->new('Function '.$fname.' not implemented.', " "Thrift::TApplicationException::UNKNOWN_METHOD);" << endl << indent() << "$output->writeMessageBegin($fname, Thrift::TMessageType::EXCEPTION, $rseqid);" << endl << indent() << "$x->write($output);" << endl << indent() << "$output->writeMessageEnd();" << endl << indent() << "$output->getTransport()->flush();" << endl << indent() << "return;" << endl; indent_down(); f_service_ << indent() << "}" << endl << indent() << "$self->$methodname($rseqid, $input, $output);" << endl << indent() << "return 1;" << endl; indent_down(); f_service_ << "}" << endl << endl; // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_perl_generator::generate_process_function(t_service* tservice, t_function* tfunction) { // Open function f_service_ << "sub process_" << tfunction->get_name() << " {" << endl; indent_up(); f_service_ << indent() << "my ($self, $seqid, $input, $output) = @_;" << endl; string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args"; string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result"; f_service_ << indent() << "my $args = " << argsname << "->new();" << endl << indent() << "$args->read($input);" << endl; f_service_ << indent() << "$input->readMessageEnd();" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Declare result for non oneway function if (!tfunction->is_oneway()) { f_service_ << indent() << "my $result = " << resultname << "->new();" << endl; } // Try block for a function with exceptions if (xceptions.size() > 0) { f_service_ << indent() << "eval {" << endl; indent_up(); } // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_service_ << "$result->{success} = "; } f_service_ << "$self->{handler}->" << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "$args->" << (*f_iter)->get_name(); } f_service_ << ");" << endl; if (!tfunction->is_oneway() && xceptions.size() > 0) { indent_down(); for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << "}; if( UNIVERSAL::isa($@,'" << perl_namespace((*x_iter)->get_type()->get_program()) << (*x_iter)->get_type()->get_name() << "') ){ " << endl; indent_up(); f_service_ << indent() << "$result->{" << (*x_iter)->get_name() << "} = $@;" << endl; f_service_ << indent() << "$@ = undef;" << endl; indent_down(); f_service_ << indent(); } f_service_ << "}" << endl; // catch-all for unexpected exceptions (THRIFT-3191) f_service_ << indent() << "if ($@) {" << endl; indent_up(); f_service_ << indent() << "$@ =~ s/^\\s+|\\s+$//g;" << endl << indent() << "my $err = Thrift::TApplicationException->new(\"Unexpected Exception: \" . $@, Thrift::TApplicationException::INTERNAL_ERROR);" << endl << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', Thrift::TMessageType::EXCEPTION, $seqid);" << endl << indent() << "$err->write($output);" << endl << indent() << "$output->writeMessageEnd();" << endl << indent() << "$output->getTransport()->flush();" << endl << indent() << "$@ = undef;" << endl << indent() << "return;" << endl; indent_down(); f_service_ << indent() << "}" << endl; } // Shortcut out here for oneway functions if (tfunction->is_oneway()) { f_service_ << indent() << "return;" << endl; indent_down(); f_service_ << "}" << endl; return; } // Serialize the reply f_service_ << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', Thrift::TMessageType::REPLY, $seqid);" << endl << indent() << "$result->write($output);" << endl << indent() << "$output->writeMessageEnd();" << endl << indent() << "$output->getTransport()->flush();" << endl; // Close function indent_down(); f_service_ << "}" << endl << endl; } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_perl_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; f_service_ << "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); string name = ts->get_name(); ts->set_name(service_name_ + "_" + name); generate_perl_struct_definition(f_service_, ts, false); generate_perl_function_helpers(*f_iter); ts->set_name(name); } } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_perl_generator::generate_perl_function_helpers(t_function* tfunction) { t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_perl_struct_definition(f_service_, &result, false); } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_perl_generator::generate_service_interface(t_service* tservice) { string extends_if = ""; t_service* extends_s = tservice->get_extends(); if (extends_s != nullptr) { extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "If);"; } f_service_ << "package " << perl_namespace(program_) << service_name_ << "If;" << endl << endl << "use strict;" << endl << extends_if << endl << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << "sub " << function_signature(*f_iter) << endl << " die 'implement interface';\n}" << endl << endl; } indent_down(); } /** * Generates a REST interface */ void t_perl_generator::generate_service_rest(t_service* tservice) { string extends = ""; string extends_if = ""; t_service* extends_s = tservice->get_extends(); if (extends_s != nullptr) { extends = extends_s->get_name(); extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "Rest);"; } f_service_ << "package " << perl_namespace(program_) << service_name_ << "Rest;" << endl << endl << "use strict;" << endl << extends_if << endl << endl; if (extends.empty()) { f_service_ << "sub new {" << endl; indent_up(); f_service_ << indent() << "my ($classname, $impl) = @_;" << endl << indent() << "my $self ={ impl => $impl };" << endl << endl << indent() << "return bless($self,$classname);" << endl; indent_down(); f_service_ << "}" << endl << endl; } vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << "sub " << (*f_iter)->get_name() << "{" << endl; indent_up(); f_service_ << indent() << "my ($self, $request) = @_;" << endl << endl; const vector& args = (*f_iter)->get_arglist()->get_members(); vector::const_iterator a_iter; for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { t_type* atype = get_true_type((*a_iter)->get_type()); string req = "$request->{'" + (*a_iter)->get_name() + "'}"; f_service_ << indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req << " : undef;" << endl; if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) { f_service_ << indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $" << (*a_iter)->get_name() << ");" << endl << indent() << "$" << (*a_iter)->get_name() << " = \\@" << (*a_iter)->get_name() << endl; } } f_service_ << indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl; indent_down(); indent(f_service_) << "}" << endl << endl; } } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_perl_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = ""; t_service* extends_s = tservice->get_extends(); if (extends_s != nullptr) { extends = perl_namespace(extends_s->get_program()) + extends_s->get_name(); extends_client = "use base qw(" + extends + "Client);"; } f_service_ << "package " << perl_namespace(program_) << service_name_ << "Client;" << endl << endl << extends_client << endl << "use base qw(" << perl_namespace(program_) << service_name_ << "If);" << endl; // Constructor function f_service_ << "sub new {" << endl; indent_up(); f_service_ << indent() << "my ($classname, $input, $output) = @_;" << endl << indent() << "my $self = {};" << endl; if (!extends.empty()) { f_service_ << indent() << "$self = $classname->SUPER::new($input, $output);" << endl; } else { f_service_ << indent() << "$self->{input} = $input;" << endl << indent() << "$self->{output} = defined $output ? $output : $input;" << endl << indent() << "$self->{seqid} = 0;" << endl; } f_service_ << indent() << "return bless($self,$classname);" << endl; indent_down(); f_service_ << "}" << endl << endl; // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = (*f_iter)->get_name(); // Open function f_service_ << "sub " << function_signature(*f_iter) << endl; indent_up(); indent(f_service_) << indent() << "$self->send_" << funname << "("; bool first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "$" << (*fld_iter)->get_name(); } f_service_ << ");" << endl; if (!(*f_iter)->is_oneway()) { f_service_ << indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << "return "; } f_service_ << "$self->recv_" << funname << "();" << endl; } indent_down(); f_service_ << "}" << endl << endl; f_service_ << "sub send_" << function_signature(*f_iter) << endl; indent_up(); std::string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args"; // Serialize the request header f_service_ << indent() << "$self->{output}->writeMessageBegin('" << (*f_iter)->get_name() << "', " << ((*f_iter)->is_oneway() ? "Thrift::TMessageType::ONEWAY" : "Thrift::TMessageType::CALL") << ", $self->{seqid});" << endl; f_service_ << indent() << "my $args = " << argsname << "->new();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << indent() << "$args->{" << (*fld_iter)->get_name() << "} = $" << (*fld_iter)->get_name() << ";" << endl; } // Write to the stream f_service_ << indent() << "$args->write($self->{output});" << endl << indent() << "$self->{output}->writeMessageEnd();" << endl << indent() << "$self->{output}->getTransport()->flush();" << endl; indent_down(); f_service_ << "}" << endl; if (!(*f_iter)->is_oneway()) { std::string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result"; t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); // Open function f_service_ << endl << "sub " << function_signature(&recv_function) << endl; indent_up(); f_service_ << indent() << "my $rseqid = 0;" << endl << indent() << "my $fname;" << endl << indent() << "my $mtype = 0;" << endl << endl; f_service_ << indent() << "$self->{input}->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl << indent() << "if ($mtype == Thrift::TMessageType::EXCEPTION) {" << endl << indent() << " my $x = Thrift::TApplicationException->new();" << endl << indent() << " $x->read($self->{input});" << endl << indent() << " $self->{input}->readMessageEnd();" << endl << indent() << " die $x;" << endl << indent() << "}" << endl; f_service_ << indent() << "my $result = " << resultname << "->new();" << endl << indent() << "$result->read($self->{input});" << endl; f_service_ << indent() << "$self->{input}->readMessageEnd();" << endl << endl; // Careful, only return result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << "if (defined $result->{success} ) {" << endl << indent() << " return $result->{success};" << endl << indent() << "}" << endl; } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << indent() << "if (defined $result->{" << (*x_iter)->get_name() << "}) {" << endl << indent() << " die $result->{" << (*x_iter)->get_name() << "};" << endl << indent() << "}" << endl; } // Careful, only return _result if not a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "return;" << endl; } else { f_service_ << indent() << "die \"" << (*f_iter)->get_name() << " failed: unknown result\";" << endl; } // Close function indent_down(); f_service_ << "}" << endl; } } } /** * Deserializes a field of any type. */ void t_perl_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, bool inclass) { (void)inclass; t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = tfield->get_name(); // Hack for when prefix is defined (always a hash ref) if (!prefix.empty()) { name = prefix + "{" + tfield->get_name() + "}"; } if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << "$xfer += $input->"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << "readString(\\$" << name << ");"; break; case t_base_type::TYPE_BOOL: out << "readBool(\\$" << name << ");"; break; case t_base_type::TYPE_I8: out << "readByte(\\$" << name << ");"; break; case t_base_type::TYPE_I16: out << "readI16(\\$" << name << ");"; break; case t_base_type::TYPE_I32: out << "readI32(\\$" << name << ");"; break; case t_base_type::TYPE_I64: out << "readI64(\\$" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble(\\$" << name << ");"; break; default: throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "readI32(\\$" << name << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type->get_name().c_str()); } } /** * Generates an unserializer for a variable. This makes two key assumptions, * first that there is a const char* variable named data that points to the * buffer for deserialization, and that there is a variable protocol which * is a reference to a TProtocol serialization object. */ void t_perl_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { out << indent() << "$" << prefix << " = " << perl_namespace(tstruct->get_program()) << tstruct->get_name() << "->new();" << endl << indent() << "$xfer += $" << prefix << "->read($input);" << endl; } void t_perl_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); string size = tmp("_size"); string ktype = tmp("_ktype"); string vtype = tmp("_vtype"); string etype = tmp("_etype"); t_field fsize(g_type_i32, size); t_field fktype(g_type_i8, ktype); t_field fvtype(g_type_i8, vtype); t_field fetype(g_type_i8, etype); out << indent() << "my $" << size << " = 0;" << endl; // Declare variables, read header if (ttype->is_map()) { out << indent() << "$" << prefix << " = {};" << endl << indent() << "my $" << ktype << " = 0;" << endl << indent() << "my $" << vtype << " = 0;" << endl; out << indent() << "$xfer += $input->readMapBegin(" << "\\$" << ktype << ", \\$" << vtype << ", \\$" << size << ");" << endl; } else if (ttype->is_set()) { out << indent() << "$" << prefix << " = {};" << endl << indent() << "my $" << etype << " = 0;" << endl << indent() << "$xfer += $input->readSetBegin(" << "\\$" << etype << ", \\$" << size << ");" << endl; } else if (ttype->is_list()) { out << indent() << "$" << prefix << " = [];" << endl << indent() << "my $" << etype << " = 0;" << endl << indent() << "$xfer += $input->readListBegin(" << "\\$" << etype << ", \\$" << size << ");" << endl; } // For loop iterates over elements string i = tmp("_i"); indent(out) << "for (my $" << i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl; scope_up(out); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } scope_down(out); // Read container end if (ttype->is_map()) { indent(out) << "$xfer += $input->readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "$xfer += $input->readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "$xfer += $input->readListEnd();" << endl; } scope_down(out); } /** * Generates code to deserialize a map */ void t_perl_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("key"); string val = tmp("val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); indent(out) << declare_field(&fkey, true, true) << endl; indent(out) << declare_field(&fval, true, true) << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); indent(out) << "$" << prefix << "->{$" << key << "} = $" << val << ";" << endl; } void t_perl_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << "my $" << elem << " = undef;" << endl; generate_deserialize_field(out, &felem); indent(out) << "$" << prefix << "->{$" << elem << "} = 1;" << endl; } void t_perl_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << "my $" << elem << " = undef;" << endl; generate_deserialize_field(out, &felem); indent(out) << "push(@{$" << prefix << "},$" << elem << ");" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_perl_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + "{" + tfield->get_name() + "}"); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + "{" + tfield->get_name() + "}"); } else if (type->is_base_type() || type->is_enum()) { string name = tfield->get_name(); // Hack for when prefix is defined (always a hash ref) if (!prefix.empty()) name = prefix + "{" + tfield->get_name() + "}"; indent(out) << "$xfer += $output->"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << "writeString($" << name << ");"; break; case t_base_type::TYPE_BOOL: out << "writeBool($" << name << ");"; break; case t_base_type::TYPE_I8: out << "writeByte($" << name << ");"; break; case t_base_type::TYPE_I16: out << "writeI16($" << name << ");"; break; case t_base_type::TYPE_I32: out << "writeI32($" << name << ");"; break; case t_base_type::TYPE_I64: out << "writeI64($" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble($" << name << ");"; break; default: throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32($" << name << ");"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type->get_name().c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_perl_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; indent(out) << "$xfer += $" << prefix << "->write($output);" << endl; } /** * Writes out a container */ void t_perl_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { scope_up(out); if (ttype->is_map()) { indent(out) << "$xfer += $output->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "scalar(keys %{$" << prefix << "}));" << endl; } else if (ttype->is_set()) { indent(out) << "$xfer += $output->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << "scalar(@{$" << prefix << "}));" << endl; } else if (ttype->is_list()) { indent(out) << "$xfer += $output->writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << "scalar(@{$" << prefix << "}));" << endl; } scope_up(out); if (ttype->is_map()) { string kiter = tmp("kiter"); string viter = tmp("viter"); indent(out) << "while( my ($" << kiter << ",$" << viter << ") = each %{$" << prefix << "}) " << endl; scope_up(out); generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); scope_down(out); } else if (ttype->is_set()) { string iter = tmp("iter"); indent(out) << "foreach my $" << iter << " (@{$" << prefix << "})" << endl; scope_up(out); generate_serialize_set_element(out, (t_set*)ttype, iter); scope_down(out); } else if (ttype->is_list()) { string iter = tmp("iter"); indent(out) << "foreach my $" << iter << " (@{$" << prefix << "}) " << endl; scope_up(out); generate_serialize_list_element(out, (t_list*)ttype, iter); scope_down(out); } scope_down(out); if (ttype->is_map()) { indent(out) << "$xfer += $output->writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "$xfer += $output->writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "$xfer += $output->writeListEnd();" << endl; } scope_down(out); } /** * Serializes the members of a map. * */ void t_perl_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter) { t_field kfield(tmap->get_key_type(), kiter); generate_serialize_field(out, &kfield); t_field vfield(tmap->get_val_type(), viter); generate_serialize_field(out, &vfield); } /** * Serializes the members of a set. */ void t_perl_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield); } /** * Serializes the members of a list. */ void t_perl_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield); } /** * Declares a field, which may include initialization as necessary. * * @param ttype The type */ string t_perl_generator::declare_field(t_field* tfield, bool init, bool obj) { string result = "my $" + tfield->get_name(); if (init) { t_type* type = get_true_type(tfield->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: break; case t_base_type::TYPE_STRING: result += " = ''"; break; case t_base_type::TYPE_BOOL: result += " = 0"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = 0.0"; break; default: throw "compiler error: no PERL initializer for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { result += " = 0"; } else if (type->is_container()) { result += " = []"; } else if (type->is_struct() || type->is_xception()) { if (obj) { result += " = " + perl_namespace(type->get_program()) + type->get_name() + "->new()"; } else { result += " = undef"; } } } return result + ";"; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_perl_generator::function_signature(t_function* tfunction, string prefix) { string str; str = prefix + tfunction->get_name() + "{\n"; str += " my $self = shift;\n"; // Need to create perl function arg inputs const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { str += " my $" + (*f_iter)->get_name() + " = shift;\n"; } return str; } /** * Renders a field list */ string t_perl_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += "$" + (*f_iter)->get_name(); } return result; } /** * Converts the parse type to a C++ enum string for the given type. */ string t_perl_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "Thrift::TType::STRING"; case t_base_type::TYPE_BOOL: return "Thrift::TType::BOOL"; case t_base_type::TYPE_I8: return "Thrift::TType::BYTE"; case t_base_type::TYPE_I16: return "Thrift::TType::I16"; case t_base_type::TYPE_I32: return "Thrift::TType::I32"; case t_base_type::TYPE_I64: return "Thrift::TType::I64"; case t_base_type::TYPE_DOUBLE: return "Thrift::TType::DOUBLE"; } } else if (type->is_enum()) { return "Thrift::TType::I32"; } else if (type->is_struct() || type->is_xception()) { return "Thrift::TType::STRUCT"; } else if (type->is_map()) { return "Thrift::TType::MAP"; } else if (type->is_set()) { return "Thrift::TType::SET"; } else if (type->is_list()) { return "Thrift::TType::LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } THRIFT_REGISTER_GENERATOR(perl, "Perl", "") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_php_generator.cc000066400000000000000000003004601420101504100250310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes #define NSGLOBAL (nsglobal_.size() ? nsglobal_ : "") #define NSGLOBAL_A ("\\" + NSGLOBAL) #define NSGLOBAL_B (NSGLOBAL + "\\") #define NSGLOBAL_AB ("\\" + NSGLOBAL + "\\") /** * PHP code generator. * */ class t_php_generator : public t_oop_generator { public: t_php_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; binary_inline_ = false; rest_ = false; phps_ = false; oop_ = false; validate_ = false; json_serializable_ = false; getters_setters_ = false; nsglobal_ = ""; // by default global namespace is empty classmap_ = false; for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if (iter->first.compare("inlined") == 0) { binary_inline_ = true; } else if (iter->first.compare("rest") == 0) { rest_ = true; } else if (iter->first.compare("server") == 0) { phps_ = true; } else if (iter->first.compare("oop") == 0) { oop_ = true; } else if (iter->first.compare("validate") == 0) { validate_ = true; } else if (iter->first.compare("json") == 0) { json_serializable_ = true; } else if (iter->first.compare("nsglobal") == 0) { nsglobal_ = iter->second; } else if (iter->first.compare("classmap") == 0) { classmap_ = true; } else if (iter->first.compare("psr4") == 0) { if(classmap_){ throw "psr4 and classmap are mutually exclusive."; } else { pwarning(0, "psr4 is default option! needn't add psr4 option!\n"); } } else if (iter->first.compare("getters_setters") == 0) { getters_setters_ = true; } else { throw "unknown option php:" + iter->first; } } if (oop_ && binary_inline_) { throw "oop and inlined are mutually exclusive."; } out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php"); escape_['$'] = "\\$"; } std::string indent_str() const override { return " "; } static bool is_valid_namespace(const std::string& sub_namespace); /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_consts(vector consts) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; std::string render_const_value(t_type* type, t_const_value* value); /** * Structs! */ void generate_php_struct(t_struct* tstruct, bool is_exception); void generate_php_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false, bool is_result = false); void generate_php_struct_reader(std::ostream& out, t_struct* tstruct, bool is_result); void generate_php_struct_writer(std::ostream& out, t_struct* tstruct, bool is_result); void generate_php_function_helpers(t_service* tservice, t_function* tfunction); void generate_php_struct_required_validator(ostream& out, t_struct* tstruct, std::string method_name, bool write_mode); void generate_php_struct_read_validator(ostream& out, t_struct* tstruct); void generate_php_struct_write_validator(ostream& out, t_struct* tstruct); void generate_php_struct_json_serialize(ostream& out, t_struct* tstruct, bool is_result); bool needs_php_write_validator(t_struct* tstruct, bool is_result); bool needs_php_read_validator(t_struct* tstruct, bool is_result); int get_php_num_required_fields(const vector& fields, bool write_mode); void generate_php_type_spec(std::ostream& out, t_type* t); void generate_php_struct_spec(std::ostream& out, t_struct* tstruct); void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct); void generate_reflection_setters(ostringstream& out, string field_name, string cap_name); void generate_reflection_getters(ostringstream& out, string field_name, string cap_name); std::string get_cap_name(std::string name); /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_rest(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_processor(t_service* tservice); void generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction); void generate_service_header(t_service* tservice, std::ostream& file); void generate_program_header(std::ostream& file); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "", bool inclass = false); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); void generate_php_doc(std::ostream& out, t_doc* tdoc); void generate_php_doc(std::ostream& out, t_field* tfield); void generate_php_doc(std::ostream& out, t_function* tfunction); void generate_php_docstring_comment(std::ostream& out, string contents); /** * Helper rendering functions */ std::string php_includes(); std::string declare_field(t_field* tfield, bool init = false, bool obj = false); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string argument_list(t_struct* tstruct, bool addTypeHints = true); std::string type_to_cast(t_type* ttype); std::string type_to_enum(t_type* ttype); std::string type_to_phpdoc(t_type* ttype); bool php_is_scalar(t_type *ttype) { ttype = ttype->get_true_type(); if(ttype->is_base_type()) { return true; } else if(ttype->is_enum()) { return true; } else { return false; } } std::string php_namespace_base(const t_program* p) { std::string ns = p->get_namespace("php"); const char* delimiter = "\\"; size_t position = ns.find('.'); while (position != string::npos) { ns.replace(position, 1, delimiter); position = ns.find('.', position + 1); } return ns; } // general use namespace prefixing: \my\namespace\ or my_namespace_ string php_namespace(const t_program* p) { string ns = php_namespace_base(p); return (nsglobal_.size() ? NSGLOBAL_AB : NSGLOBAL_B) + (ns.size() ? (ns + "\\") : ""); } // return the namespace of a file: // global\ns\sub\ns or global\ns or sub\ns string php_namespace_suffix(const t_program* p) { string ns = php_namespace_base(p); return NSGLOBAL + (ns.size() && NSGLOBAL.size() ? "\\" : "") + ns; } // add a directory to already existing namespace string php_namespace_directory(string directory, bool end = true) { (void)directory; if (end) { return ";"; } else { return ""; } } // writing an autload identifier into globa;ls: my\namespace\ or my_namespace_ string php_namespace_autoload(const t_program* p) { std::string ns = php_namespace_base(p); return (nsglobal_.size() ? NSGLOBAL_B : NSGLOBAL) + (ns.size() ? (ns + "\\") : ""); } // declaring a type: typename or my_namespace_typename string php_namespace_declaration(t_type* t) { return t->get_name(); } std::string php_path(t_program* p) { std::string ns = p->get_namespace("php.path"); if (ns.empty()) { return p->get_name(); } // Transform the java-style namespace into a path. for (char & n : ns) { if (n == '.') { n = '/'; } } return ns + '/'; } /** * Transform class_method into ClassMethod * * @param str * @return stirng */ string classify(string str) { string classe = ""; vector x = split(str, '_'); for (const auto & i : x) { classe = classe + capitalize(i); } return classe; } /** * Split method * @param s * @param delim * @param elems * @return */ vector& split(const string& s, char delim, vector& elems) { stringstream ss(s); string item; while (getline(ss, item, delim)) { elems.push_back(item); } return elems; } vector split(const string& s, char delim) { vector elems; return split(s, delim, elems); } /** * Capitalize method * @param str * @return */ string capitalize(string str) { string::iterator it(str.begin()); if (it != str.end()) str[0] = toupper((unsigned char)str[0]); // while(++it != str.end()) // { // *it = tolower((unsigned char)*it); // } return str; } private: /** * File streams */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_service_; std::string package_dir_; /** * Generate protocol-independent template? Or Binary inline code? */ bool binary_inline_; /** * Generate a REST handler class */ bool rest_; /** * Generate stubs for a PHP server */ bool phps_; /** * Whether to use OOP base class TBase */ bool oop_; /** * Whether to generate old-style PHP file to use classmap autoloading */ bool classmap_; /** * Whether to generate validator code */ bool validate_; /** * Whether to generate JsonSerializable classes */ bool json_serializable_; /** * Global namespace for PHP 5.3 */ std::string nsglobal_; /** * Whether to generate getters and setters */ bool getters_setters_; }; bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) { return sub_namespace == "path"; } /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_php_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); // Create Real directory Namespaces vector NSx = split(php_namespace_suffix(get_program()), '\\'); package_dir_ = get_out_dir(); for (const auto & i : NSx) { package_dir_ = package_dir_ + "/" + i + "/"; MKDIR(package_dir_.c_str()); } // Prepare output file for all the types in classmap mode if (classmap_) { // Make output file string f_types_name = package_dir_ + "Types.php"; f_types_.open(f_types_name.c_str()); generate_program_header(f_types_); } } /** * Prints standard php includes */ string t_php_generator::php_includes() { string includes = "use Thrift\\Base\\TBase;\n" "use Thrift\\Type\\TType;\n" "use Thrift\\Type\\TMessageType;\n" "use Thrift\\Exception\\TException;\n" "use Thrift\\Exception\\TProtocolException;\n" "use Thrift\\Protocol\\TProtocol;\n" "use Thrift\\Protocol\\TBinaryProtocolAccelerated;\n" "use Thrift\\Exception\\TApplicationException;\n"; if (json_serializable_) { includes += "use JsonSerializable;\n" "use stdClass;\n"; } return includes; } /** * Close up (or down) some filez. */ void t_php_generator::close_generator() { if (classmap_) { // Close types file f_types_.close(); } } /** * Generates a typedef. This is not done in PHP, types are all implicit. * * @param ttypedef The type definition */ void t_php_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Generates service header contains namespace suffix and includes inside file specified */ void t_php_generator::generate_service_header(t_service* tservice, std::ostream& file) { file << "get_program()).empty()) { file << "namespace " << php_namespace_suffix(tservice->get_program()) << ";" << endl << endl; } file << autogen_comment() << php_includes(); file << endl; } /** * Generates program header contains namespace suffix and includes inside file specified */ void t_php_generator::generate_program_header(std::ostream& file) { file << "get_name() + ".php"; f_enum.open(f_enum_name.c_str()); generate_program_header(f_enum); } vector constants = tenum->get_constants(); vector::iterator c_iter; // We're also doing it this way to see how it performs. It's more legible // code but you can't do things like an 'extract' on it, which is a bit of // a downer. generate_php_doc(f_enum, tenum); f_enum << "final class " << tenum->get_name() << endl << "{" << endl; indent_up(); for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); generate_php_doc(f_enum, *c_iter); indent(f_enum) << "const " << (*c_iter)->get_name() << " = " << value << ";" << endl << endl; } indent(f_enum) << "static public $__names = array(" << endl; indent_up(); for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); indent(f_enum) << value << " => '" << (*c_iter)->get_name() << "'," << endl; } indent_down(); indent(f_enum) << ");" << endl; indent_down(); f_enum << "}" << endl << endl; if (!classmap_) { f_enum.close(); } } /** * Generate constant class * * Override the one from t_generator */ void t_php_generator::generate_consts(vector consts) { vector::iterator c_iter; // Create class only if needed if (consts.size() > 0) { ofstream_with_content_based_conditional_update& f_consts = f_types_; if (!classmap_) { string f_consts_name = package_dir_ + "Constant.php"; f_consts.open(f_consts_name.c_str()); generate_program_header(f_consts); } f_consts << "final class Constant extends \\Thrift\\Type\\TConstant"<< endl << "{" << endl; indent_up(); // Create static property for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { string name = (*c_iter)->get_name(); indent(f_consts) << "static protected $" << name << ";" << endl; } // Create init function for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { string name = (*c_iter)->get_name(); f_consts << endl; f_consts << indent() << "protected static function init_" << name << "()" <get_type(), (*c_iter)->get_value()); f_consts << ";" << endl; indent_down(); indent(f_consts) << "}" << endl; } indent_down(); f_consts << "}" << endl; if (!classmap_) { f_consts.close(); } } } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_php_generator::render_const_value(t_type* type, t_const_value* value) { std::ostringstream out; type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { indent(out) << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << "new " << php_namespace(type->get_program()) << type->get_name() << "(array(" << endl; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } out << indent(); out << render_const_value(g_type_string, v_iter->first); out << " => "; out << render_const_value(field_type, v_iter->second); out << "," << endl; } indent_down(); indent(out) << "))"; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); out << "array(" << endl; indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent(); out << render_const_value(ktype, v_iter->first); out << " => "; out << render_const_value(vtype, v_iter->second); out << "," << endl; } indent_down(); indent(out) << ")"; } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } out << "array(" << endl; indent_up(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent(); out << render_const_value(etype, *v_iter); if (type->is_set()) { out << " => true"; } out << "," << endl; } indent_down(); indent(out) << ")"; } return out.str(); } /** * Make a struct */ void t_php_generator::generate_struct(t_struct* tstruct) { generate_php_struct(tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_php_generator::generate_xception(t_struct* txception) { generate_php_struct(txception, true); } /** * Structs can be normal or exceptions. */ void t_php_generator::generate_php_struct(t_struct* tstruct, bool is_exception) { ofstream_with_content_based_conditional_update& f_struct = f_types_; if (!classmap_) { string f_struct_name = package_dir_ + tstruct->get_name() + ".php"; f_struct.open(f_struct_name.c_str()); generate_program_header(f_struct); } generate_php_struct_definition(f_struct, tstruct, is_exception); if (!classmap_) { f_struct.close(); } } void t_php_generator::generate_php_type_spec(ostream& out, t_type* t) { t = get_true_type(t); indent(out) << "'type' => " << type_to_enum(t) << "," << endl; if (t->is_base_type()) { // Noop, type is all we need } else if (t->is_struct() || t->is_xception() || t->is_enum()) { indent(out) << "'class' => '" << php_namespace(t->get_program()) << t->get_name() << "'," << endl; } else if (t->is_map()) { t_type* ktype = get_true_type(((t_map*)t)->get_key_type()); t_type* vtype = get_true_type(((t_map*)t)->get_val_type()); indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl; indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl; indent(out) << "'key' => array(" << endl; indent_up(); generate_php_type_spec(out, ktype); indent_down(); indent(out) << ")," << endl; indent(out) << "'val' => array(" << endl; indent_up(); generate_php_type_spec(out, vtype); indent(out) << ")," << endl; indent_down(); } else if (t->is_list() || t->is_set()) { t_type* etype; if (t->is_list()) { etype = get_true_type(((t_list*)t)->get_elem_type()); } else { etype = get_true_type(((t_set*)t)->get_elem_type()); } indent(out) << "'etype' => " << type_to_enum(etype) << "," << endl; indent(out) << "'elem' => array(" << endl; indent_up(); generate_php_type_spec(out, etype); indent(out) << ")," << endl; indent_down(); } else { throw "compiler error: no type for php struct spec field"; } } /** * Generates the struct specification structure, which fully qualifies enough * type information to generalize serialization routines. */ void t_php_generator::generate_php_struct_spec(ostream& out, t_struct* tstruct) { indent(out) << "static public $_TSPEC = array(" << endl; indent_up(); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); indent(out) << (*m_iter)->get_key() << " => array(" << endl; indent_up(); out << indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl; out << indent() << "'isRequired' => " << ((*m_iter)->get_req() == t_field::T_REQUIRED ? "true" : "false") << "," << endl; generate_php_type_spec(out, t); indent_down(); indent(out) << ")," << endl; } indent_down(); indent(out) << ");" << endl << endl; } /** * Generates necessary accessors and mutators for the fields */ void t_php_generator::generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct) { std::ostringstream getter_stream; std::ostringstream setter_stream; // build up the bodies of both the getter and setter at once const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = *f_iter; std::string field_name = field->get_name(); std::string cap_name = get_cap_name(field_name); indent_up(); generate_reflection_setters(setter_stream, field_name, cap_name); generate_reflection_getters(getter_stream, field_name, cap_name); indent_down(); } indent(out) << endl; out << getter_stream.str(); out << setter_stream.str(); indent(out) << endl; } /** * Generates a getter for the generated private fields */ void t_php_generator::generate_reflection_getters(ostringstream& out, string field_name, string cap_name) { out << indent() << "public function " << "get" << cap_name << "()" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return $this->" << field_name << ";" << endl; indent_down(); out << indent() << "}" << endl; out << endl; } /** * Generates a setter for the generated private fields */ void t_php_generator::generate_reflection_setters(ostringstream& out, string field_name, string cap_name) { out << indent() << "public function set" << cap_name << "(" << "$" << field_name << ")" << endl << indent() << "{" << endl; indent_up(); out << indent() << "$this->" << field_name << " = $" << field_name << ";" << endl; indent_down(); out << indent() << "}" << endl; out << endl; } /** * Gets the first-letter capitalized name for the field * * @param std::string name of the field */ std::string t_php_generator::get_cap_name(std::string name) { name[0] = toupper(name[0]); return name; } /** * Generates a struct definition for a thrift data type. This is nothing in PHP * where the objects are all just associative arrays (unless of course we * decide to start using objects for them...) * * @param tstruct The struct definition */ void t_php_generator::generate_php_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool is_result) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; generate_php_doc(out, tstruct); out << "class " << php_namespace_declaration(tstruct); if (is_exception) { out << " extends " << "TException"; } else if (oop_) { out << " extends " << "TBase"; } if (json_serializable_) { out << " implements JsonSerializable"; } out << endl << "{" << endl; indent_up(); out << indent() << "static public $isValidate = " << (validate_ ? "true" : "false") << ";" << endl << endl; generate_php_struct_spec(out, tstruct); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { string dval = "null"; t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr && !(t->is_struct() || t->is_xception())) { dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value()); } generate_php_doc(out, *m_iter); string access = (getters_setters_) ? "private" : "public"; indent(out) << access << " $" << (*m_iter)->get_name() << " = " << dval << ";" << endl; } out << endl; // Generate constructor from array string param = (members.size() > 0) ? "$vals = null" : ""; out << indent() << "public function __construct(" << param << ")"<< endl << indent() << "{" << endl; indent_up(); if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_type* t = get_true_type((*m_iter)->get_type()); if ((*m_iter)->get_value() != nullptr && (t->is_struct() || t->is_xception())) { indent(out) << "$this->" << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl; } } out << indent() << "if (is_array($vals)) {" << endl; indent_up(); if (oop_) { out << indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl; } else { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl; indent_up(); out << indent() << "$this->" << (*m_iter)->get_name() << " = $vals['" << (*m_iter)->get_name() << "'];" << endl; indent_down(); out << indent() << "}" << endl; } } indent_down(); out << indent() << "}" << endl; } scope_down(out); out << endl; out << indent() << "public function getName()" << endl << indent() << "{" << endl; indent_up(); out << indent() << "return '" << tstruct->get_name() << "';" << endl; indent_down(); out << indent() << "}" << endl << endl; out << endl; if (getters_setters_) { generate_generic_field_getters_setters(out, tstruct); } generate_php_struct_reader(out, tstruct, is_result); out << endl; generate_php_struct_writer(out, tstruct, is_result); if (needs_php_read_validator(tstruct, is_result)) { out << endl; generate_php_struct_read_validator(out, tstruct); } if (needs_php_write_validator(tstruct, is_result)) { out << endl; generate_php_struct_write_validator(out, tstruct); } if (json_serializable_) { out << endl; generate_php_struct_json_serialize(out, tstruct, is_result); } indent_down(); out << indent() << "}" << endl; } /** * Generates the read() method for a struct */ void t_php_generator::generate_php_struct_reader(ostream& out, t_struct* tstruct, bool is_result) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; indent(out) << "public function read($input)" << endl; scope_up(out); if (oop_) { if (needs_php_read_validator(tstruct, is_result)) { indent(out) << "$tmp = $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl; indent(out) << "$this->_validateForRead();" << endl; indent(out) << "return $tmp;" << endl; } else { indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl; } scope_down(out); out << endl; return; } out << indent() << "$xfer = 0;" << endl << indent() << "$fname = null;" << endl << indent() << "$ftype = 0;" << endl << indent() << "$fid = 0;" << endl; // Declare stack tmp variables if (!binary_inline_) { indent(out) << "$xfer += $input->readStructBegin($fname);" << endl; } // Loop over reading in fields indent(out) << "while (true) {" << endl; indent_up(); // Read beginning field marker if (binary_inline_) { t_field fftype(g_type_i8, "ftype"); t_field ffid(g_type_i16, "fid"); generate_deserialize_field(out, &fftype); out << indent() << "if ($ftype == " << "TType::STOP) {" << endl << indent() << " break;" << endl << indent() << "}" << endl; generate_deserialize_field(out, &ffid); } else { indent(out) << "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl; // Check for field STOP marker and break indent(out) << "if ($ftype == " << "TType::STOP) {" << endl; indent_up(); indent(out) << "break;" << endl; indent_down(); indent(out) << "}" << endl; } // Switch statement on the field we are reading indent(out) << "switch ($fid) {" << endl; indent_up(); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case " << (*f_iter)->get_key() << ":" << endl; indent_up(); indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; indent_up(); generate_deserialize_field(out, *f_iter, "this->"); indent_down(); out << indent() << "} else {" << endl; indent_up(); if (binary_inline_) { indent(out) << "$xfer += TProtocol::skipBinary($input, $ftype);" << endl; } else { indent(out) << "$xfer += $input->skip($ftype);" << endl; } indent_down(); out << indent() << "}" << endl << indent() << "break;" << endl; indent_down(); } // In the default case we skip the field indent(out) << "default:" << endl; indent_up(); if (binary_inline_) { indent(out) << "$xfer += " << "TProtocol::skipBinary($input, $ftype);" << endl; } else { indent(out) << "$xfer += $input->skip($ftype);" << endl; } indent(out) << "break;" << endl; indent_down(); scope_down(out); if (!binary_inline_) { // Read field end marker indent(out) << "$xfer += $input->readFieldEnd();" << endl; } scope_down(out); if (!binary_inline_) { indent(out) << "$xfer += $input->readStructEnd();" << endl; } if (needs_php_read_validator(tstruct, is_result)) { indent(out) << "$this->_validateForRead();" << endl; } indent(out) << "return $xfer;" << endl; indent_down(); out << indent() << "}" << endl; } /** * Generates the write() method for a struct */ void t_php_generator::generate_php_struct_writer(ostream& out, t_struct* tstruct, bool is_result) { string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; if (binary_inline_) { indent(out) << "public function write(&$output)" << endl; } else { indent(out) << "public function write($output)" << endl; } indent(out) << "{" << endl; indent_up(); if (needs_php_write_validator(tstruct, is_result)) { indent(out) << "$this->_validateForWrite();" << endl; } if (oop_) { indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" << endl; scope_down(out); out << endl; return; } indent(out) << "$xfer = 0;" << endl; if (!binary_inline_) { indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl; } for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { out << indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl; indent_up(); t_type* type = get_true_type((*f_iter)->get_type()); string expect; if (type->is_container()) { expect = "array"; } else if (type->is_struct()) { expect = "object"; } if (!expect.empty()) { out << indent() << "if (!is_" << expect << "($this->" << (*f_iter)->get_name() << ")) {" << endl; indent_up(); out << indent() << "throw new " << "TProtocolException('Bad type in structure.', " << "TProtocolException::INVALID_DATA);" << endl; scope_down(out); } // Write field header if (binary_inline_) { out << indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl << indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl; } else { indent(out) << "$xfer += $output->writeFieldBegin(" << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ");" << endl; } // Write field contents generate_serialize_field(out, *f_iter, "this->"); // Write field closer if (!binary_inline_) { indent(out) << "$xfer += $output->writeFieldEnd();" << endl; } indent_down(); indent(out) << "}" << endl; } if (binary_inline_) { out << indent() << "$output .= pack('c', " << "TType::STOP);" << endl; } else { out << indent() << "$xfer += $output->writeFieldStop();" << endl << indent() << "$xfer += $output->writeStructEnd();" << endl; } out << indent() << "return $xfer;" << endl; indent_down(); out << indent() << "}" << endl; } void t_php_generator::generate_php_struct_read_validator(ostream& out, t_struct* tstruct) { generate_php_struct_required_validator(out, tstruct, "_validateForRead", false); } void t_php_generator::generate_php_struct_write_validator(ostream& out, t_struct* tstruct) { generate_php_struct_required_validator(out, tstruct, "_validateForWrite", true); } void t_php_generator::generate_php_struct_required_validator(ostream& out, t_struct* tstruct, std::string method_name, bool write_mode) { indent(out) << "private function " << method_name << "() {" << endl; indent_up(); const vector& fields = tstruct->get_members(); if (fields.size() > 0) { vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = (*f_iter); if (field->get_req() == t_field::T_REQUIRED || (field->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) { indent(out) << "if ($this->" << field->get_name() << " === null) {" << endl; indent_up(); indent(out) << "throw new TProtocolException('Required field " << tstruct->get_name() << "." << field->get_name() << " is unset!');" << endl; indent_down(); indent(out) << "}" << endl; } } } indent_down(); indent(out) << "}" << endl; } void t_php_generator::generate_php_struct_json_serialize(ostream& out, t_struct* tstruct, bool is_result) { indent(out) << "public function jsonSerialize() {" << endl; indent_up(); if (needs_php_write_validator(tstruct, is_result)) { indent(out) << "$this->_validateForWrite();" << endl; } indent(out) << "$json = new stdClass;" << endl; const vector& fields = tstruct->get_members(); if (fields.size() > 0) { vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = (*f_iter); t_type* type = field->get_type(); const string& name = field->get_name(); if (type->is_map()) { t_type* key_type = ((t_map*)type)->get_key_type(); if (!(key_type->is_base_type() || key_type->is_enum())) { // JSON object keys must be strings. PHP's json_encode() // function will convert any scalar key to strings, but // we skip thrift maps with non-scalar keys. continue; } } indent(out) << "if ($this->" << name << " !== null) {" << endl; indent_up(); indent(out) << "$json->" << name << " = "; if (type->is_map()) { out << "(object)"; } else { out << type_to_cast(type); } out << "$this->" << name << ";" << endl; indent_down(); indent(out) << "}" << endl; } } indent(out) << "return $json;" << endl; indent_down(); indent(out) << "}" << endl; } int t_php_generator::get_php_num_required_fields(const vector& fields, bool write_mode) { int num_req = 0; if (fields.size() > 0) { vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_req() == t_field::T_REQUIRED || ((*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) { ++num_req; } } } return num_req; } bool t_php_generator::needs_php_write_validator(t_struct* tstruct, bool is_result) { return (validate_ && !is_result && !tstruct->is_union() && get_php_num_required_fields(tstruct->get_members(), true) > 0); } bool t_php_generator::needs_php_read_validator(t_struct* tstruct, bool is_result) { return (validate_ && !is_result && (get_php_num_required_fields(tstruct->get_members(), false) > 0)); } /** * Generates a thrift service. * * @param tservice The service definition */ void t_php_generator::generate_service(t_service* tservice) { if(classmap_) { string f_service_name = package_dir_ + service_name_ + ".php"; f_service_.open(f_service_name.c_str()); generate_service_header(tservice, f_service_); } // Generate the three main parts of the service (well, two for now in PHP) generate_service_interface(tservice); if (rest_) { generate_service_rest(tservice); } generate_service_client(tservice); generate_service_helpers(tservice); if (phps_) { generate_service_processor(tservice); } if(classmap_) { // Close service file f_service_ << endl; f_service_.close(); } } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_php_generator::generate_service_processor(t_service* tservice) { ofstream_with_content_based_conditional_update& f_service_processor = f_service_; if (!classmap_) { string f_service_processor_name = package_dir_ + service_name_ + "Processor.php"; f_service_processor.open(f_service_processor_name.c_str()); generate_service_header(tservice, f_service_processor); } // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_processor = ""; if (tservice->get_extends() != nullptr) { extends = tservice->get_extends()->get_name(); extends_processor = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends + "Processor"; } // Generate the header portion f_service_processor << "class " << service_name_ << "Processor" << extends_processor << endl << "{" << endl; indent_up(); if (extends.empty()) { f_service_processor << indent() << "protected $handler_ = null;" << endl; } f_service_processor << indent() << "public function __construct($handler)"<< endl << indent() << "{" << endl; indent_up(); if (extends.empty()) { f_service_processor << indent() << "$this->handler_ = $handler;" << endl; } else { f_service_processor << indent() << "parent::__construct($handler);" << endl; } indent_down(); f_service_processor << indent() << "}" << endl << endl; // Generate the server implementation f_service_processor << indent() << "public function process($input, $output)" << endl << indent() << "{" << endl; indent_up(); f_service_processor << indent() << "$rseqid = 0;" << endl << indent() << "$fname = null;" << endl << indent() << "$mtype = 0;" << endl << endl; if (binary_inline_) { t_field ffname(g_type_string, "fname"); t_field fmtype(g_type_i8, "mtype"); t_field fseqid(g_type_i32, "rseqid"); generate_deserialize_field(f_service_processor, &ffname, "", true); generate_deserialize_field(f_service_processor, &fmtype, "", true); generate_deserialize_field(f_service_processor, &fseqid, "", true); } else { f_service_processor << indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl; } // HOT: check for method implementation f_service_processor << indent() << "$methodname = 'process_'.$fname;" << endl << indent() << "if (!method_exists($this, $methodname)) {" << endl; indent_up(); if (binary_inline_) { f_service_processor << indent() << "throw new \\Exception('Function '.$fname.' not implemented.');" << endl; } else { f_service_processor << indent() << " $input->skip(" << "TType::STRUCT);" << endl << indent() << " $input->readMessageEnd();" << endl << indent() << " $x = new " << "TApplicationException('Function '.$fname.' not implemented.', " << "TApplicationException::UNKNOWN_METHOD);" << endl << indent() << " $output->writeMessageBegin($fname, " << "TMessageType::EXCEPTION, $rseqid);" << endl << indent() << " $x->write($output);" << endl << indent() << " $output->writeMessageEnd();" << endl << indent() << " $output->getTransport()->flush();" << endl << indent() << " return;" << endl; } indent_down(); f_service_processor << indent() << "}" << endl << indent() << "$this->$methodname($rseqid, $input, $output);" << endl << indent() << "return true;" << endl; indent_down(); f_service_processor << indent() << "}" << endl << endl; // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(f_service_processor, tservice, *f_iter); } indent_down(); f_service_processor << "}" << endl; if (!classmap_) { f_service_processor.close(); } } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_php_generator::generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction) { // Open function out << indent() << "protected function process_" << tfunction->get_name() << "($seqid, $input, $output)" << endl << indent() << "{" << endl; indent_up(); string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args"; string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result"; out << indent() << "$bin_accel = ($input instanceof " << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_read_binary_after_message_begin');" << endl; out << indent() << "if ($bin_accel) {" << endl; indent_up(); out << indent() << "$args = thrift_protocol_read_binary_after_message_begin(" <isStrictRead()" <read($input);" << endl; indent_down(); out << indent() << "}" << endl; if (!binary_inline_) { out << indent() << "$input->readMessageEnd();" << endl; } t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Declare result for non oneway function if (!tfunction->is_oneway()) { out << indent() << "$result = new " << resultname << "();" << endl; } // Try block for a function with exceptions if (xceptions.size() > 0) { out << indent() << "try {" << endl; indent_up(); } // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; out << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { out << "$result->success = "; } out << "$this->handler_->" << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { out << ", "; } out << "$args->" << (*f_iter)->get_name(); } out << ");" << endl; if (!tfunction->is_oneway() && xceptions.size() > 0) { indent_down(); for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << indent() << "} catch (" << php_namespace(get_true_type((*x_iter)->get_type())->get_program()) << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {" << endl; if (!tfunction->is_oneway()) { indent_up(); out << indent() << "$result->" << (*x_iter)->get_name() << " = $" << (*x_iter)->get_name() << ";" << endl; indent_down(); out << indent(); } } out << "}" << endl; } // Shortcut out here for oneway functions if (tfunction->is_oneway()) { out << indent() << "return;" << endl; indent_down(); out << indent() << "}" << endl; return; } out << indent() << "$bin_accel = ($output instanceof " << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');" << endl; out << indent() << "if ($bin_accel) {" << endl; indent_up(); out << indent() << "thrift_protocol_write_binary(" << endl; indent_up(); out << indent() << "$output,"<get_name()<< "'," <isStrictWrite()"<get_name() << "'));" << endl << indent() << "$buff .= '" << tfunction->get_name() << "';" << endl << indent() << "$buff .= pack('N', $seqid);" << endl << indent() << "$result->write($buff);" << endl << indent() << "$output->write($buff);" << endl << indent() << "$output->flush();" << endl; } else { out << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', " << "TMessageType::REPLY, $seqid);" << endl << indent() << "$result->write($output);" << endl << indent() << "$output->writeMessageEnd();" << endl << indent() << "$output->getTransport()->flush();" << endl; } scope_down(out); // Close function indent_down(); out << indent() << "}" << endl; } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_php_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; ofstream_with_content_based_conditional_update& f_struct_definition = f_service_; if (classmap_) { f_struct_definition << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl; } for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); string name = ts->get_name(); ts->set_name(service_name_ + "_" + name); if (!classmap_) { string f_struct_definition_name = package_dir_ + service_name_ + "_" + name + ".php"; f_struct_definition.open(f_struct_definition_name.c_str()); generate_service_header(tservice, f_struct_definition); } generate_php_struct_definition(f_struct_definition, ts); if (!classmap_) { f_struct_definition.close(); } generate_php_function_helpers(tservice, *f_iter); ts->set_name(name); } } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_php_generator::generate_php_function_helpers(t_service* tservice, t_function* tfunction) { if (!tfunction->is_oneway()) { t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } ofstream_with_content_based_conditional_update& f_struct_helper = f_service_; if (!classmap_) { string f_struct_helper_name = package_dir_ + result.get_name() + ".php"; f_struct_helper.open(f_struct_helper_name.c_str()); generate_service_header(tservice, f_struct_helper); } generate_php_struct_definition(f_struct_helper, &result, false, true); if (!classmap_) { f_struct_helper.close(); } } } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_php_generator::generate_service_interface(t_service* tservice) { ofstream_with_content_based_conditional_update& f_service_interface = f_service_; if (!classmap_) { string f_service_interface_name = package_dir_ + service_name_ + "If.php"; f_service_interface.open(f_service_interface_name.c_str()); generate_service_header(tservice, f_service_interface); } string extends = ""; string extends_if = ""; if (tservice->get_extends() != nullptr) { extends = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name(); extends_if = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name() + "If"; } generate_php_doc(f_service_interface, tservice); f_service_interface << "interface " << php_namespace_declaration(tservice) << "If" << extends_if << endl << "{" << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_php_doc(f_service_interface, *f_iter); indent(f_service_interface) << "public function " << function_signature(*f_iter) << ";" << endl; } indent_down(); f_service_interface << "}" << endl; // Close service interface file if (!classmap_) { f_service_interface.close(); } } /** * Generates a REST interface */ void t_php_generator::generate_service_rest(t_service* tservice) { ofstream_with_content_based_conditional_update& f_service_rest = f_service_; if (!classmap_) { string f_service_rest_name = package_dir_ + service_name_ + "Rest.php"; f_service_rest.open(f_service_rest_name.c_str()); generate_service_header(tservice, f_service_rest); } string extends = ""; string extends_if = ""; if (tservice->get_extends() != nullptr) { extends = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name(); extends_if = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name() + "Rest"; } f_service_rest << "class " << service_name_ << "Rest" << extends_if << endl << "{" << endl; indent_up(); if (extends.empty()) { f_service_rest << indent() << "protected $impl_;" << endl << endl; } f_service_rest << indent() << "public function __construct($impl) {" << endl << indent() << " $this->impl_ = $impl;" << endl << indent() << "}" << endl << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_service_rest) << "public function " << (*f_iter)->get_name() << "($request) {" << endl; indent_up(); const vector& args = (*f_iter)->get_arglist()->get_members(); vector::const_iterator a_iter; for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { t_type* atype = get_true_type((*a_iter)->get_type()); string cast = type_to_cast(atype); string req = "$request['" + (*a_iter)->get_name() + "']"; if (atype->is_bool()) { f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req << ") && (" << req << " !== 'false'));" << endl; } else { f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " << cast << req << " : null;" << endl; } if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) { f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = explode(',', $" << (*a_iter)->get_name() << ");" << endl; } else if (atype->is_map() || atype->is_list()) { f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = json_decode($" << (*a_iter)->get_name() << ", true);" << endl; } else if (atype->is_set()) { f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = array_fill_keys(json_decode($" << (*a_iter)->get_name() << ", true), 1);" << endl; } else if (atype->is_struct() || atype->is_xception()) { f_service_rest << indent() << "if ($" << (*a_iter)->get_name() << " !== null) {" << endl << indent() << " $" << (*a_iter)->get_name() << " = new " << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($" << (*a_iter)->get_name() << ", true));" << endl << indent() << "}" << endl; } } f_service_rest << indent() << "return $this->impl_->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist(), false) << ");" << endl; indent_down(); indent(f_service_rest) << "}" << endl << endl; } indent_down(); f_service_rest << "}" << endl << endl; // Close service rest file f_service_rest << endl; if (!classmap_) { f_service_rest.close(); } } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_php_generator::generate_service_client(t_service* tservice) { ofstream_with_content_based_conditional_update& f_service_client = f_service_; if (!classmap_) { string f_service_client_name = package_dir_ + service_name_ + "Client.php"; f_service_client.open(f_service_client_name.c_str()); generate_service_header(tservice, f_service_client); } string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = tservice->get_extends()->get_name(); extends_client = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends + "Client"; } f_service_client << "class " << php_namespace_declaration(tservice) << "Client" << extends_client << " implements " << php_namespace(tservice->get_program()) << service_name_ << "If" << endl <<"{"<< endl; indent_up(); // Private members if (extends.empty()) { f_service_client << indent() << "protected $input_ = null;" << endl << indent() << "protected $output_ = null;" << endl << endl; f_service_client << indent() << "protected $seqid_ = 0;" << endl << endl; } // Constructor function f_service_client << indent() << "public function __construct($input, $output = null)" << endl << indent() << "{" << endl; indent_up(); if (!extends.empty()) { f_service_client << indent() << "parent::__construct($input, $output);" << endl; } else { f_service_client << indent() << "$this->input_ = $input;" << endl << indent() << "$this->output_ = $output ? $output : $input;" << endl; } indent_down(); f_service_client << indent() << "}" << endl << endl; // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = (*f_iter)->get_name(); f_service_client << endl; // Open function indent(f_service_client) << "public function " << function_signature(*f_iter) << endl; scope_up(f_service_client); indent(f_service_client) << "$this->send_" << funname << "("; bool first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { f_service_client << ", "; } f_service_client << "$" << (*fld_iter)->get_name(); } f_service_client << ");" << endl; if (!(*f_iter)->is_oneway()) { f_service_client << indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_client << "return "; } f_service_client << "$this->recv_" << funname << "();" << endl; } scope_down(f_service_client); f_service_client << endl; indent(f_service_client) << "public function send_" << function_signature(*f_iter) << endl; scope_up(f_service_client); std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args"; f_service_client << indent() << "$args = new " << argsname << "();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_client << indent() << "$args->" << (*fld_iter)->get_name() << " = $" << (*fld_iter)->get_name() << ";" << endl; } f_service_client << indent() << "$bin_accel = ($this->output_ instanceof " << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');" << endl; f_service_client << indent() << "if ($bin_accel) {" << endl; indent_up(); string messageType = (*f_iter)->is_oneway() ? "TMessageType::ONEWAY" : "TMessageType::CALL"; f_service_client << indent() << "thrift_protocol_write_binary(" << endl; indent_up(); f_service_client << indent() << "$this->output_," << endl << indent() << "'" << (*f_iter)->get_name() << "'," << endl << indent() << messageType << "," << endl << indent() << "$args," << endl << indent() << "$this->seqid_," << endl << indent() << "$this->output_->isStrictWrite()" << endl; indent_down(); f_service_client << indent() << ");" << endl; indent_down(); f_service_client << indent() << "} else {" << endl; indent_up(); // Serialize the request header if (binary_inline_) { f_service_client << indent() << "$buff = pack('N', (0x80010000 | " << messageType << "));" << endl << indent() << "$buff .= pack('N', strlen('" << funname << "'));" << endl << indent() << "$buff .= '" << funname << "';" << endl << indent() << "$buff .= pack('N', $this->seqid_);" << endl; } else { f_service_client << indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name() << "', " << messageType << ", $this->seqid_);" << endl; } // Write to the stream if (binary_inline_) { f_service_client << indent() << "$args->write($buff);" << endl << indent() << "$this->output_->write($buff);" << endl << indent() << "$this->output_->flush();" << endl; } else { f_service_client << indent() << "$args->write($this->output_);" << endl << indent() << "$this->output_->writeMessageEnd();" << endl << indent() << "$this->output_->getTransport()->flush();" << endl; } scope_down(f_service_client); scope_down(f_service_client); if (!(*f_iter)->is_oneway()) { std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result"; t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); // Open function f_service_client << endl << indent() << "public function " << function_signature(&recv_function) << endl; scope_up(f_service_client); f_service_client << indent() << "$bin_accel = ($this->input_ instanceof " << "TBinaryProtocolAccelerated)" << " && function_exists('thrift_protocol_read_binary');" << endl; f_service_client << indent() << "if ($bin_accel) {" << endl; indent_up(); f_service_client << indent() << "$result = thrift_protocol_read_binary(" << endl; indent_up(); f_service_client << indent() << "$this->input_," << endl << indent() << "'" << resultname << "'," << endl << indent() << "$this->input_->isStrictRead()" << endl; indent_down(); f_service_client << indent() << ");" << endl; indent_down(); f_service_client << indent() << "} else {" << endl; indent_up(); f_service_client << indent() << "$rseqid = 0;" << endl << indent() << "$fname = null;" << endl << indent() << "$mtype = 0;" << endl << endl; if (binary_inline_) { t_field ffname(g_type_string, "fname"); t_field fseqid(g_type_i32, "rseqid"); f_service_client << indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl << indent() << "$ver = $ver[1];" << endl << indent() << "$mtype = $ver & 0xff;" << endl << indent() << "$ver = $ver & 0xffff0000;" << endl << indent() << "if ($ver != 0x80010000) throw new " << "TProtocolException('Bad version identifier: '.$ver, " << "TProtocolException::BAD_VERSION);" << endl; generate_deserialize_field(f_service_client, &ffname, "", true); generate_deserialize_field(f_service_client, &fseqid, "", true); } else { f_service_client << indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl << indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl; indent_up(); f_service_client << indent() << "$x = new TApplicationException();" << endl << indent() << "$x->read($this->input_);" << endl << indent() << "$this->input_->readMessageEnd();" << endl << indent() << "throw $x;" << endl; indent_down(); f_service_client << indent() << "}" << endl; } f_service_client << indent() << "$result = new " << resultname << "();" << endl << indent() << "$result->read($this->input_);" << endl; if (!binary_inline_) { f_service_client << indent() << "$this->input_->readMessageEnd();" << endl; } scope_down(f_service_client); // Careful, only return result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_client << indent() << "if ($result->success !== null) {" << endl; indent_up(); f_service_client << indent() << "return $result->success;" << endl; indent_down(); f_service_client << indent() << "}" << endl; } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_client << indent() << "if ($result->" << (*x_iter)->get_name() << " !== null) {" << endl; indent_up(); f_service_client << indent() << "throw $result->" << (*x_iter)->get_name() << ";" << endl; indent_down(); f_service_client << indent() << "}" << endl; } // Careful, only return _result if not a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_client) << "return;" << endl; } else { f_service_client << indent() << "throw new \\Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; } // Close function scope_down(f_service_client); } } indent_down(); f_service_client << "}" << endl; // Close service client file if (!classmap_) { f_service_client.close(); } } /** * Deserializes a field of any type. */ void t_php_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, bool inclass) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + tfield->get_name(); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else { if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { if (binary_inline_) { std::string itrans = (inclass ? "$this->input_" : "$input"); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << indent() << "$len = unpack('N', " << itrans << "->readAll(4));" << endl << indent() << "$len = $len[1];" << endl << indent() << "if ($len > 0x7fffffff) {" << endl << indent() << " $len = 0 - (($len - 1) ^ 0xffffffff);" << endl << indent() << "}" << endl << indent() << "$" << name << " = " << itrans << "->readAll($len);" << endl; break; case t_base_type::TYPE_BOOL: out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl << indent() << "$" << name << " = (bool)$" << name << "[1];" << endl; break; case t_base_type::TYPE_I8: out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl << indent() << "$" << name << " = $" << name << "[1];" << endl; break; case t_base_type::TYPE_I16: out << indent() << "$val = unpack('n', " << itrans << "->readAll(2));" << endl << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fff) {" << endl << indent() << " $val = 0 - (($val - 1) ^ 0xffff);" << endl << indent() << "}" << endl << indent() << "$" << name << " = $val;" << endl; break; case t_base_type::TYPE_I32: out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {" << endl << indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent() << "}" << endl << indent() << "$" << name << " = $val;" << endl; break; case t_base_type::TYPE_I64: out << indent() << "$arr = unpack('N2', " << itrans << "->readAll(8));" << endl << indent() << "if ($arr[1] & 0x80000000) {" << endl << indent() << " $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl << indent() << " $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl << indent() << " $" << name << " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl << indent() << "} else {" << endl << indent() << " $" << name << " = $arr[1]*4294967296 + $arr[2];" << endl << indent() << "}" << endl; break; case t_base_type::TYPE_DOUBLE: out << indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl << indent() << "$" << name << " = $arr[1];" << endl; break; default: throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase) + tfield->get_name(); } } else if (type->is_enum()) { out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {" << endl << indent() << " $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent() << "}" << endl << indent() << "$" << name << " = $val;" << endl; } } else { indent(out) << "$xfer += $input->"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << "readString($" << name << ");"; break; case t_base_type::TYPE_BOOL: out << "readBool($" << name << ");"; break; case t_base_type::TYPE_I8: out << "readByte($" << name << ");"; break; case t_base_type::TYPE_I16: out << "readI16($" << name << ");"; break; case t_base_type::TYPE_I32: out << "readI32($" << name << ");"; break; case t_base_type::TYPE_I64: out << "readI64($" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble($" << name << ");"; break; default: throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "readI32($" << name << ");"; } out << endl; } } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type->get_name().c_str()); } } } /** * Generates an unserializer for a variable. This makes two key assumptions, * first that there is a const char* variable named data that points to the * buffer for deserialization, and that there is a variable protocol which * is a reference to a TProtocol serialization object. */ void t_php_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { out << indent() << "$" << prefix << " = new " << php_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl << indent() << "$xfer += $" << prefix << "->read($input);" << endl; } void t_php_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { string size = tmp("_size"); string ktype = tmp("_ktype"); string vtype = tmp("_vtype"); string etype = tmp("_etype"); t_field fsize(g_type_i32, size); t_field fktype(g_type_i8, ktype); t_field fvtype(g_type_i8, vtype); t_field fetype(g_type_i8, etype); out << indent() << "$" << prefix << " = array();" << endl << indent() << "$" << size << " = 0;" << endl; // Declare variables, read header if (ttype->is_map()) { out << indent() << "$" << ktype << " = 0;" << endl << indent() << "$" << vtype << " = 0;" << endl; if (binary_inline_) { generate_deserialize_field(out, &fktype); generate_deserialize_field(out, &fvtype); generate_deserialize_field(out, &fsize); } else { out << indent() << "$xfer += $input->readMapBegin(" << "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl; } } else if (ttype->is_set()) { if (binary_inline_) { generate_deserialize_field(out, &fetype); generate_deserialize_field(out, &fsize); } else { out << indent() << "$" << etype << " = 0;" << endl << indent() << "$xfer += $input->readSetBegin(" << "$" << etype << ", $" << size << ");" << endl; } } else if (ttype->is_list()) { if (binary_inline_) { generate_deserialize_field(out, &fetype); generate_deserialize_field(out, &fsize); } else { out << indent() << "$" << etype << " = 0;" << endl << indent() << "$xfer += $input->readListBegin(" << "$" << etype << ", $" << size << ");" << endl; } } // For loop iterates over elements string i = tmp("_i"); indent(out) << "for ($" << i << " = 0; $" << i << " < $" << size << "; ++$" << i << ") {" << endl; indent_up(); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } scope_down(out); if (!binary_inline_) { // Read container end if (ttype->is_map()) { indent(out) << "$xfer += $input->readMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "$xfer += $input->readSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "$xfer += $input->readListEnd();" << endl; } } } /** * Generates code to deserialize a map */ void t_php_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("key"); string val = tmp("val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); indent(out) << declare_field(&fkey, true, true) << endl; indent(out) << declare_field(&fval, true, true) << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); indent(out) << "$" << prefix << "[$" << key << "] = $" << val << ";" << endl; } void t_php_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("elem"); t_field felem(tset->get_elem_type(), elem); indent(out) << "$" << elem << " = null;" << endl; generate_deserialize_field(out, &felem); t_type* elem_type = tset->get_elem_type(); if(php_is_scalar(elem_type)) { indent(out) << "$" << prefix << "[$" << elem << "] = true;" << endl; } else { indent(out) << "$" << prefix << "[] = $" << elem << ";" << endl; } } void t_php_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("elem"); t_field felem(tlist->get_elem_type(), elem); indent(out) << "$" << elem << " = null;" << endl; generate_deserialize_field(out, &felem); indent(out) << "$" << prefix << " []= $" << elem << ";" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_php_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + tfield->get_name()); } else if (type->is_base_type() || type->is_enum()) { string name = prefix + tfield->get_name(); if (binary_inline_) { if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << indent() << "$output .= pack('N', strlen($" << name << "));" << endl << indent() << "$output .= $" << name << ";" << endl; break; case t_base_type::TYPE_BOOL: out << indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl; break; case t_base_type::TYPE_I8: out << indent() << "$output .= pack('c', $" << name << ");" << endl; break; case t_base_type::TYPE_I16: out << indent() << "$output .= pack('n', $" << name << ");" << endl; break; case t_base_type::TYPE_I32: out << indent() << "$output .= pack('N', $" << name << ");" << endl; break; case t_base_type::TYPE_I64: out << indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl; break; case t_base_type::TYPE_DOUBLE: out << indent() << "$output .= strrev(pack('d', $" << name << "));" << endl; break; default: throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << indent() << "$output .= pack('N', $" << name << ");" << endl; } } else { indent(out) << "$xfer += $output->"; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: out << "writeString($" << name << ");"; break; case t_base_type::TYPE_BOOL: out << "writeBool($" << name << ");"; break; case t_base_type::TYPE_I8: out << "writeByte($" << name << ");"; break; case t_base_type::TYPE_I16: out << "writeI16($" << name << ");"; break; case t_base_type::TYPE_I32: out << "writeI32($" << name << ");"; break; case t_base_type::TYPE_I64: out << "writeI64($" << name << ");"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble($" << name << ");"; break; default: throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32($" << name << ");"; } out << endl; } } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type->get_name().c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_php_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; indent(out) << "$xfer += $" << prefix << "->write($output);" << endl; } /** * Writes out a container */ void t_php_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { if (ttype->is_map()) { if (binary_inline_) { out << indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type()) << ");" << endl << indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl; } else { indent(out) << "$output->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "count($" << prefix << "));" << endl; } } else if (ttype->is_set()) { if (binary_inline_) { out << indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl; } else { indent(out) << "$output->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << "count($" << prefix << "));" << endl; } } else if (ttype->is_list()) { if (binary_inline_) { out << indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl; } else { indent(out) << "$output->writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << "count($" << prefix << "));" << endl; } } if (ttype->is_map()) { string kiter = tmp("kiter"); string viter = tmp("viter"); indent(out) << "foreach ($" << prefix << " as " << "$" << kiter << " => $" << viter << ") {" << endl; indent_up(); generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); scope_down(out); } else if (ttype->is_set()) { string iter = tmp("iter"); string iter_val = tmp("iter"); indent(out) << "foreach ($" << prefix << " as $" << iter << " => $" << iter_val << ") {" << endl; indent_up(); t_type* elem_type = ((t_set*)ttype)->get_elem_type(); if(php_is_scalar(elem_type)) { generate_serialize_set_element(out, (t_set*)ttype, iter); } else { generate_serialize_set_element(out, (t_set*)ttype, iter_val); } scope_down(out); } else if (ttype->is_list()) { string iter = tmp("iter"); indent(out) << "foreach ($" << prefix << " as $" << iter << ") {" << endl; indent_up(); generate_serialize_list_element(out, (t_list*)ttype, iter); scope_down(out); } if (!binary_inline_) { if (ttype->is_map()) { indent(out) << "$output->writeMapEnd();" << endl; } else if (ttype->is_set()) { indent(out) << "$output->writeSetEnd();" << endl; } else if (ttype->is_list()) { indent(out) << "$output->writeListEnd();" << endl; } } } /** * Serializes the members of a map. * */ void t_php_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter) { t_field kfield(tmap->get_key_type(), kiter); generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), viter); generate_serialize_field(out, &vfield, ""); } /** * Serializes the members of a set. */ void t_php_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Serializes the members of a list. */ void t_php_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Emits a PHPDoc comment for the given contents */ void t_php_generator::generate_php_docstring_comment(ostream& out, string contents) { generate_docstring_comment(out, "/**\n", " * ", contents, " */\n"); } /** * Emits a PHPDoc comment if the provided object has a doc in Thrift */ void t_php_generator::generate_php_doc(ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_php_docstring_comment(out, tdoc->get_doc()); } } /** * Emits a PHPDoc comment for a field */ void t_php_generator::generate_php_doc(ostream& out, t_field* field) { stringstream ss; // prepend free-style doc if available if (field->has_doc()) { ss << field->get_doc() << endl; } // append @var tag t_type* type = get_true_type(field->get_type()); ss << "@var " << type_to_phpdoc(type) << endl; generate_php_docstring_comment(out, ss.str()); } /** * Emits a PHPDoc comment for a function */ void t_php_generator::generate_php_doc(ostream& out, t_function* function) { stringstream ss; if (function->has_doc()) { ss << function->get_doc() << endl; } // generate parameter types doc const vector& args = function->get_arglist()->get_members(); vector::const_iterator a_iter; for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { t_field* arg = *a_iter; ss << "@param " << type_to_phpdoc(arg->get_type()) << " $" << arg->get_name(); if (arg->has_doc()) { ss << " " << arg->get_doc(); } ss << endl; } // generate return type doc t_type* ret_type = function->get_returntype(); if (!ret_type->is_void() || ret_type->has_doc()) { ss << "@return " << type_to_phpdoc(ret_type); if (ret_type->has_doc()) { ss << " " << ret_type->get_doc(); } ss << endl; } // generate exceptions doc const vector& excs = function->get_xceptions()->get_members(); vector::const_iterator e_iter; for (e_iter = excs.begin(); e_iter != excs.end(); ++e_iter) { t_field* exc = *e_iter; ss << "@throws " << type_to_phpdoc(exc->get_type()); if (exc->has_doc()) { ss << " " << exc->get_doc(); } ss << endl; } generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); } /** * Declares a field, which may include initialization as necessary. * * @param ttype The type */ string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) { string result = "$" + tfield->get_name(); if (init) { t_type* type = get_true_type(tfield->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: break; case t_base_type::TYPE_STRING: result += " = ''"; break; case t_base_type::TYPE_BOOL: result += " = false"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: result += " = 0"; break; case t_base_type::TYPE_DOUBLE: result += " = 0.0"; break; default: throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { result += " = 0"; } else if (type->is_container()) { result += " = array()"; } else if (type->is_struct() || type->is_xception()) { if (obj) { result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()"; } else { result += " = null"; } } } return result + ";"; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_php_generator::function_signature(t_function* tfunction, string prefix) { return prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")"; } /** * Renders a field list */ string t_php_generator::argument_list(t_struct* tstruct, bool addTypeHints) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } t_type* type = (*f_iter)->get_type(); // Set type name if (addTypeHints) { if (type->is_struct()) { string className = php_namespace(type->get_program()) + php_namespace_directory("Definition", false) + classify(type->get_name()); result += className + " "; } else if (type->is_container()) { result += "array "; } } result += "$" + (*f_iter)->get_name(); } return result; } /** * Gets a typecast string for a particular type. */ string t_php_generator::type_to_cast(t_type* type) { if (type->is_base_type()) { t_base_type* btype = (t_base_type*)type; switch (btype->get_base()) { case t_base_type::TYPE_BOOL: return "(bool)"; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: return "(int)"; case t_base_type::TYPE_DOUBLE: return "(double)"; case t_base_type::TYPE_STRING: return "(string)"; default: return ""; } } else if (type->is_enum()) { return "(int)"; } return ""; } /** * Converts the parse type to a C++ enum string for the given type. */ string t_php_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType::STRING"; case t_base_type::TYPE_BOOL: return "TType::BOOL"; case t_base_type::TYPE_I8: return "TType::BYTE"; case t_base_type::TYPE_I16: return "TType::I16"; case t_base_type::TYPE_I32: return "TType::I32"; case t_base_type::TYPE_I64: return "TType::I64"; case t_base_type::TYPE_DOUBLE: return "TType::DOUBLE"; } } else if (type->is_enum()) { return "TType::I32"; } else if (type->is_struct() || type->is_xception()) { return "TType::STRUCT"; } else if (type->is_map()) { return "TType::MAP"; } else if (type->is_set()) { return "TType::SET"; } else if (type->is_list()) { return "TType::LST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** * Converts the parse type to a PHPDoc string for the given type. */ string t_php_generator::type_to_phpdoc(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: return "string"; case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: return "int"; case t_base_type::TYPE_I16: return "int"; case t_base_type::TYPE_I32: return "int"; case t_base_type::TYPE_I64: return "int"; case t_base_type::TYPE_DOUBLE: return "double"; } } else if (type->is_enum()) { return "int"; } else if (type->is_struct() || type->is_xception()) { return php_namespace(type->get_program()) + type->get_name(); } else if (type->is_map()) { return "array"; } else if (type->is_set()) { t_set* tset = static_cast(type); t_type* t_elem = tset->get_elem_type(); if (t_elem->is_container()) { return "(" + type_to_phpdoc(t_elem) + ")[]"; } else { return type_to_phpdoc(t_elem) + "[]"; } } else if (type->is_list()) { t_list* tlist = static_cast(type); t_type* t_elem = tlist->get_elem_type(); if (t_elem->is_container()) { return "(" + type_to_phpdoc(t_elem) + ")[]"; } else { return type_to_phpdoc(t_elem) + "[]"; } } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } THRIFT_REGISTER_GENERATOR( php, "PHP", " inlined: Generate PHP inlined files\n" " server: Generate PHP server stubs\n" " oop: Generate PHP with object oriented subclasses\n" " classmap: Generate old-style PHP files (use classmap autoloading)\n" " rest: Generate PHP REST processors\n" " nsglobal=NAME: Set global namespace\n" " validate: Generate PHP validator methods\n" " json: Generate JsonSerializable classes (requires PHP >= 5.4)\n" " getters_setters: Generate Getters and Setters for struct variables\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_py_generator.cc000066400000000000000000003042241420101504100246740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" #include "thrift/generate/t_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * Python code generator. * */ class t_py_generator : public t_generator { public: t_py_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator (program) { update_keywords(); std::map::const_iterator iter; gen_newstyle_ = true; gen_utf8strings_ = true; gen_dynbase_ = false; gen_slots_ = false; gen_tornado_ = false; gen_zope_interface_ = false; gen_twisted_ = false; gen_dynamic_ = false; coding_ = ""; gen_dynbaseclass_ = ""; gen_dynbaseclass_exc_ = ""; gen_dynbaseclass_frozen_exc_ = ""; gen_dynbaseclass_frozen_ = ""; import_dynbase_ = ""; package_prefix_ = ""; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("new_style") == 0) { pwarning(0, "new_style is enabled by default, so the option will be removed in the near future.\n"); } else if( iter->first.compare("old_style") == 0) { gen_newstyle_ = false; pwarning(0, "old_style is deprecated and may be removed in the future.\n"); } else if( iter->first.compare("utf8strings") == 0) { pwarning(0, "utf8strings is enabled by default, so the option will be removed in the near future.\n"); } else if( iter->first.compare("no_utf8strings") == 0) { gen_utf8strings_ = false; } else if( iter->first.compare("slots") == 0) { gen_slots_ = true; } else if( iter->first.compare("package_prefix") == 0) { package_prefix_ = iter->second; } else if( iter->first.compare("dynamic") == 0) { gen_dynamic_ = true; gen_newstyle_ = false; // dynamic is newstyle if( gen_dynbaseclass_.empty()) { gen_dynbaseclass_ = "TBase"; } if( gen_dynbaseclass_frozen_.empty()) { gen_dynbaseclass_frozen_ = "TFrozenBase"; } if( gen_dynbaseclass_exc_.empty()) { gen_dynbaseclass_exc_ = "TExceptionBase"; } if( gen_dynbaseclass_frozen_exc_.empty()) { gen_dynbaseclass_frozen_exc_ = "TFrozenExceptionBase"; } if( import_dynbase_.empty()) { import_dynbase_ = "from thrift.protocol.TBase import TBase, TFrozenBase, TExceptionBase, TFrozenExceptionBase, TTransport\n"; } } else if( iter->first.compare("dynbase") == 0) { gen_dynbase_ = true; gen_dynbaseclass_ = (iter->second); } else if( iter->first.compare("dynfrozen") == 0) { gen_dynbaseclass_frozen_ = (iter->second); } else if( iter->first.compare("dynexc") == 0) { gen_dynbaseclass_exc_ = (iter->second); } else if( iter->first.compare("dynfrozenexc") == 0) { gen_dynbaseclass_frozen_exc_ = (iter->second); } else if( iter->first.compare("dynimport") == 0) { gen_dynbase_ = true; import_dynbase_ = (iter->second); } else if( iter->first.compare("zope.interface") == 0) { gen_zope_interface_ = true; } else if( iter->first.compare("twisted") == 0) { gen_twisted_ = true; gen_zope_interface_ = true; } else if( iter->first.compare("tornado") == 0) { gen_tornado_ = true; } else if( iter->first.compare("coding") == 0) { coding_ = iter->second; } else { throw "unknown option py:" + iter->first; } } if (gen_twisted_ && gen_tornado_) { throw "at most one of 'twisted' and 'tornado' are allowed"; } copy_options_ = option_string; if (gen_twisted_) { out_dir_base_ = "gen-py.twisted"; } else if (gen_tornado_) { out_dir_base_ = "gen-py.tornado"; } else { out_dir_base_ = "gen-py"; } } std::string indent_str() const override { return " "; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_forward_declaration(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; std::string render_const_value(t_type* type, t_const_value* value); /** * Struct generation code */ void generate_py_struct(t_struct* tstruct, bool is_exception); void generate_py_thrift_spec(std::ostream& out, t_struct* tstruct, bool is_exception); void generate_py_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception = false); void generate_py_struct_reader(std::ostream& out, t_struct* tstruct); void generate_py_struct_writer(std::ostream& out, t_struct* tstruct); void generate_py_struct_required_validator(std::ostream& out, t_struct* tstruct); void generate_py_function_helpers(t_function* tfunction); /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_remote(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); /** * Serialization constructs */ void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(std::ostream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); void generate_python_docstring(std::ostream& out, t_struct* tstruct); void generate_python_docstring(std::ostream& out, t_function* tfunction); void generate_python_docstring(std::ostream& out, t_doc* tdoc, t_struct* tstruct, const char* subheader); void generate_python_docstring(std::ostream& out, t_doc* tdoc); /** * Helper rendering functions */ std::string py_autogen_comment(); std::string py_imports(); std::string render_includes(); std::string declare_argument(t_field* tfield); std::string render_field_default_value(t_field* tfield); std::string type_name(t_type* ttype); std::string function_signature(t_function* tfunction, bool interface = false); std::string argument_list(t_struct* tstruct, std::vector* pre = nullptr, std::vector* post = nullptr); std::string type_to_enum(t_type* ttype); std::string type_to_spec_args(t_type* ttype); static bool is_valid_namespace(const std::string& sub_namespace) { return sub_namespace == "twisted"; } static std::string get_real_py_module(const t_program* program, bool gen_twisted, std::string package_dir="") { if (gen_twisted) { std::string twisted_module = program->get_namespace("py.twisted"); if (!twisted_module.empty()) { return twisted_module; } } std::string real_module = program->get_namespace("py"); if (real_module.empty()) { return program->get_name(); } return package_dir + real_module; } static bool is_immutable(t_type* ttype) { std::map::iterator it = ttype->annotations_.find("python.immutable"); if (it == ttype->annotations_.end()) { // Exceptions are immutable by default. return ttype->is_xception(); } else if (it->second == "false") { return false; } else { return true; } } private: /** * True if we should generate new-style classes. */ bool gen_newstyle_; /** * True if we should generate dynamic style classes. */ bool gen_dynamic_; bool gen_dynbase_; std::string gen_dynbaseclass_; std::string gen_dynbaseclass_frozen_; std::string gen_dynbaseclass_exc_; std::string gen_dynbaseclass_frozen_exc_; std::string import_dynbase_; bool gen_slots_; std::string copy_options_; /** * True if we should generate code for use with zope.interface. */ bool gen_zope_interface_; /** * True if we should generate Twisted-friendly RPC services. */ bool gen_twisted_; /** * True if we should generate code for use with Tornado */ bool gen_tornado_; /** * True if strings should be encoded using utf-8. */ bool gen_utf8strings_; /** * specify generated file encoding * eg. # -*- coding: utf-8 -*- */ string coding_; string package_prefix_; /** * File streams */ ofstream_with_content_based_conditional_update f_types_; ofstream_with_content_based_conditional_update f_consts_; ofstream_with_content_based_conditional_update f_service_; std::string package_dir_; std::string module_; protected: std::set lang_keywords() const override { std::string keywords[] = { "False", "None", "True", "and", "as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except", "exec", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "print", "raise", "return", "try", "while", "with", "yield" }; return std::set(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) ); } }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_py_generator::init_generator() { // Make output directory string module = get_real_py_module(program_, gen_twisted_); package_dir_ = get_out_dir(); module_ = module; while (true) { // TODO: Do better error checking here. MKDIR(package_dir_.c_str()); std::ofstream init_py((package_dir_ + "/__init__.py").c_str(), std::ios_base::app); init_py.close(); if (module.empty()) { break; } string::size_type pos = module.find('.'); if (pos == string::npos) { package_dir_ += "/"; package_dir_ += module; module.clear(); } else { package_dir_ += "/"; package_dir_ += module.substr(0, pos); module.erase(0, pos + 1); } } // Make output file string f_types_name = package_dir_ + "/" + "ttypes.py"; f_types_.open(f_types_name.c_str()); string f_consts_name = package_dir_ + "/" + "constants.py"; f_consts_.open(f_consts_name.c_str()); string f_init_name = package_dir_ + "/__init__.py"; ofstream_with_content_based_conditional_update f_init; f_init.open(f_init_name.c_str()); f_init << "__all__ = ['ttypes', 'constants'"; vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { f_init << ", '" << (*sv_iter)->get_name() << "'"; } f_init << "]" << endl; f_init.close(); // Print header f_types_ << py_autogen_comment() << endl << py_imports() << endl << render_includes() << endl << "from thrift.transport import TTransport" << endl << import_dynbase_; f_types_ << "all_structs = []" << endl; f_consts_ << py_autogen_comment() << endl << py_imports() << endl << "from .ttypes import *" << endl; } /** * Renders all the imports necessary for including another Thrift program */ string t_py_generator::render_includes() { const vector& includes = program_->get_includes(); string result = ""; for (auto include : includes) { result += "import " + get_real_py_module(include, gen_twisted_, package_prefix_) + ".ttypes\n"; } return result; } /** * Autogen'd comment */ string t_py_generator::py_autogen_comment() { string coding; if (!coding_.empty()) { coding = "# -*- coding: " + coding_ + " -*-\n"; } return coding + std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n" + "# options string: " + copy_options_ + "\n" + "#\n"; } /** * Prints standard thrift imports */ string t_py_generator::py_imports() { ostringstream ss; ss << "from thrift.Thrift import TType, TMessageType, TFrozenDict, TException, " "TApplicationException" << endl << "from thrift.protocol.TProtocol import TProtocolException" << endl << "from thrift.TRecursive import fix_spec" << endl; if (gen_utf8strings_) { ss << endl << "import sys"; } return ss.str(); } /** * Closes the type files */ void t_py_generator::close_generator() { // Fix thrift_spec definitions for recursive structs. f_types_ << "fix_spec(all_structs)" << endl; f_types_ << "del all_structs" << endl; // Close types file f_types_.close(); f_consts_.close(); } /** * Generates a typedef. This is not done in Python, types are all implicit. * * @param ttypedef The type definition */ void t_py_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Generates code for an enumerated type. Done using a class to scope * the values. * * @param tenum The enumeration */ void t_py_generator::generate_enum(t_enum* tenum) { std::ostringstream to_string_mapping, from_string_mapping; f_types_ << endl << endl << "class " << tenum->get_name() << (gen_newstyle_ ? "(object)" : "") << (gen_dynamic_ ? "(" + gen_dynbaseclass_ + ")" : "") << ":" << endl; indent_up(); generate_python_docstring(f_types_, tenum); to_string_mapping << indent() << "_VALUES_TO_NAMES = {" << endl; from_string_mapping << indent() << "_NAMES_TO_VALUES = {" << endl; vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); indent(f_types_) << (*c_iter)->get_name() << " = " << value << endl; // Dictionaries to/from string names of enums to_string_mapping << indent() << indent() << value << ": \"" << escape_string((*c_iter)->get_name()) << "\"," << endl; from_string_mapping << indent() << indent() << '"' << escape_string((*c_iter)->get_name()) << "\": " << value << ',' << endl; } to_string_mapping << indent() << "}" << endl; from_string_mapping << indent() << "}" << endl; indent_down(); f_types_ << endl; f_types_ << to_string_mapping.str() << endl << from_string_mapping.str(); } /** * Generate a constant value */ void t_py_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); indent(f_consts_) << name << " = " << render_const_value(type, value); f_consts_ << endl; } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_py_generator::render_const_value(t_type* type, t_const_value* value) { type = get_true_type(type); std::ostringstream out; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: if (((t_base_type*)type)->is_binary()) { out << 'b'; } out << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "True" : "False"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << "float(" << value->get_integer() << ")"; } else { out << emit_double_as_string(value->get_double()); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << type_name(type) << "(**{" << endl; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } indent(out) << render_const_value(g_type_string, v_iter->first) << ": " << render_const_value(field_type, v_iter->second) << "," << endl; } indent_down(); indent(out) << "})"; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); if (is_immutable(type)) { out << "TFrozenDict("; } out << "{" << endl; indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { indent(out) << render_const_value(ktype, v_iter->first) << ": " << render_const_value(vtype, v_iter->second) << "," << endl; } indent_down(); indent(out) << "}"; if (is_immutable(type)) { out << ")"; } } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } if (type->is_set()) { if (is_immutable(type)) { out << "frozen"; } out << "set("; } if (is_immutable(type) || type->is_set()) { out << "(" << endl; } else { out << "[" << endl; } indent_up(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { indent(out) << render_const_value(etype, *v_iter) << "," << endl; } indent_down(); if (is_immutable(type) || type->is_set()) { indent(out) << ")"; } else { indent(out) << "]"; } if (type->is_set()) { out << ")"; } } else { throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); } return out.str(); } /** * Generates the "forward declarations" for python structs. * These are actually full class definitions so that calls to generate_struct * can add the thrift_spec field. This is needed so that all thrift_spec * definitions are grouped at the end of the file to enable co-recursive structs. */ void t_py_generator::generate_forward_declaration(t_struct* tstruct) { generate_py_struct(tstruct, tstruct->is_xception()); } /** * Generates a python struct */ void t_py_generator::generate_struct(t_struct* tstruct) { generate_py_thrift_spec(f_types_, tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_py_generator::generate_xception(t_struct* txception) { generate_py_thrift_spec(f_types_, txception, true); } /** * Generates a python struct */ void t_py_generator::generate_py_struct(t_struct* tstruct, bool is_exception) { generate_py_struct_definition(f_types_, tstruct, is_exception); } /** * Generate the thrift_spec for a struct * For example, * all_structs.append(Recursive) * Recursive.thrift_spec = ( * None, # 0 * (1, TType.LIST, 'Children', (TType.STRUCT, (Recursive, None), False), None, ), # 1 * ) */ void t_py_generator::generate_py_thrift_spec(ostream& out, t_struct* tstruct, bool /*is_exception*/) { const vector& sorted_members = tstruct->get_sorted_members(); vector::const_iterator m_iter; // Add struct definition to list so thrift_spec can be fixed for recursive structures. indent(out) << "all_structs.append(" << tstruct->get_name() << ")" << endl; if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) { indent(out) << tstruct->get_name() << ".thrift_spec = (" << endl; indent_up(); int sorted_keys_pos = 0; for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) { for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) { indent(out) << "None, # " << sorted_keys_pos << endl; } indent(out) << "(" << (*m_iter)->get_key() << ", " << type_to_enum((*m_iter)->get_type()) << ", " << "'" << (*m_iter)->get_name() << "'" << ", " << type_to_spec_args((*m_iter)->get_type()) << ", " << render_field_default_value(*m_iter) << ", " << ")," << " # " << sorted_keys_pos << endl; sorted_keys_pos++; } indent_down(); indent(out) << ")" << endl; } else { indent(out) << tstruct->get_name() << ".thrift_spec = ()" << endl; } } /** * Generates a struct definition for a thrift data type. * * @param tstruct The struct definition */ void t_py_generator::generate_py_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) { const vector& members = tstruct->get_members(); const vector& sorted_members = tstruct->get_sorted_members(); vector::const_iterator m_iter; out << endl << endl << "class " << tstruct->get_name(); if (is_exception) { if (gen_dynamic_) { if (is_immutable(tstruct)) { out << "(" << gen_dynbaseclass_frozen_exc_ << ")"; } else { out << "(" << gen_dynbaseclass_exc_ << ")"; } } else { out << "(TException)"; } } else if (gen_dynamic_) { if (is_immutable(tstruct)) { out << "(" << gen_dynbaseclass_frozen_ << ")"; } else { out << "(" << gen_dynbaseclass_ << ")"; } } else if (gen_newstyle_) { out << "(object)"; } out << ":" << endl; indent_up(); generate_python_docstring(out, tstruct); out << endl; /* Here we generate the structure specification for the fastbinary codec. These specifications have the following structure: thrift_spec -> tuple of item_spec item_spec -> None | (tag, type_enum, name, spec_args, default) tag -> integer type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ... name -> string_literal default -> None # Handled by __init__ spec_args -> None # For simple types | (type_enum, spec_args) # Value type for list/set | (type_enum, spec_args, type_enum, spec_args) # Key and value for map | (class_name, spec_args_ptr) # For struct/exception class_name -> identifier # Basically a pointer to the class spec_args_ptr -> expression # just class_name.spec_args TODO(dreiss): Consider making this work for structs with negative tags. */ if (gen_slots_) { indent(out) << "__slots__ = (" << endl; indent_up(); for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) { indent(out) << "'" << (*m_iter)->get_name() << "'," << endl; } indent_down(); indent(out) << ")" << endl << endl; } // TODO(dreiss): Look into generating an empty tuple instead of None // for structures with no members. // TODO(dreiss): Test encoding of structs where some inner structs // don't have thrift_spec. if (members.size() > 0) { out << endl; out << indent() << "def __init__(self,"; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << " " << declare_argument(*m_iter) << ","; } out << "):" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { // Initialize fields t_type* type = (*m_iter)->get_type(); if (!type->is_base_type() && !type->is_enum() && (*m_iter)->get_value() != nullptr) { indent(out) << "if " << (*m_iter)->get_name() << " is " << "self.thrift_spec[" << (*m_iter)->get_key() << "][4]:" << endl; indent_up(); indent(out) << (*m_iter)->get_name() << " = " << render_field_default_value(*m_iter) << endl; indent_down(); } if (is_immutable(tstruct)) { if (gen_newstyle_ || gen_dynamic_) { indent(out) << "super(" << tstruct->get_name() << ", self).__setattr__('" << (*m_iter)->get_name() << "', " << (*m_iter)->get_name() << ")" << endl; } else { indent(out) << "self.__dict__['" << (*m_iter)->get_name() << "'] = " << (*m_iter)->get_name() << endl; } } else { indent(out) << "self." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << endl; } } indent_down(); } if (is_immutable(tstruct)) { out << endl; out << indent() << "def __setattr__(self, *args):" << endl << indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl << endl; out << indent() << "def __delattr__(self, *args):" << endl << indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl << endl; // Hash all of the members in order, and also hash in the class // to avoid collisions for stuff like single-field structures. out << indent() << "def __hash__(self):" << endl << indent() << indent_str() << "return hash(self.__class__) ^ hash(("; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << "self." << (*m_iter)->get_name() << ", "; } out << "))" << endl; } if (!gen_dynamic_) { out << endl; generate_py_struct_reader(out, tstruct); generate_py_struct_writer(out, tstruct); } // For exceptions only, generate a __str__ method. This is // because when raised exceptions are printed to the console, __repr__ // isn't used. See python bug #5882 if (is_exception) { out << endl; out << indent() << "def __str__(self):" << endl << indent() << indent_str() << "return repr(self)" << endl; } if (!gen_slots_) { out << endl; // Printing utilities so that on the command line thrift // structs look pretty like dictionaries indent(out) << "def __repr__(self):" << endl; indent_up(); out << indent() << "L = ['%s=%r' % (key, value)" << endl << indent() << " for key, value in self.__dict__.items()]" << endl << indent() << "return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl << endl; indent_down(); // Equality and inequality methods that compare by value out << indent() << "def __eq__(self, other):" << endl; indent_up(); out << indent() << "return isinstance(other, self.__class__) and " "self.__dict__ == other.__dict__" << endl; indent_down(); out << endl; out << indent() << "def __ne__(self, other):" << endl; indent_up(); out << indent() << "return not (self == other)" << endl; indent_down(); } else if (!gen_dynamic_) { out << endl; // no base class available to implement __eq__ and __repr__ and __ne__ for us // so we must provide one that uses __slots__ indent(out) << "def __repr__(self):" << endl; indent_up(); out << indent() << "L = ['%s=%r' % (key, getattr(self, key))" << endl << indent() << " for key in self.__slots__]" << endl << indent() << "return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl << endl; indent_down(); // Equality method that compares each attribute by value and type, walking __slots__ out << indent() << "def __eq__(self, other):" << endl; indent_up(); out << indent() << "if not isinstance(other, self.__class__):" << endl << indent() << indent_str() << "return False" << endl << indent() << "for attr in self.__slots__:" << endl << indent() << indent_str() << "my_val = getattr(self, attr)" << endl << indent() << indent_str() << "other_val = getattr(other, attr)" << endl << indent() << indent_str() << "if my_val != other_val:" << endl << indent() << indent_str() << indent_str() << "return False" << endl << indent() << "return True" << endl << endl; indent_down(); out << indent() << "def __ne__(self, other):" << endl << indent() << indent_str() << "return not (self == other)" << endl; } indent_down(); } /** * Generates the read method for a struct */ void t_py_generator::generate_py_struct_reader(ostream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; if (is_immutable(tstruct)) { out << indent() << "@classmethod" << endl << indent() << "def read(cls, iprot):" << endl; } else { indent(out) << "def read(self, iprot):" << endl; } indent_up(); const char* id = is_immutable(tstruct) ? "cls" : "self"; indent(out) << "if iprot._fast_decode is not None " "and isinstance(iprot.trans, TTransport.CReadableTransport) " "and " << id << ".thrift_spec is not None:" << endl; indent_up(); if (is_immutable(tstruct)) { indent(out) << "return iprot._fast_decode(None, iprot, [cls, cls.thrift_spec])" << endl; } else { indent(out) << "iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec])" << endl; indent(out) << "return" << endl; } indent_down(); indent(out) << "iprot.readStructBegin()" << endl; if (is_immutable(tstruct)) { for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* tfield = *f_iter; std::ostringstream result; result << tfield->get_name() << " = "; if (tfield->get_value() != nullptr) { result << render_field_default_value(tfield); } else { result << "None"; } indent(out) << result.str() << endl; } } // Loop over reading in fields indent(out) << "while True:" << endl; indent_up(); // Read beginning field marker indent(out) << "(fname, ftype, fid) = iprot.readFieldBegin()" << endl; // Check for field STOP marker and break indent(out) << "if ftype == TType.STOP:" << endl; indent_up(); indent(out) << "break" << endl; indent_down(); // Switch statement on the field we are reading bool first = true; // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; out << indent() << "if "; } else { out << indent() << "elif "; } out << "fid == " << (*f_iter)->get_key() << ":" << endl; indent_up(); indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << ":" << endl; indent_up(); if (is_immutable(tstruct)) { generate_deserialize_field(out, *f_iter); } else { generate_deserialize_field(out, *f_iter, "self."); } indent_down(); out << indent() << "else:" << endl << indent() << indent_str() << "iprot.skip(ftype)" << endl; indent_down(); } // In the default case we skip the field out << indent() << "else:" << endl << indent() << indent_str() << "iprot.skip(ftype)" << endl; // Read field end marker indent(out) << "iprot.readFieldEnd()" << endl; indent_down(); indent(out) << "iprot.readStructEnd()" << endl; if (is_immutable(tstruct)) { indent(out) << "return cls(" << endl; indent_up(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << (*f_iter)->get_name() << "=" << (*f_iter)->get_name() << "," << endl; } indent_down(); indent(out) << ")" << endl; } indent_down(); out << endl; } void t_py_generator::generate_py_struct_writer(ostream& out, t_struct* tstruct) { string name = tstruct->get_name(); const vector& fields = tstruct->get_sorted_members(); vector::const_iterator f_iter; indent(out) << "def write(self, oprot):" << endl; indent_up(); indent(out) << "if oprot._fast_encode is not None and self.thrift_spec is not None:" << endl; indent_up(); indent(out) << "oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec]))" << endl; indent(out) << "return" << endl; indent_down(); indent(out) << "oprot.writeStructBegin('" << name << "')" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { // Write field header indent(out) << "if self." << (*f_iter)->get_name() << " is not None:" << endl; indent_up(); indent(out) << "oprot.writeFieldBegin(" << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ")" << endl; // Write field contents generate_serialize_field(out, *f_iter, "self."); // Write field closer indent(out) << "oprot.writeFieldEnd()" << endl; indent_down(); } // Write the struct map out << indent() << "oprot.writeFieldStop()" << endl << indent() << "oprot.writeStructEnd()" << endl; out << endl; indent_down(); generate_py_struct_required_validator(out, tstruct); } void t_py_generator::generate_py_struct_required_validator(ostream& out, t_struct* tstruct) { indent(out) << "def validate(self):" << endl; indent_up(); const vector& fields = tstruct->get_members(); if (fields.size() > 0) { vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = (*f_iter); if (field->get_req() == t_field::T_REQUIRED) { indent(out) << "if self." << field->get_name() << " is None:" << endl; indent(out) << indent_str() << "raise TProtocolException(message='Required field " << field->get_name() << " is unset!')" << endl; } } } indent(out) << "return" << endl; indent_down(); } /** * Generates a thrift service. * * @param tservice The service definition */ void t_py_generator::generate_service(t_service* tservice) { string f_service_name = package_dir_ + "/" + service_name_ + ".py"; f_service_.open(f_service_name.c_str()); f_service_ << py_autogen_comment() << endl << py_imports() << endl; if (tservice->get_extends() != nullptr) { f_service_ << "import " << get_real_py_module(tservice->get_extends()->get_program(), gen_twisted_, package_prefix_) << "." << tservice->get_extends()->get_name() << endl; } f_service_ << "import logging" << endl << "from .ttypes import *" << endl << "from thrift.Thrift import TProcessor" << endl << "from thrift.transport import TTransport" << endl << import_dynbase_; if (gen_zope_interface_) { f_service_ << "from zope.interface import Interface, implementer" << endl; } if (gen_twisted_) { f_service_ << "from twisted.internet import defer" << endl << "from thrift.transport import TTwisted" << endl; } else if (gen_tornado_) { f_service_ << "from tornado import gen" << endl; f_service_ << "from tornado import concurrent" << endl; } f_service_ << "all_structs = []" << endl; // Generate the three main parts of the service generate_service_interface(tservice); generate_service_client(tservice); generate_service_server(tservice); generate_service_helpers(tservice); generate_service_remote(tservice); // Close service file f_service_ << "fix_spec(all_structs)" << endl << "del all_structs" << endl; f_service_.close(); } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_py_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; f_service_ << endl << "# HELPER FUNCTIONS AND STRUCTURES" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_py_struct_definition(f_service_, ts, false); generate_py_thrift_spec(f_service_, ts, false); generate_py_function_helpers(*f_iter); } } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_py_generator::generate_py_function_helpers(t_function* tfunction) { if (!tfunction->is_oneway()) { t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_py_struct_definition(f_service_, &result, false); generate_py_thrift_spec(f_service_, &result, false); } } /** * Generates a service interface definition. * * @param tservice The service to generate a header definition for */ void t_py_generator::generate_service_interface(t_service* tservice) { string extends = ""; string extends_if = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_if = "(" + extends + ".Iface)"; } else { if (gen_zope_interface_) { extends_if = "(Interface)"; } else if (gen_newstyle_ || gen_dynamic_ || gen_tornado_) { extends_if = "(object)"; } } f_service_ << endl << endl << "class Iface" << extends_if << ":" << endl; indent_up(); generate_python_docstring(f_service_, tservice); vector functions = tservice->get_functions(); if (functions.empty()) { f_service_ << indent() << "pass" << endl; } else { vector::iterator f_iter; bool first = true; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << endl; } f_service_ << indent() << "def " << function_signature(*f_iter, true) << ":" << endl; indent_up(); generate_python_docstring(f_service_, (*f_iter)); f_service_ << indent() << "pass" << endl; indent_down(); } } indent_down(); } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_py_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); if (gen_zope_interface_) { extends_client = "(" + extends + ".Client)"; } else { extends_client = extends + ".Client, "; } } else { if (gen_zope_interface_ && (gen_newstyle_ || gen_dynamic_)) { extends_client = "(object)"; } } f_service_ << endl << endl; if (gen_zope_interface_) { f_service_ << "@implementer(Iface)" << endl << "class Client" << extends_client << ":" << endl << endl; } else { f_service_ << "class Client(" << extends_client << "Iface):" << endl; } indent_up(); generate_python_docstring(f_service_, tservice); // Constructor function if (gen_twisted_) { f_service_ << indent() << "def __init__(self, transport, oprot_factory):" << endl; } else if (gen_tornado_) { f_service_ << indent() << "def __init__(self, transport, iprot_factory, oprot_factory=None):" << endl; } else { f_service_ << indent() << "def __init__(self, iprot, oprot=None):" << endl; } indent_up(); if (extends.empty()) { if (gen_twisted_) { f_service_ << indent() << "self._transport = transport" << endl << indent() << "self._oprot_factory = oprot_factory" << endl << indent() << "self._seqid = 0" << endl << indent() << "self._reqs = {}" << endl; } else if (gen_tornado_) { f_service_ << indent() << "self._transport = transport" << endl << indent() << "self._iprot_factory = iprot_factory" << endl << indent() << "self._oprot_factory = (oprot_factory if oprot_factory is not None" << endl << indent() << " else iprot_factory)" << endl << indent() << "self._seqid = 0" << endl << indent() << "self._reqs = {}" << endl << indent() << "self._transport.io_loop.spawn_callback(self._start_receiving)" << endl; } else { f_service_ << indent() << "self._iprot = self._oprot = iprot" << endl << indent() << "if oprot is not None:" << endl << indent() << indent_str() << "self._oprot = oprot" << endl << indent() << "self._seqid = 0" << endl; } } else { if (gen_twisted_) { f_service_ << indent() << extends << ".Client.__init__(self, transport, oprot_factory)" << endl; } else if (gen_tornado_) { f_service_ << indent() << extends << ".Client.__init__(self, transport, iprot_factory, oprot_factory)" << endl; } else { f_service_ << indent() << extends << ".Client.__init__(self, iprot, oprot)" << endl; } } indent_down(); if (gen_tornado_ && extends.empty()) { f_service_ << endl << indent() << "@gen.engine" << endl << indent() << "def _start_receiving(self):" << endl; indent_up(); indent(f_service_) << "while True:" << endl; indent_up(); f_service_ << indent() << "try:" << endl << indent() << indent_str() << "frame = yield self._transport.readFrame()" << endl << indent() << "except TTransport.TTransportException as e:" << endl << indent() << indent_str() << "for future in self._reqs.values():" << endl << indent() << indent_str() << indent_str() << "future.set_exception(e)" << endl << indent() << indent_str() << "self._reqs = {}" << endl << indent() << indent_str() << "return" << endl << indent() << "tr = TTransport.TMemoryBuffer(frame)" << endl << indent() << "iprot = self._iprot_factory.getProtocol(tr)" << endl << indent() << "(fname, mtype, rseqid) = iprot.readMessageBegin()" << endl << indent() << "method = getattr(self, 'recv_' + fname)" << endl << indent() << "future = self._reqs.pop(rseqid, None)" << endl << indent() << "if not future:" << endl << indent() << indent_str() << "# future has already been discarded" << endl << indent() << indent_str() << "continue" << endl << indent() << "try:" << endl << indent() << indent_str() << "result = method(iprot, mtype, rseqid)" << endl << indent() << "except Exception as e:" << endl << indent() << indent_str() << "future.set_exception(e)" << endl << indent() << "else:" << endl << indent() << indent_str() << "future.set_result(result)" << endl; indent_down(); indent_down(); } // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = (*f_iter)->get_name(); f_service_ << endl; // Open function indent(f_service_) << "def " << function_signature(*f_iter, false) << ":" << endl; indent_up(); generate_python_docstring(f_service_, (*f_iter)); if (gen_twisted_) { indent(f_service_) << "seqid = self._seqid = self._seqid + 1" << endl; indent(f_service_) << "self._reqs[seqid] = defer.Deferred()" << endl << endl; indent(f_service_) << "d = defer.maybeDeferred(self.send_" << funname; } else if (gen_tornado_) { indent(f_service_) << "self._seqid += 1" << endl; if (!(*f_iter)->is_oneway()) { indent(f_service_) << "future = self._reqs[self._seqid] = concurrent.Future()" << endl; } indent(f_service_) << "self.send_" << funname << "("; } else { indent(f_service_) << "self.send_" << funname << "("; } bool first = true; if (gen_twisted_) { // we need a leading comma if there are args, since it's called as maybeDeferred(funcname, // arg) first = false; } for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << (*fld_iter)->get_name(); } f_service_ << ")" << endl; if (!(*f_iter)->is_oneway()) { if (gen_twisted_) { // nothing. See the next block. } else if (gen_tornado_) { indent(f_service_) << "return future" << endl; } else { f_service_ << indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << "return "; } f_service_ << "self.recv_" << funname << "()" << endl; } } indent_down(); if (gen_twisted_) { // This block injects the body of the send_<> method for twisted (and a cb/eb pair) indent_up(); indent(f_service_) << "d.addCallbacks(" << endl; indent_up(); f_service_ << indent() << "callback=self.cb_send_" << funname << "," << endl << indent() << "callbackArgs=(seqid,)," << endl << indent() << "errback=self.eb_send_" << funname << "," << endl << indent() << "errbackArgs=(seqid,))" << endl; indent_down(); indent(f_service_) << "return d" << endl; indent_down(); f_service_ << endl; indent(f_service_) << "def cb_send_" << funname << "(self, _, seqid):" << endl; indent_up(); if ((*f_iter)->is_oneway()) { // if one-way, fire the deferred & remove it from _reqs f_service_ << indent() << "d = self._reqs.pop(seqid)" << endl << indent() << "d.callback(None)" << endl << indent() << "return d" << endl; } else { f_service_ << indent() << "return self._reqs[seqid]" << endl; } indent_down(); f_service_ << endl; // add an errback to fail the request if the call to send_<> raised an exception indent(f_service_) << "def eb_send_" << funname << "(self, f, seqid):" << endl; indent_up(); f_service_ << indent() << "d = self._reqs.pop(seqid)" << endl << indent() << "d.errback(f)" << endl << indent() << "return d" << endl; indent_down(); } f_service_ << endl; indent(f_service_) << "def send_" << function_signature(*f_iter, false) << ":" << endl; indent_up(); std::string argsname = (*f_iter)->get_name() + "_args"; std::string messageType = (*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL"; // Serialize the request header if (gen_twisted_ || gen_tornado_) { f_service_ << indent() << "oprot = self._oprot_factory.getProtocol(self._transport)" << endl << indent() << "oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', " << messageType << ", self._seqid)" << endl; } else { f_service_ << indent() << "self._oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', " << messageType << ", self._seqid)" << endl; } f_service_ << indent() << "args = " << argsname << "()" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << endl; } // Write to the stream if (gen_twisted_ || gen_tornado_) { f_service_ << indent() << "args.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()" << endl << indent() << "oprot.trans.flush()" << endl; } else { f_service_ << indent() << "args.write(self._oprot)" << endl << indent() << "self._oprot.writeMessageEnd()" << endl << indent() << "self._oprot.trans.flush()" << endl; } indent_down(); if (!(*f_iter)->is_oneway()) { std::string resultname = (*f_iter)->get_name() + "_result"; // Open function f_service_ << endl; if (gen_twisted_ || gen_tornado_) { f_service_ << indent() << "def recv_" << (*f_iter)->get_name() << "(self, iprot, mtype, rseqid):" << endl; } else { t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); f_service_ << indent() << "def " << function_signature(&recv_function) << ":" << endl; } indent_up(); // TODO(mcslee): Validate message reply here, seq ids etc. if (gen_twisted_) { f_service_ << indent() << "d = self._reqs.pop(rseqid)" << endl; } else if (gen_tornado_) { } else { f_service_ << indent() << "iprot = self._iprot" << endl << indent() << "(fname, mtype, rseqid) = iprot.readMessageBegin()" << endl; } f_service_ << indent() << "if mtype == TMessageType.EXCEPTION:" << endl << indent() << indent_str() << "x = TApplicationException()" << endl; if (gen_twisted_) { f_service_ << indent() << indent_str() << "x.read(iprot)" << endl << indent() << indent_str() << "iprot.readMessageEnd()" << endl << indent() << indent_str() << "return d.errback(x)" << endl << indent() << "result = " << resultname << "()" << endl << indent() << "result.read(iprot)" << endl << indent() << "iprot.readMessageEnd()" << endl; } else { f_service_ << indent() << indent_str() << "x.read(iprot)" << endl << indent() << indent_str() << "iprot.readMessageEnd()" << endl << indent() << indent_str() << "raise x" << endl << indent() << "result = " << resultname << "()" << endl << indent() << "result.read(iprot)" << endl << indent() << "iprot.readMessageEnd()" << endl; } // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << "if result.success is not None:" << endl; if (gen_twisted_) { f_service_ << indent() << indent_str() << "return d.callback(result.success)" << endl; } else { f_service_ << indent() << indent_str() << "return result.success" << endl; } } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { const string& xname = (*x_iter)->get_name(); f_service_ << indent() << "if result." << xname << " is not None:" << endl; if (gen_twisted_) { f_service_ << indent() << indent_str() << "return d.errback(result." << xname << ")" << endl; } else { f_service_ << indent() << indent_str() << "raise result." << xname << "" << endl; } } // Careful, only return _result if not a void function if ((*f_iter)->get_returntype()->is_void()) { if (gen_twisted_) { f_service_ << indent() << "return d.callback(None)" << endl; } else { f_service_ << indent() << "return" << endl; } } else { if (gen_twisted_) { f_service_ << indent() << "return d.errback(TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl; } else { f_service_ << indent() << "raise TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\")" << endl; } } // Close function indent_down(); } } indent_down(); } /** * Generates a command line tool for making remote requests * * @param tservice The service to generate a remote for. */ void t_py_generator::generate_service_remote(t_service* tservice) { vector functions = tservice->get_functions(); // Get all function from parents t_service* parent = tservice->get_extends(); while (parent != nullptr) { vector p_functions = parent->get_functions(); functions.insert(functions.end(), p_functions.begin(), p_functions.end()); parent = parent->get_extends(); } vector::iterator f_iter; string f_remote_name = package_dir_ + "/" + service_name_ + "-remote"; ofstream_with_content_based_conditional_update f_remote; f_remote.open(f_remote_name.c_str()); f_remote << "#!/usr/bin/env python" << endl << py_autogen_comment() << endl << "import sys" << endl << "import pprint" << endl << "if sys.version_info[0] > 2:" << endl << indent_str() << "from urllib.parse import urlparse" << endl << "else:" << endl << indent_str() << "from urlparse import urlparse" << endl << "from thrift.transport import TTransport, TSocket, TSSLSocket, THttpClient" << endl << "from thrift.protocol.TBinaryProtocol import TBinaryProtocol" << endl << endl; f_remote << "from " << module_ << " import " << service_name_ << endl << "from " << module_ << ".ttypes import *" << endl << endl; f_remote << "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl << indent_str() << "print('')" << endl << indent_str() << "print('Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] [-s[sl]] [-novalidate] [-ca_certs certs] [-keyfile keyfile] [-certfile certfile] function [arg1 [arg2...]]')" << endl << indent_str() << "print('')" << endl << indent_str() << "print('Functions:')" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_remote << indent_str() << "print(' " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "("; t_struct* arg_struct = (*f_iter)->get_arglist(); const std::vector& args = arg_struct->get_members(); std::vector::size_type num_args = args.size(); bool first = true; for (std::vector::size_type i = 0; i < num_args; ++i) { if (first) { first = false; } else { f_remote << ", "; } f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name(); } f_remote << ")')" << endl; } f_remote << indent_str() << "print('')" << endl << indent_str() << "sys.exit(0)" << endl << endl; f_remote << "pp = pprint.PrettyPrinter(indent=2)" << endl << "host = 'localhost'" << endl << "port = 9090" << endl << "uri = ''" << endl << "framed = False" << endl << "ssl = False" << endl << "validate = True" << endl << "ca_certs = None" << endl << "keyfile = None" << endl << "certfile = None" << endl << "http = False" << endl << "argi = 1" << endl << endl << "if sys.argv[argi] == '-h':" << endl << indent_str() << "parts = sys.argv[argi + 1].split(':')" << endl << indent_str() << "host = parts[0]" << endl << indent_str() << "if len(parts) > 1:" << endl << indent_str() << indent_str() << "port = int(parts[1])" << endl << indent_str() << "argi += 2" << endl << endl << "if sys.argv[argi] == '-u':" << endl << indent_str() << "url = urlparse(sys.argv[argi + 1])" << endl << indent_str() << "parts = url[1].split(':')" << endl << indent_str() << "host = parts[0]" << endl << indent_str() << "if len(parts) > 1:" << endl << indent_str() << indent_str() << "port = int(parts[1])" << endl << indent_str() << "else:" << endl << indent_str() << indent_str() << "port = 80" << endl << indent_str() << "uri = url[2]" << endl << indent_str() << "if url[4]:" << endl << indent_str() << indent_str() << "uri += '?%s' % url[4]" << endl << indent_str() << "http = True" << endl << indent_str() << "argi += 2" << endl << endl << "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl << indent_str() << "framed = True" << endl << indent_str() << "argi += 1" << endl << endl << "if sys.argv[argi] == '-s' or sys.argv[argi] == '-ssl':" << endl << indent_str() << "ssl = True" << endl << indent_str() << "argi += 1" << endl << endl << "if sys.argv[argi] == '-novalidate':" << endl << indent_str() << "validate = False" << endl << indent_str() << "argi += 1" << endl << endl << "if sys.argv[argi] == '-ca_certs':" << endl << indent_str() << "ca_certs = sys.argv[argi+1]" << endl << indent_str() << "argi += 2" << endl << endl << "if sys.argv[argi] == '-keyfile':" << endl << indent_str() << "keyfile = sys.argv[argi+1]" << endl << indent_str() << "argi += 2" << endl << endl << "if sys.argv[argi] == '-certfile':" << endl << indent_str() << "certfile = sys.argv[argi+1]" << endl << indent_str() << "argi += 2" << endl << endl << "cmd = sys.argv[argi]" << endl << "args = sys.argv[argi + 1:]" << endl << endl << "if http:" << endl << indent_str() << "transport = THttpClient.THttpClient(host, port, uri)" << endl << "else:" << endl << indent_str() << "if ssl:" << endl << indent_str() << indent_str() << "socket = TSSLSocket.TSSLSocket(host, port, " "validate=validate, ca_certs=ca_certs, keyfile=keyfile, certfile=certfile)" << endl << indent_str() << "else:" << endl << indent_str() << indent_str() << "socket = TSocket.TSocket(host, port)" << endl << indent_str() << "if framed:" << endl << indent_str() << indent_str() << "transport = TTransport.TFramedTransport(socket)" << endl << indent_str() << "else:" << endl << indent_str() << indent_str() << "transport = TTransport.TBufferedTransport(socket)" << endl << "protocol = TBinaryProtocol(transport)" << endl << "client = " << service_name_ << ".Client(protocol)" << endl << "transport.open()" << endl << endl; // Generate the dispatch methods bool first = true; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { if (first) { first = false; } else { f_remote << "el"; } t_struct* arg_struct = (*f_iter)->get_arglist(); const std::vector& args = arg_struct->get_members(); std::vector::size_type num_args = args.size(); f_remote << "if cmd == '" << (*f_iter)->get_name() << "':" << endl; indent_up(); f_remote << indent() << "if len(args) != " << num_args << ":" << endl << indent() << indent_str() << "print('" << (*f_iter)->get_name() << " requires " << num_args << " args')" << endl << indent() << indent_str() << "sys.exit(1)" << endl << indent() << "pp.pprint(client." << (*f_iter)->get_name() << "("; indent_down(); bool first_arg = true; for (std::vector::size_type i = 0; i < num_args; ++i) { if (first_arg) first_arg = false; else f_remote << " "; if (args[i]->get_type()->is_string()) { f_remote << "args[" << i << "],"; } else { f_remote << "eval(args[" << i << "]),"; } } f_remote << "))" << endl; f_remote << endl; } if (functions.size() > 0) { f_remote << "else:" << endl; f_remote << indent_str() << "print('Unrecognized method %s' % cmd)" << endl; f_remote << indent_str() << "sys.exit(1)" << endl; f_remote << endl; } f_remote << "transport.close()" << endl; // Close service file f_remote.close(); #ifndef _MSC_VER // Make file executable, love that bitwise OR action chmod(f_remote_name.c_str(), S_IRUSR | S_IWUSR | S_IXUSR #ifndef _WIN32 | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH #endif ); #endif // _MSC_VER } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_py_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_processor = ""; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_processor = extends + ".Processor, "; } f_service_ << endl << endl; // Generate the header portion if (gen_zope_interface_) { f_service_ << "@implementer(Iface)" << endl << "class Processor(" << extends_processor << "TProcessor):" << endl; } else { f_service_ << "class Processor(" << extends_processor << "Iface, TProcessor):" << endl; } indent_up(); indent(f_service_) << "def __init__(self, handler):" << endl; indent_up(); if (extends.empty()) { if (gen_zope_interface_) { f_service_ << indent() << "self._handler = Iface(handler)" << endl; } else { f_service_ << indent() << "self._handler = handler" << endl; } f_service_ << indent() << "self._processMap = {}" << endl; } else { if (gen_zope_interface_) { f_service_ << indent() << extends << ".Processor.__init__(self, Iface(handler))" << endl; } else { f_service_ << indent() << extends << ".Processor.__init__(self, handler)" << endl; } } for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << indent() << "self._processMap[\"" << (*f_iter)->get_name() << "\"] = Processor.process_" << (*f_iter)->get_name() << endl; } f_service_ << indent() << "self._on_message_begin = None" << endl; indent_down(); f_service_ << endl; f_service_ << indent() << "def on_message_begin(self, func):" << endl; indent_up(); f_service_ << indent() << "self._on_message_begin = func" << endl; indent_down(); f_service_ << endl; // Generate the server implementation f_service_ << indent() << "def process(self, iprot, oprot):" << endl; indent_up(); f_service_ << indent() << "(name, type, seqid) = iprot.readMessageBegin()" << endl; f_service_ << indent() << "if self._on_message_begin:" << endl; indent_up(); f_service_ << indent() << "self._on_message_begin(name, type, seqid)" << endl; indent_down(); // TODO(mcslee): validate message // HOT: dictionary function lookup f_service_ << indent() << "if name not in self._processMap:" << endl; indent_up(); f_service_ << indent() << "iprot.skip(TType.STRUCT)" << endl << indent() << "iprot.readMessageEnd()" << endl << indent() << "x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown " "function %s' % (name))" << endl << indent() << "oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)" << endl << indent() << "x.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()" << endl << indent() << "oprot.trans.flush()" << endl; if (gen_twisted_) { f_service_ << indent() << "return defer.succeed(None)" << endl; } else { f_service_ << indent() << "return" << endl; } indent_down(); f_service_ << indent() << "else:" << endl; if (gen_twisted_ || gen_tornado_) { f_service_ << indent() << indent_str() << "return self._processMap[name](self, seqid, iprot, oprot)" << endl; } else { f_service_ << indent() << indent_str() << "self._processMap[name](self, seqid, iprot, oprot)" << endl; // Read end of args field, the T_STOP, and the struct close f_service_ << indent() << "return True" << endl; } indent_down(); // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << endl; generate_process_function(tservice, *f_iter); } indent_down(); } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_py_generator::generate_process_function(t_service* tservice, t_function* tfunction) { (void)tservice; // Open function if (gen_tornado_) { f_service_ << indent() << "@gen.coroutine" << endl << indent() << "def process_" << tfunction->get_name() << "(self, seqid, iprot, oprot):" << endl; } else { f_service_ << indent() << "def process_" << tfunction->get_name() << "(self, seqid, iprot, oprot):" << endl; } indent_up(); string argsname = tfunction->get_name() + "_args"; string resultname = tfunction->get_name() + "_result"; f_service_ << indent() << "args = " << argsname << "()" << endl << indent() << "args.read(iprot)" << endl << indent() << "iprot.readMessageEnd()" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Declare result for non oneway function if (!tfunction->is_oneway()) { f_service_ << indent() << "result = " << resultname << "()" << endl; } if (gen_twisted_) { // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent() << "d = defer.maybeDeferred(self._handler." << tfunction->get_name() << ", "; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ")" << endl; if (tfunction->is_oneway()) { f_service_ << indent() << "d.addErrback(self.handle_exception_" << tfunction->get_name() << ", seqid)" << endl; } else { f_service_ << indent() << "d.addCallback(self.write_results_success_" << tfunction->get_name() << ", result, seqid, oprot)" << endl << indent() << "d.addErrback(self.write_results_exception_" << tfunction->get_name() << ", result, seqid, oprot)" << endl; } f_service_ << indent() << "return d" << endl << endl; indent_down(); if (tfunction->is_oneway()) { indent(f_service_) << "def handle_exception_" << tfunction->get_name() << "(self, error, seqid):" << endl; } else { indent(f_service_) << "def write_results_success_" << tfunction->get_name() << "(self, success, result, seqid, oprot):" << endl; indent_up(); if (!tfunction->get_returntype()->is_void()) { f_service_ << indent() << "result.success = success" << endl; } f_service_ << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl << indent() << "result.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()" << endl << indent() << "oprot.trans.flush()" << endl << endl; indent_down(); indent(f_service_) << "def write_results_exception_" << tfunction->get_name() << "(self, error, result, seqid, oprot):" << endl; } indent_up(); if (!tfunction->is_oneway()) { f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl; } f_service_ << indent() << "try:" << endl; // Kinda absurd f_service_ << indent() << indent_str() << "error.raiseException()" << endl; if (!tfunction->is_oneway()) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { const string& xname = (*x_iter)->get_name(); f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname << ":" << endl; indent_up(); f_service_ << indent() << "result." << xname << " = " << xname << endl; indent_down(); } } f_service_ << indent() << "except TTransport.TTransportException:" << endl << indent() << indent_str() << "raise" << endl; if (!tfunction->is_oneway()) { f_service_ << indent() << "except TApplicationException as ex:" << endl << indent() << indent_str() << "logging.exception('TApplication exception in handler')" << endl << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl << indent() << indent_str() << "result = ex" << endl << indent() << "except Exception:" << endl << indent() << indent_str() << "logging.exception('Unexpected exception in handler')" << endl << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl << indent() << indent_str() << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, " "'Internal error')" << endl << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", msg_type, seqid)" << endl << indent() << "result.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()" << endl << indent() << "oprot.trans.flush()" << endl; } else { f_service_ << indent() << "except Exception:" << endl << indent() << indent_str() << "logging.exception('Exception in oneway handler')" << endl; } indent_down(); } else if (gen_tornado_) { // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; if (!tfunction->is_oneway()) { indent(f_service_) << "msg_type = TMessageType.REPLY" << endl; } f_service_ << indent() << "try:" << endl; indent_up(); f_service_ << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_service_ << "result.success = "; } f_service_ << "yield gen.maybe_future(self._handler." << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << "))" << endl; indent_down(); if (!tfunction->is_oneway()) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { const string& xname = (*x_iter)->get_name(); f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname << ":" << endl << indent() << indent_str() << "result." << xname << " = " << xname << endl; } } f_service_ << indent() << "except TTransport.TTransportException:" << endl << indent() << indent_str() << "raise" << endl; if (!tfunction->is_oneway()) { f_service_ << indent() << "except TApplicationException as ex:" << endl << indent() << indent_str() << "logging.exception('TApplication exception in handler')" << endl << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl << indent() << indent_str() << "result = ex" << endl << indent() << "except Exception:" << endl << indent() << indent_str() << "logging.exception('Unexpected exception in handler')" << endl << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl << indent() << indent_str() << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, " "'Internal error')" << endl; } else { f_service_ << indent() << "except Exception:" << endl << indent() << indent_str() << "logging.exception('Exception in oneway handler')" << endl; } if (!tfunction->is_oneway()) { f_service_ << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", msg_type, seqid)" << endl << indent() << "result.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()" << endl << indent() << "oprot.trans.flush()" << endl; } // Close function indent_down(); } else { // py // Try block for a function with exceptions // It also catches arbitrary exceptions raised by handler method to propagate them to the client f_service_ << indent() << "try:" << endl; indent_up(); // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_ << indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_service_ << "result.success = "; } f_service_ << "self._handler." << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ")" << endl; if (!tfunction->is_oneway()) { f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl; } indent_down(); f_service_ << indent() << "except TTransport.TTransportException:" << endl << indent() << indent_str() << "raise" << endl; if (!tfunction->is_oneway()) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { const string& xname = (*x_iter)->get_name(); f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname << ":" << endl; indent_up(); f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl; f_service_ << indent() << "result." << xname << " = " << xname << endl; indent_down(); } f_service_ << indent() << "except TApplicationException as ex:" << endl << indent() << indent_str() << "logging.exception('TApplication exception in handler')" << endl << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl << indent() << indent_str() << "result = ex" << endl << indent() << "except Exception:" << endl << indent() << indent_str() << "logging.exception('Unexpected exception in handler')" << endl << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl << indent() << indent_str() << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, " "'Internal error')" << endl << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", msg_type, seqid)" << endl << indent() << "result.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()" << endl << indent() << "oprot.trans.flush()" << endl; } else { f_service_ << indent() << "except Exception:" << endl << indent() << indent_str() << "logging.exception('Exception in oneway handler')" << endl; } // Close function indent_down(); } } /** * Deserializes a field of any type. */ void t_py_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); if (type->is_void()) { throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } string name = prefix + tfield->get_name(); if (type->is_struct() || type->is_xception()) { generate_deserialize_struct(out, (t_struct*)type, name); } else if (type->is_container()) { generate_deserialize_container(out, type, name); } else if (type->is_base_type() || type->is_enum()) { indent(out) << name << " = iprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "readBinary()"; } else if(!gen_utf8strings_) { out << "readString()"; } else { out << "readString().decode('utf-8', errors='replace') if sys.version_info[0] == 2 else iprot.readString()"; } break; case t_base_type::TYPE_BOOL: out << "readBool()"; break; case t_base_type::TYPE_I8: out << "readByte()"; break; case t_base_type::TYPE_I16: out << "readI16()"; break; case t_base_type::TYPE_I32: out << "readI32()"; break; case t_base_type::TYPE_I64: out << "readI64()"; break; case t_base_type::TYPE_DOUBLE: out << "readDouble()"; break; default: throw "compiler error: no Python name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "readI32()"; } out << endl; } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type->get_name().c_str()); } } /** * Generates an unserializer for a struct, calling read() */ void t_py_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) { if (is_immutable(tstruct)) { out << indent() << prefix << " = " << type_name(tstruct) << ".read(iprot)" << endl; } else { out << indent() << prefix << " = " << type_name(tstruct) << "()" << endl << indent() << prefix << ".read(iprot)" << endl; } } /** * Serialize a container by writing out the header followed by * data and then a footer. */ void t_py_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { string size = tmp("_size"); string ktype = tmp("_ktype"); string vtype = tmp("_vtype"); string etype = tmp("_etype"); t_field fsize(g_type_i32, size); t_field fktype(g_type_i8, ktype); t_field fvtype(g_type_i8, vtype); t_field fetype(g_type_i8, etype); // Declare variables, read header if (ttype->is_map()) { out << indent() << prefix << " = {}" << endl << indent() << "(" << ktype << ", " << vtype << ", " << size << ") = iprot.readMapBegin()" << endl; } else if (ttype->is_set()) { out << indent() << prefix << " = set()" << endl << indent() << "(" << etype << ", " << size << ") = iprot.readSetBegin()" << endl; } else if (ttype->is_list()) { out << indent() << prefix << " = []" << endl << indent() << "(" << etype << ", " << size << ") = iprot.readListBegin()" << endl; } // For loop iterates over elements string i = tmp("_i"); indent(out) << "for " << i << " in range(" << size << "):" << endl; indent_up(); if (ttype->is_map()) { generate_deserialize_map_element(out, (t_map*)ttype, prefix); } else if (ttype->is_set()) { generate_deserialize_set_element(out, (t_set*)ttype, prefix); } else if (ttype->is_list()) { generate_deserialize_list_element(out, (t_list*)ttype, prefix); } indent_down(); // Read container end if (ttype->is_map()) { indent(out) << "iprot.readMapEnd()" << endl; if (is_immutable(ttype)) { indent(out) << prefix << " = TFrozenDict(" << prefix << ")" << endl; } } else if (ttype->is_set()) { indent(out) << "iprot.readSetEnd()" << endl; if (is_immutable(ttype)) { indent(out) << prefix << " = frozenset(" << prefix << ")" << endl; } } else if (ttype->is_list()) { if (is_immutable(ttype)) { indent(out) << prefix << " = tuple(" << prefix << ")" << endl; } indent(out) << "iprot.readListEnd()" << endl; } } /** * Generates code to deserialize a map */ void t_py_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); indent(out) << prefix << "[" << key << "] = " << val << endl; } /** * Write a set element */ void t_py_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); generate_deserialize_field(out, &felem); indent(out) << prefix << ".add(" << elem << ")" << endl; } /** * Write a list element */ void t_py_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); generate_deserialize_field(out, &felem); indent(out) << prefix << ".append(" << elem << ")" << endl; } /** * Serializes a field of any type. * * @param tfield The field to serialize * @param prefix Name to prepend to field name */ void t_py_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { t_type* type = get_true_type(tfield->get_type()); // Do nothing for void types if (type->is_void()) { throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); } if (type->is_struct() || type->is_xception()) { generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); } else if (type->is_container()) { generate_serialize_container(out, type, prefix + tfield->get_name()); } else if (type->is_base_type() || type->is_enum()) { string name = prefix + tfield->get_name(); indent(out) << "oprot."; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "compiler error: cannot serialize void field in a struct: " + name; break; case t_base_type::TYPE_STRING: if (type->is_binary()) { out << "writeBinary(" << name << ")"; } else if (!gen_utf8strings_) { out << "writeString(" << name << ")"; } else { out << "writeString(" << name << ".encode('utf-8') if sys.version_info[0] == 2 else " << name << ")"; } break; case t_base_type::TYPE_BOOL: out << "writeBool(" << name << ")"; break; case t_base_type::TYPE_I8: out << "writeByte(" << name << ")"; break; case t_base_type::TYPE_I16: out << "writeI16(" << name << ")"; break; case t_base_type::TYPE_I32: out << "writeI32(" << name << ")"; break; case t_base_type::TYPE_I64: out << "writeI64(" << name << ")"; break; case t_base_type::TYPE_DOUBLE: out << "writeDouble(" << name << ")"; break; default: throw "compiler error: no Python name for base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << "writeI32(" << name << ")"; } out << endl; } else { printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type->get_name().c_str()); } } /** * Serializes all the members of a struct. * * @param tstruct The struct to serialize * @param prefix String prefix to attach to all fields */ void t_py_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { (void)tstruct; indent(out) << prefix << ".write(oprot)" << endl; } void t_py_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { if (ttype->is_map()) { indent(out) << "oprot.writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "len(" << prefix << "))" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << "len(" << prefix << "))" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << "len(" << prefix << "))" << endl; } if (ttype->is_map()) { string kiter = tmp("kiter"); string viter = tmp("viter"); indent(out) << "for " << kiter << ", " << viter << " in " << prefix << ".items():" << endl; indent_up(); generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); indent_down(); } else if (ttype->is_set()) { string iter = tmp("iter"); indent(out) << "for " << iter << " in " << prefix << ":" << endl; indent_up(); generate_serialize_set_element(out, (t_set*)ttype, iter); indent_down(); } else if (ttype->is_list()) { string iter = tmp("iter"); indent(out) << "for " << iter << " in " << prefix << ":" << endl; indent_up(); generate_serialize_list_element(out, (t_list*)ttype, iter); indent_down(); } if (ttype->is_map()) { indent(out) << "oprot.writeMapEnd()" << endl; } else if (ttype->is_set()) { indent(out) << "oprot.writeSetEnd()" << endl; } else if (ttype->is_list()) { indent(out) << "oprot.writeListEnd()" << endl; } } /** * Serializes the members of a map. * */ void t_py_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter) { t_field kfield(tmap->get_key_type(), kiter); generate_serialize_field(out, &kfield, ""); t_field vfield(tmap->get_val_type(), viter); generate_serialize_field(out, &vfield, ""); } /** * Serializes the members of a set. */ void t_py_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { t_field efield(tset->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Serializes the members of a list. */ void t_py_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { t_field efield(tlist->get_elem_type(), iter); generate_serialize_field(out, &efield, ""); } /** * Generates the docstring for a given struct. */ void t_py_generator::generate_python_docstring(ostream& out, t_struct* tstruct) { generate_python_docstring(out, tstruct, tstruct, "Attributes"); } /** * Generates the docstring for a given function. */ void t_py_generator::generate_python_docstring(ostream& out, t_function* tfunction) { generate_python_docstring(out, tfunction, tfunction->get_arglist(), "Parameters"); } /** * Generates the docstring for a struct or function. */ void t_py_generator::generate_python_docstring(ostream& out, t_doc* tdoc, t_struct* tstruct, const char* subheader) { bool has_doc = false; stringstream ss; if (tdoc->has_doc()) { has_doc = true; ss << tdoc->get_doc(); } const vector& fields = tstruct->get_members(); if (fields.size() > 0) { if (has_doc) { ss << endl; } has_doc = true; ss << subheader << ":\n"; vector::const_iterator p_iter; for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { t_field* p = *p_iter; ss << " - " << p->get_name(); if (p->has_doc()) { ss << ": " << p->get_doc(); } else { ss << endl; } } } if (has_doc) { generate_docstring_comment(out, "\"\"\"\n", "", ss.str(), "\"\"\"\n"); } } /** * Generates the docstring for a generic object. */ void t_py_generator::generate_python_docstring(ostream& out, t_doc* tdoc) { if (tdoc->has_doc()) { generate_docstring_comment(out, "\"\"\"\n", "", tdoc->get_doc(), "\"\"\"\n"); } } /** * Declares an argument, which may include initialization as necessary. * * @param tfield The field */ string t_py_generator::declare_argument(t_field* tfield) { std::ostringstream result; result << tfield->get_name() << "="; if (tfield->get_value() != nullptr) { result << render_field_default_value(tfield); } else { result << "None"; } return result.str(); } /** * Renders a field default value, returns None otherwise. * * @param tfield The field */ string t_py_generator::render_field_default_value(t_field* tfield) { t_type* type = get_true_type(tfield->get_type()); if (tfield->get_value() != nullptr) { return render_const_value(type, tfield->get_value()); } else { return "None"; } } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_py_generator::function_signature(t_function* tfunction, bool interface) { vector pre; vector post; string signature = tfunction->get_name() + "("; if (!(gen_zope_interface_ && interface)) { pre.emplace_back("self"); } signature += argument_list(tfunction->get_arglist(), &pre, &post) + ")"; return signature; } /** * Renders a field list */ string t_py_generator::argument_list(t_struct* tstruct, vector* pre, vector* post) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; vector::const_iterator s_iter; bool first = true; if (pre) { for (s_iter = pre->begin(); s_iter != pre->end(); ++s_iter) { if (first) { first = false; } else { result += ", "; } result += *s_iter; } } for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += (*f_iter)->get_name(); } if (post) { for (s_iter = post->begin(); s_iter != post->end(); ++s_iter) { if (first) { first = false; } else { result += ", "; } result += *s_iter; } } return result; } string t_py_generator::type_name(t_type* ttype) { while (ttype->is_typedef()) { ttype = ((t_typedef*)ttype)->get_type(); } t_program* program = ttype->get_program(); if (ttype->is_service()) { return get_real_py_module(program, gen_twisted_, package_prefix_) + "." + ttype->get_name(); } if (program != nullptr && program != program_) { return get_real_py_module(program, gen_twisted_, package_prefix_) + ".ttypes." + ttype->get_name(); } return ttype->get_name(); } /** * Converts the parse type to a Python tyoe */ string t_py_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType.STRING"; case t_base_type::TYPE_BOOL: return "TType.BOOL"; case t_base_type::TYPE_I8: return "TType.BYTE"; case t_base_type::TYPE_I16: return "TType.I16"; case t_base_type::TYPE_I32: return "TType.I32"; case t_base_type::TYPE_I64: return "TType.I64"; case t_base_type::TYPE_DOUBLE: return "TType.DOUBLE"; } } else if (type->is_enum()) { return "TType.I32"; } else if (type->is_struct() || type->is_xception()) { return "TType.STRUCT"; } else if (type->is_map()) { return "TType.MAP"; } else if (type->is_set()) { return "TType.SET"; } else if (type->is_list()) { return "TType.LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } /** See the comment inside generate_py_struct_definition for what this is. */ string t_py_generator::type_to_spec_args(t_type* ttype) { while (ttype->is_typedef()) { ttype = ((t_typedef*)ttype)->get_type(); } if (ttype->is_binary()) { return "'BINARY'"; } else if (gen_utf8strings_ && ttype->is_base_type() && reinterpret_cast(ttype)->is_string()) { return "'UTF8'"; } else if (ttype->is_base_type() || ttype->is_enum()) { return "None"; } else if (ttype->is_struct() || ttype->is_xception()) { return "[" + type_name(ttype) + ", None]"; } else if (ttype->is_map()) { return "(" + type_to_enum(((t_map*)ttype)->get_key_type()) + ", " + type_to_spec_args(((t_map*)ttype)->get_key_type()) + ", " + type_to_enum(((t_map*)ttype)->get_val_type()) + ", " + type_to_spec_args(((t_map*)ttype)->get_val_type()) + ", " + (is_immutable(ttype) ? "True" : "False") + ")"; } else if (ttype->is_set()) { return "(" + type_to_enum(((t_set*)ttype)->get_elem_type()) + ", " + type_to_spec_args(((t_set*)ttype)->get_elem_type()) + ", " + (is_immutable(ttype) ? "True" : "False") + ")"; } else if (ttype->is_list()) { return "(" + type_to_enum(((t_list*)ttype)->get_elem_type()) + ", " + type_to_spec_args(((t_list*)ttype)->get_elem_type()) + ", " + (is_immutable(ttype) ? "True" : "False") + ")"; } throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name(); } THRIFT_REGISTER_GENERATOR( py, "Python", " zope.interface: Generate code for use with zope.interface.\n" " twisted: Generate Twisted-friendly RPC services.\n" " tornado: Generate code for use with Tornado.\n" " no_utf8strings: Do not Encode/decode strings using utf8 in the generated code. Basically no effect for Python 3.\n" " coding=CODING: Add file encoding declare in generated file.\n" " slots: Generate code using slots for instance members.\n" " dynamic: Generate dynamic code, less code generated but slower.\n" " dynbase=CLS Derive generated classes from class CLS instead of TBase.\n" " dynfrozen=CLS Derive generated immutable classes from class CLS instead of TFrozenBase.\n" " dynexc=CLS Derive generated exceptions from CLS instead of TExceptionBase.\n" " dynfrozenexc=CLS Derive generated immutable exceptions from CLS instead of TFrozenExceptionBase.\n" " dynimport='from foo.bar import CLS'\n" " Add an import line to generated code to find the dynbase class.\n" " package_prefix='top.package.'\n" " Package prefix for generated files.\n" " old_style: Deprecated. Generate old-style classes.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_rb_generator.cc000066400000000000000000001224631420101504100246520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ofstream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * A subclass of std::ofstream that includes indenting functionality. */ class t_rb_ofstream : public std::ofstream { private: int indent_; public: t_rb_ofstream() : std::ofstream(), indent_(0) {} explicit t_rb_ofstream(const char* filename, ios_base::openmode mode = ios_base::out, int indent = 0) : std::ofstream(filename, mode), indent_(indent) {} t_rb_ofstream& indent() { for (int i = 0; i < indent_; ++i) { *this << " "; } return *this; } void indent_up() { indent_++; } void indent_down() { indent_--; } }; /** * Ruby code generator. * */ class t_rb_generator : public t_oop_generator { public: t_rb_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; std::map::const_iterator iter; require_rubygems_ = false; namespaced_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("rubygems") == 0) { require_rubygems_ = true; } else if( iter->first.compare("namespaced") == 0) { namespaced_ = true; } else { throw "unknown option ruby:" + iter->first; } } out_dir_base_ = "gen-rb"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_forward_declaration(t_struct* tstruct) override; void generate_union(t_struct* tunion); void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; t_rb_ofstream& render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value); /** * Struct generation code */ void generate_rb_struct_declaration(t_rb_ofstream& out, t_struct* tstruct, bool is_exception); void generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception); void generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct); void generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception); void generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct); void generate_rb_function_helpers(t_function* tfunction); void generate_rb_simple_constructor(t_rb_ofstream& out, t_struct* tstruct); void generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct); void generate_field_constants(t_rb_ofstream& out, t_struct* tstruct); void generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct); void generate_field_defns(t_rb_ofstream& out, t_struct* tstruct); void generate_field_data(t_rb_ofstream& out, t_type* field_type, const std::string& field_name, t_const_value* field_value, bool optional); /** * Service-level generation functions */ void generate_service_helpers(t_service* tservice); void generate_service_interface(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); /** * Serialization constructs */ void generate_deserialize_field(t_rb_ofstream& out, t_field* tfield, std::string prefix = "", bool inclass = false); void generate_deserialize_struct(t_rb_ofstream& out, t_struct* tstruct, std::string prefix = ""); void generate_deserialize_container(t_rb_ofstream& out, t_type* ttype, std::string prefix = ""); void generate_deserialize_set_element(t_rb_ofstream& out, t_set* tset, std::string prefix = ""); void generate_deserialize_map_element(t_rb_ofstream& out, t_map* tmap, std::string prefix = ""); void generate_deserialize_list_element(t_rb_ofstream& out, t_list* tlist, std::string prefix = ""); void generate_serialize_field(t_rb_ofstream& out, t_field* tfield, std::string prefix = ""); void generate_serialize_struct(t_rb_ofstream& out, t_struct* tstruct, std::string prefix = ""); void generate_serialize_container(t_rb_ofstream& out, t_type* ttype, std::string prefix = ""); void generate_serialize_map_element(t_rb_ofstream& out, t_map* tmap, std::string kiter, std::string viter); void generate_serialize_set_element(t_rb_ofstream& out, t_set* tmap, std::string iter); void generate_serialize_list_element(t_rb_ofstream& out, t_list* tlist, std::string iter); void generate_rdoc(t_rb_ofstream& out, t_doc* tdoc); /** * Helper rendering functions */ std::string rb_autogen_comment(); std::string render_require_thrift(); std::string render_includes(); std::string declare_field(t_field* tfield); std::string type_name(const t_type* ttype); std::string full_type_name(const t_type* ttype); std::string function_signature(t_function* tfunction, std::string prefix = ""); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string rb_namespace_to_path_prefix(std::string rb_namespace); std::vector ruby_modules(const t_program* p) { std::string ns = p->get_namespace("rb"); std::vector modules; if (ns.empty()) { return modules; } std::string::iterator pos = ns.begin(); while (true) { std::string::iterator delim = std::find(pos, ns.end(), '.'); modules.push_back(capitalize(std::string(pos, delim))); pos = delim; if (pos == ns.end()) { break; } ++pos; } return modules; } void begin_namespace(t_rb_ofstream&, std::vector); void end_namespace(t_rb_ofstream&, std::vector); private: /** * File streams */ t_rb_ofstream f_types_; t_rb_ofstream f_consts_; t_rb_ofstream f_service_; std::string namespace_dir_; std::string require_prefix_; /** If true, add a "require 'rubygems'" line to the top of each gen-rb file. */ bool require_rubygems_; /** If true, generate files in idiomatic namespaced directories. */ bool namespaced_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_rb_generator::init_generator() { string subdir = get_out_dir(); // Make output directory MKDIR(subdir.c_str()); if (namespaced_) { require_prefix_ = rb_namespace_to_path_prefix(program_->get_namespace("rb")); string dir = require_prefix_; string::size_type loc; while ((loc = dir.find("/")) != string::npos) { subdir = subdir + dir.substr(0, loc) + "/"; MKDIR(subdir.c_str()); dir = dir.substr(loc + 1); } } namespace_dir_ = subdir; // Make output file string f_types_name = namespace_dir_ + underscore(program_name_) + "_types.rb"; f_types_.open(f_types_name.c_str()); string f_consts_name = namespace_dir_ + underscore(program_name_) + "_constants.rb"; f_consts_.open(f_consts_name.c_str()); // Print header f_types_ << rb_autogen_comment() << endl << render_require_thrift() << render_includes() << endl; begin_namespace(f_types_, ruby_modules(program_)); f_consts_ << rb_autogen_comment() << endl << render_require_thrift() << "require '" << require_prefix_ << underscore(program_name_) << "_types'" << endl << endl; begin_namespace(f_consts_, ruby_modules(program_)); } /** * Renders the require of thrift itself, and possibly of the rubygems dependency. */ string t_rb_generator::render_require_thrift() { if (require_rubygems_) { return "require 'rubygems'\nrequire 'thrift'\n"; } else { return "require 'thrift'\n"; } } /** * Renders all the imports necessary for including another Thrift program */ string t_rb_generator::render_includes() { const vector& includes = program_->get_includes(); string result = ""; for (auto include : includes) { if (namespaced_) { t_program* included = include; std::string included_require_prefix = rb_namespace_to_path_prefix(included->get_namespace("rb")); std::string included_name = included->get_name(); result += "require '" + included_require_prefix + underscore(included_name) + "_types'\n"; } else { result += "require '" + underscore(include->get_name()) + "_types'\n"; } } if (includes.size() > 0) { result += "\n"; } return result; } /** * Autogen'd comment */ string t_rb_generator::rb_autogen_comment() { return std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n"; } /** * Closes the type files */ void t_rb_generator::close_generator() { // Close types file end_namespace(f_types_, ruby_modules(program_)); end_namespace(f_consts_, ruby_modules(program_)); f_types_.close(); f_consts_.close(); } /** * Generates a typedef. This is not done in Ruby, types are all implicit. * * @param ttypedef The type definition */ void t_rb_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } /** * Generates code for an enumerated type. Done using a class to scope * the values. * * @param tenum The enumeration */ void t_rb_generator::generate_enum(t_enum* tenum) { f_types_.indent() << "module " << capitalize(tenum->get_name()) << endl; f_types_.indent_up(); vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); // Ruby class constants have to be capitalized... omg i am so on the fence // about languages strictly enforcing capitalization why can't we just all // agree and play nice. string name = capitalize((*c_iter)->get_name()); generate_rdoc(f_types_, *c_iter); f_types_.indent() << name << " = " << value << endl; } // Create a hash mapping values back to their names (as strings) since ruby has no native enum // type f_types_.indent() << "VALUE_MAP = {"; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { // Populate the hash int value = (*c_iter)->get_value(); if (c_iter != constants.begin()) f_types_ << ", "; f_types_ << value << " => \"" << capitalize((*c_iter)->get_name()) << "\""; } f_types_ << "}" << endl; // Create a set with valid values for this enum f_types_.indent() << "VALID_VALUES = Set.new(["; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { // Populate the set if (c_iter != constants.begin()) f_types_ << ", "; f_types_ << capitalize((*c_iter)->get_name()); } f_types_ << "]).freeze" << endl; f_types_.indent_down(); f_types_.indent() << "end" << endl << endl; } /** * Generate a constant value */ void t_rb_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); name[0] = toupper(name[0]); f_consts_.indent() << name << " = "; render_const_value(f_consts_, type, value) << endl << endl; } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ t_rb_ofstream& t_rb_generator::render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << "%q\"" << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out.indent() << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << full_type_name(type) << ".new({" << endl; out.indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } out.indent(); render_const_value(out, g_type_string, v_iter->first) << " => "; render_const_value(out, field_type, v_iter->second) << "," << endl; } out.indent_down(); out.indent() << "})"; } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); out << "{" << endl; out.indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out.indent(); render_const_value(out, ktype, v_iter->first) << " => "; render_const_value(out, vtype, v_iter->second) << "," << endl; } out.indent_down(); out.indent() << "}"; } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } if (type->is_set()) { out << "Set.new([" << endl; } else { out << "[" << endl; } out.indent_up(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out.indent(); render_const_value(out, etype, *v_iter) << "," << endl; } out.indent_down(); if (type->is_set()) { out.indent() << "])"; } else { out.indent() << "]"; } } else { throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); } return out; } /** * Generates a ruby struct */ void t_rb_generator::generate_struct(t_struct* tstruct) { if (tstruct->is_union()) { generate_rb_union(f_types_, tstruct, false); } else { generate_rb_struct(f_types_, tstruct, false); } } /** * Generates the "forward declarations" for ruby structs. * These are simply a declaration of each class with proper inheritance. * The rest of the struct is still generated in generate_struct as has * always been the case. These declarations allow thrift to generate valid * ruby in cases where thrift structs rely on recursive definitions. */ void t_rb_generator::generate_forward_declaration(t_struct* tstruct) { generate_rb_struct_declaration(f_types_, tstruct, tstruct->is_xception()); } void t_rb_generator::generate_rb_struct_declaration(t_rb_ofstream& out, t_struct* tstruct, bool is_exception) { out.indent() << "class " << type_name(tstruct); if (tstruct->is_union()) { out << " < ::Thrift::Union"; } if (is_exception) { out << " < ::Thrift::Exception"; } out << "; end" << endl << endl; } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_rb_generator::generate_xception(t_struct* txception) { generate_rb_struct(f_types_, txception, true); } /** * Generates a ruby struct */ void t_rb_generator::generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception = false) { generate_rdoc(out, tstruct); out.indent() << "class " << type_name(tstruct); if (is_exception) { out << " < ::Thrift::Exception"; } out << endl; out.indent_up(); out.indent() << "include ::Thrift::Struct, ::Thrift::Struct_Union" << endl; if (is_exception) { generate_rb_simple_exception_constructor(out, tstruct); } generate_field_constants(out, tstruct); generate_field_defns(out, tstruct); generate_rb_struct_required_validator(out, tstruct); out.indent() << "::Thrift::Struct.generate_accessors self" << endl; out.indent_down(); out.indent() << "end" << endl << endl; } /** * Generates a ruby union */ void t_rb_generator::generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception = false) { (void)is_exception; generate_rdoc(out, tstruct); out.indent() << "class " << type_name(tstruct) << " < ::Thrift::Union" << endl; out.indent_up(); out.indent() << "include ::Thrift::Struct_Union" << endl; generate_field_constructors(out, tstruct); generate_field_constants(out, tstruct); generate_field_defns(out, tstruct); generate_rb_union_validator(out, tstruct); out.indent() << "::Thrift::Union.generate_accessors self" << endl; out.indent_down(); out.indent() << "end" << endl << endl; } void t_rb_generator::generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct) { out.indent() << "class << self" << endl; out.indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (f_iter != fields.begin()) { out << endl; } std::string field_name = (*f_iter)->get_name(); out.indent() << "def " << field_name << "(val)" << endl; out.indent() << " " << tstruct->get_name() << ".new(:" << field_name << ", val)" << endl; out.indent() << "end" << endl; } out.indent_down(); out.indent() << "end" << endl; out << endl; } void t_rb_generator::generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); if (members.size() == 1) { vector::const_iterator m_iter = members.begin(); if ((*m_iter)->get_type()->is_string()) { string name = (*m_iter)->get_name(); out.indent() << "def initialize(message=nil)" << endl; out.indent_up(); out.indent() << "super()" << endl; out.indent() << "self." << name << " = message" << endl; out.indent_down(); out.indent() << "end" << endl << endl; if (name != "message") { out.indent() << "def message; " << name << " end" << endl << endl; } } } } void t_rb_generator::generate_field_constants(t_rb_ofstream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { std::string field_name = (*f_iter)->get_name(); std::string cap_field_name = upcase_string(field_name); out.indent() << cap_field_name << " = " << (*f_iter)->get_key() << endl; } out << endl; } void t_rb_generator::generate_field_defns(t_rb_ofstream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; out.indent() << "FIELDS = {" << endl; out.indent_up(); for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (f_iter != fields.begin()) { out << "," << endl; } // generate the field docstrings within the FIELDS constant. no real better place... generate_rdoc(out, *f_iter); out.indent() << upcase_string((*f_iter)->get_name()) << " => "; generate_field_data(out, (*f_iter)->get_type(), (*f_iter)->get_name(), (*f_iter)->get_value(), (*f_iter)->get_req() == t_field::T_OPTIONAL); } out.indent_down(); out << endl; out.indent() << "}" << endl << endl; out.indent() << "def struct_fields; FIELDS; end" << endl << endl; } void t_rb_generator::generate_field_data(t_rb_ofstream& out, t_type* field_type, const std::string& field_name = "", t_const_value* field_value = nullptr, bool optional = false) { field_type = get_true_type(field_type); // Begin this field's defn out << "{:type => " << type_to_enum(field_type); if (!field_name.empty()) { out << ", :name => '" << field_name << "'"; } if (field_value != nullptr) { out << ", :default => "; render_const_value(out, field_type, field_value); } if (!field_type->is_base_type()) { if (field_type->is_struct() || field_type->is_xception()) { out << ", :class => " << full_type_name((t_struct*)field_type); } else if (field_type->is_list()) { out << ", :element => "; generate_field_data(out, ((t_list*)field_type)->get_elem_type()); } else if (field_type->is_map()) { out << ", :key => "; generate_field_data(out, ((t_map*)field_type)->get_key_type()); out << ", :value => "; generate_field_data(out, ((t_map*)field_type)->get_val_type()); } else if (field_type->is_set()) { out << ", :element => "; generate_field_data(out, ((t_set*)field_type)->get_elem_type()); } } else { if (((t_base_type*)field_type)->is_binary()) { out << ", :binary => true"; } } if (optional) { out << ", :optional => true"; } if (field_type->is_enum()) { out << ", :enum_class => " << full_type_name(field_type); } // End of this field's defn out << "}"; } void t_rb_generator::begin_namespace(t_rb_ofstream& out, vector modules) { for (auto & module : modules) { out.indent() << "module " << module << endl; out.indent_up(); } } void t_rb_generator::end_namespace(t_rb_ofstream& out, vector modules) { for (vector::reverse_iterator m_iter = modules.rbegin(); m_iter != modules.rend(); ++m_iter) { out.indent_down(); out.indent() << "end" << endl; } } /** * Generates a thrift service. * * @param tservice The service definition */ void t_rb_generator::generate_service(t_service* tservice) { string f_service_name = namespace_dir_ + underscore(service_name_) + ".rb"; f_service_.open(f_service_name.c_str()); f_service_ << rb_autogen_comment() << endl << render_require_thrift(); if (tservice->get_extends() != nullptr) { if (namespaced_) { f_service_ << "require '" << rb_namespace_to_path_prefix( tservice->get_extends()->get_program()->get_namespace("rb")) << underscore(tservice->get_extends()->get_name()) << "'" << endl; } else { f_service_ << "require '" << require_prefix_ << underscore(tservice->get_extends()->get_name()) << "'" << endl; } } f_service_ << "require '" << require_prefix_ << underscore(program_name_) << "_types'" << endl << endl; begin_namespace(f_service_, ruby_modules(tservice->get_program())); f_service_.indent() << "module " << capitalize(tservice->get_name()) << endl; f_service_.indent_up(); // Generate the three main parts of the service (well, two for now in PHP) generate_service_client(tservice); generate_service_server(tservice); generate_service_helpers(tservice); f_service_.indent_down(); f_service_.indent() << "end" << endl << endl; end_namespace(f_service_, ruby_modules(tservice->get_program())); // Close service file f_service_.close(); } /** * Generates helper functions for a service. * * @param tservice The service to generate a header definition for */ void t_rb_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; f_service_.indent() << "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); generate_rb_struct(f_service_, ts); generate_rb_function_helpers(*f_iter); } } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_rb_generator::generate_rb_function_helpers(t_function* tfunction) { t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } generate_rb_struct(f_service_, &result); } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_rb_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = ""; if (tservice->get_extends() != nullptr) { extends = full_type_name(tservice->get_extends()); extends_client = " < " + extends + "::Client "; } f_service_.indent() << "class Client" << extends_client << endl; f_service_.indent_up(); f_service_.indent() << "include ::Thrift::Client" << endl << endl; // Generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = (*f_iter)->get_name(); // Open function f_service_.indent() << "def " << function_signature(*f_iter) << endl; f_service_.indent_up(); f_service_.indent() << "send_" << funname << "("; bool first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << (*fld_iter)->get_name(); } f_service_ << ")" << endl; if (!(*f_iter)->is_oneway()) { f_service_.indent(); if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << "return "; } f_service_ << "recv_" << funname << "()" << endl; } f_service_.indent_down(); f_service_.indent() << "end" << endl; f_service_ << endl; f_service_.indent() << "def send_" << function_signature(*f_iter) << endl; f_service_.indent_up(); std::string argsname = capitalize((*f_iter)->get_name() + "_args"); std::string messageSendProc = (*f_iter)->is_oneway() ? "send_oneway_message" : "send_message"; f_service_.indent() << messageSendProc << "('" << funname << "', " << argsname; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << ", :" << (*fld_iter)->get_name() << " => " << (*fld_iter)->get_name(); } f_service_ << ")" << endl; f_service_.indent_down(); f_service_.indent() << "end" << endl; if (!(*f_iter)->is_oneway()) { std::string resultname = capitalize((*f_iter)->get_name() + "_result"); t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); // Open function f_service_ << endl; f_service_.indent() << "def " << function_signature(&recv_function) << endl; f_service_.indent_up(); // TODO(mcslee): Validate message reply here, seq ids etc. f_service_.indent() << "result = receive_message(" << resultname << ")" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_.indent() << "return result.success unless result.success.nil?" << endl; } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_.indent() << "raise result." << (*x_iter)->get_name() << " unless result." << (*x_iter)->get_name() << ".nil?" << endl; } // Careful, only return _result if not a void function if ((*f_iter)->get_returntype()->is_void()) { f_service_.indent() << "return" << endl; } else { f_service_.indent() << "raise " "::Thrift::ApplicationException.new(::Thrift::ApplicationException::" "MISSING_RESULT, '" << (*f_iter)->get_name() << " failed: unknown result')" << endl; } // Close function f_service_.indent_down(); f_service_.indent() << "end" << endl << endl; } } f_service_.indent_down(); f_service_.indent() << "end" << endl << endl; } /** * Generates a service server definition. * * @param tservice The service to generate a server for. */ void t_rb_generator::generate_service_server(t_service* tservice) { // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; string extends = ""; string extends_processor = ""; if (tservice->get_extends() != nullptr) { extends = full_type_name(tservice->get_extends()); extends_processor = " < " + extends + "::Processor "; } // Generate the header portion f_service_.indent() << "class Processor" << extends_processor << endl; f_service_.indent_up(); f_service_.indent() << "include ::Thrift::Processor" << endl << endl; // Generate the process subfunctions for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } f_service_.indent_down(); f_service_.indent() << "end" << endl << endl; } /** * Generates a process function definition. * * @param tfunction The function to write a dispatcher for */ void t_rb_generator::generate_process_function(t_service* tservice, t_function* tfunction) { (void)tservice; // Open function f_service_.indent() << "def process_" << tfunction->get_name() << "(seqid, iprot, oprot)" << endl; f_service_.indent_up(); string argsname = capitalize(tfunction->get_name()) + "_args"; string resultname = capitalize(tfunction->get_name()) + "_result"; f_service_.indent() << "args = read_args(iprot, " << argsname << ")" << endl; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; // Declare result for non oneway function if (!tfunction->is_oneway()) { f_service_.indent() << "result = " << resultname << ".new()" << endl; } // Try block for a function with exceptions if (xceptions.size() > 0) { f_service_.indent() << "begin" << endl; f_service_.indent_up(); } // Generate the function call t_struct* arg_struct = tfunction->get_arglist(); const std::vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; f_service_.indent(); if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { f_service_ << "result.success = "; } f_service_ << "@handler." << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { f_service_ << ", "; } f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ")" << endl; if (!tfunction->is_oneway() && xceptions.size() > 0) { f_service_.indent_down(); for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_.indent() << "rescue " << full_type_name((*x_iter)->get_type()) << " => " << (*x_iter)->get_name() << endl; if (!tfunction->is_oneway()) { f_service_.indent_up(); f_service_.indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl; f_service_.indent_down(); } } f_service_.indent() << "end" << endl; } // Shortcut out here for oneway functions if (tfunction->is_oneway()) { f_service_.indent() << "return" << endl; f_service_.indent_down(); f_service_.indent() << "end" << endl << endl; return; } f_service_.indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)" << endl; // Close function f_service_.indent_down(); f_service_.indent() << "end" << endl << endl; } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_rb_generator::function_signature(t_function* tfunction, string prefix) { // TODO(mcslee): Nitpicky, no ',' if argument_list is empty return prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")"; } /** * Renders a field list */ string t_rb_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += ", "; } result += (*f_iter)->get_name(); } return result; } string t_rb_generator::type_name(const t_type* ttype) { string prefix = ""; string name = ttype->get_name(); if (ttype->is_struct() || ttype->is_xception() || ttype->is_enum()) { name = capitalize(ttype->get_name()); } return prefix + name; } string t_rb_generator::full_type_name(const t_type* ttype) { string prefix = "::"; vector modules = ruby_modules(ttype->get_program()); for (auto & module : modules) { prefix += module + "::"; } return prefix + type_name(ttype); } /** * Converts the parse type to a Ruby tyoe */ string t_rb_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "::Thrift::Types::STRING"; case t_base_type::TYPE_BOOL: return "::Thrift::Types::BOOL"; case t_base_type::TYPE_I8: return "::Thrift::Types::BYTE"; case t_base_type::TYPE_I16: return "::Thrift::Types::I16"; case t_base_type::TYPE_I32: return "::Thrift::Types::I32"; case t_base_type::TYPE_I64: return "::Thrift::Types::I64"; case t_base_type::TYPE_DOUBLE: return "::Thrift::Types::DOUBLE"; } } else if (type->is_enum()) { return "::Thrift::Types::I32"; } else if (type->is_struct() || type->is_xception()) { return "::Thrift::Types::STRUCT"; } else if (type->is_map()) { return "::Thrift::Types::MAP"; } else if (type->is_set()) { return "::Thrift::Types::SET"; } else if (type->is_list()) { return "::Thrift::Types::LIST"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } string t_rb_generator::rb_namespace_to_path_prefix(string rb_namespace) { string namespaces_left = rb_namespace; string::size_type loc; string path_prefix = ""; while ((loc = namespaces_left.find(".")) != string::npos) { path_prefix = path_prefix + underscore(namespaces_left.substr(0, loc)) + "/"; namespaces_left = namespaces_left.substr(loc + 1); } if (namespaces_left.size() > 0) { path_prefix = path_prefix + underscore(namespaces_left) + "/"; } return path_prefix; } void t_rb_generator::generate_rdoc(t_rb_ofstream& out, t_doc* tdoc) { if (tdoc->has_doc()) { out.indent(); generate_docstring_comment(out, "", "# ", tdoc->get_doc(), ""); } } void t_rb_generator::generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct) { out.indent() << "def validate" << endl; out.indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = (*f_iter); if (field->get_req() == t_field::T_REQUIRED) { out.indent() << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, " "'Required field " << field->get_name() << " is unset!')"; if (field->get_type()->is_bool()) { out << " if @" << field->get_name() << ".nil?"; } else { out << " unless @" << field->get_name(); } out << endl; } } // if field is an enum, check that its value is valid for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field* field = (*f_iter); if (field->get_type()->is_enum()) { out.indent() << "unless @" << field->get_name() << ".nil? || " << full_type_name(field->get_type()) << "::VALID_VALUES.include?(@" << field->get_name() << ")" << endl; out.indent_up(); out.indent() << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, " "'Invalid value of field " << field->get_name() << "!')" << endl; out.indent_down(); out.indent() << "end" << endl; } } out.indent_down(); out.indent() << "end" << endl << endl; } void t_rb_generator::generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct) { out.indent() << "def validate" << endl; out.indent_up(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; out.indent() << "raise(StandardError, 'Union fields are not set.') if get_set_field.nil? || get_value.nil?" << endl; // if field is an enum, check that its value is valid for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { const t_field* field = (*f_iter); if (field->get_type()->is_enum()) { out.indent() << "if get_set_field == :" << field->get_name() << endl; out.indent() << " raise " "::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, " "'Invalid value of field " << field->get_name() << "!') unless " << full_type_name(field->get_type()) << "::VALID_VALUES.include?(get_value)" << endl; out.indent() << "end" << endl; } } out.indent_down(); out.indent() << "end" << endl << endl; } THRIFT_REGISTER_GENERATOR( rb, "Ruby", " rubygems: Add a \"require 'rubygems'\" line to the top of each generated file.\n" " namespaced: Generate files in idiomatic namespaced directories.\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_rs_generator.cc000066400000000000000000003632611420101504100246760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include "thrift/platform.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostringstream; using std::pair; using std::set; using std::string; using std::vector; static const string endl("\n"); // avoid ostream << std::endl flushes static const string SERVICE_RESULT_VARIABLE("result_value"); static const string RESULT_STRUCT_SUFFIX("Result"); static const string RUST_RESERVED_WORDS[] = { "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return", "Self", "self", "sizeof", "static", "struct", "super", "trait", "true", "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield" }; const set RUST_RESERVED_WORDS_SET( RUST_RESERVED_WORDS, RUST_RESERVED_WORDS + sizeof(RUST_RESERVED_WORDS)/sizeof(RUST_RESERVED_WORDS[0]) ); static const string SYNC_CLIENT_GENERIC_BOUND_VARS(""); static const string SYNC_CLIENT_GENERIC_BOUNDS("where IP: TInputProtocol, OP: TOutputProtocol"); // FIXME: extract common TMessageIdentifier function // FIXME: have to_rust_type deal with Option class t_rs_generator : public t_generator { public: t_rs_generator( t_program* program, const std::map&, const std::string& ) : t_generator(program) { gen_dir_ = get_out_dir(); } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; private: // struct type // T_REGULAR: user-defined struct in the IDL // T_ARGS: struct used to hold all service-call parameters // T_RESULT: struct used to hold all service-call returns and exceptions // T_EXCEPTION: user-defined exception in the IDL enum e_struct_type { T_REGULAR, T_ARGS, T_RESULT, T_EXCEPTION }; // Directory to which generated code is written. string gen_dir_; // File to which generated code is written. ofstream_with_content_based_conditional_update f_gen_; // Write the common compiler attributes and module includes to the top of the auto-generated file. void render_attributes_and_includes(); // Create the closure of Rust modules referenced by this service. void compute_service_referenced_modules(t_service *tservice, set> &referenced_modules); // Write the rust representation of an enum. void render_enum_definition(t_enum* tenum, const string& enum_name); // Write the impl blocks associated with the traits necessary to convert an enum to/from an i32. void render_enum_conversion(t_enum* tenum, const string& enum_name); // Write the impl block associated with the rust representation of an enum. This includes methods // to write the enum to a protocol, read it from a protocol, etc. void render_enum_impl(t_enum* tenum, const string& enum_name); // Write a simple rust const value (ie. `pub const FOO: foo...`). void render_const_value(const string& name, t_type* ttype, t_const_value* tvalue); // Write a constant list, set, map or struct. These constants require allocation and cannot be defined // using a 'pub const'. As a result, I create a holder struct with a single `const_value` method that // returns the initialized instance. void render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue); // Write the actual const value - the right side of a const definition. void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true); // Write a const struct (returned from `const_value` method). void render_const_struct(t_type* ttype, t_const_value* tvalue); // Write a const list (returned from `const_value` method). void render_const_list(t_type* ttype, t_const_value* tvalue); // Write a const set (returned from `const_value` method). void render_const_set(t_type* ttype, t_const_value* tvalue); // Write a const map (returned from `const_value` method). void render_const_map(t_type* ttype, t_const_value* tvalue); // Write the code to insert constant values into a rust vec or set. The // `insert_function` is the rust function that we'll use to insert the elements. void render_container_const_value( const string& insert_function, t_type* ttype, t_const_value* tvalue ); // Write the rust representation of a thrift struct to the generated file. Set `struct_type` to `T_ARGS` // if rendering the struct used to pack arguments for a service call. When `struct_type` is `T_ARGS` the // struct and its members have module visibility, and all fields are required. When `struct_type` is // anything else the struct and its members have public visibility and fields have the visibility set // in their definition. void render_struct(const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type); // Write the comment block preceding a type definition (and implementation). void render_type_comment(const string& struct_name); // Write the rust representation of a thrift struct. Supports argument structs, result structs, // user-defined structs and exception structs. The exact struct type to be generated is controlled // by the `struct_type` parameter, which (among other things) modifies the visibility of the // written struct and members, controls which trait implementations are generated. void render_struct_definition( const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type ); // Writes the impl block associated with the rust representation of a struct. At minimum this // contains the methods to read from a protocol and write to a protocol. Additional methods may // be generated depending on `struct_type`. void render_struct_impl( const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type ); // Generate a `fn new(...)` for a struct with name `struct_name` and type `t_struct`. The auto-generated // code may include generic type parameters to make the constructor more ergonomic. `struct_type` controls // the visibility of the generated constructor. void render_struct_constructor( const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type ); // Write the `ok_or` method added to all Thrift service call result structs. You can use this method // to convert a struct into a `Result` and use it in a `try!` or combinator chain. void render_result_struct_to_result_method(t_struct* tstruct); // Write the implementations for the `Error` and `Debug` traits. These traits are necessary for a // user-defined exception to be properly handled as Rust errors. void render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct); // Write the implementations for the `Default`. This trait allows you to specify only the fields you want // and use `..Default::default()` to fill in the rest. void render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct); // Write the function that serializes a struct to its wire representation. If `struct_type` is `T_ARGS` // then all fields are considered "required", if not, the default optionality is used. void render_struct_sync_write(t_struct *tstruct, t_rs_generator::e_struct_type struct_type); // Helper function that serializes a single struct field to its wire representation. Unpacks the // variable (since it may be optional) and serializes according to the optionality rules required by `req`. // Variables in auto-generated code are passed by reference. Since this function may be called in // contexts where the variable is *already* a reference you can set `field_var_is_ref` to `true` to avoid // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. void render_struct_field_sync_write( const string &field_var, bool field_var_is_ref, t_field *tfield, t_field::e_req req); // Write the rust function that serializes a single type (i.e. a i32 etc.) to its wire representation. // Variables in auto-generated code are passed by reference. Since this function may be called in // contexts where the variable is *already* a reference you can set `type_var_is_ref` to `true` to avoid // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. void render_type_sync_write(const string &type_var, bool type_var_is_ref, t_type *ttype); // Write a list to the output protocol. `list_variable` is the variable containing the list // that will be written to the output protocol. // Variables in auto-generated code are passed by reference. Since this function may be called in // contexts where the variable is *already* a reference you can set `list_var_is_ref` to `true` to avoid // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. void render_list_sync_write(const string &list_var, bool list_var_is_ref, t_list *tlist); // Write a set to the output protocol. `set_variable` is the variable containing the set that will // be written to the output protocol. // Variables in auto-generated code are passed by reference. Since this function may be called in // contexts where the variable is *already* a reference you can set `set_var_is_ref` to `true` to avoid // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. void render_set_sync_write(const string &set_var, bool set_var_is_ref, t_set *tset); // Write a map to the output protocol. `map_variable` is the variable containing the map that will // be written to the output protocol. // Variables in auto-generated code are passed by reference. Since this function may be called in // contexts where the variable is *already* a reference you can set `map_var_is_ref` to `true` to avoid // generating an extra, unnecessary `&` that the compiler will have to automatically dereference. void render_map_sync_write(const string &map_var, bool map_var_is_ref, t_map *tset); // Return `true` if we need to dereference ths type when writing an element from a container. // Iterations on rust containers are performed as follows: `for v in &values { ... }` // where `v` has type `&RUST_TYPE` All defined functions take primitives by value, so, if the // rendered code is calling such a function it has to dereference `v`. bool needs_deref_on_container_write(t_type* ttype); // Return the variable (including all dereferences) required to write values from a rust container // to the output protocol. For example, if you were iterating through a container and using the temp // variable `v` to represent each element, then `ttype` is the type stored in the container and // `base_var` is "v". The return value is the actual string you will have to use to properly reference // the temp variable for writing to the output protocol. string string_container_write_variable(t_type* ttype, const string& base_var); // Write the code to read bytes from the wire into the given `t_struct`. `struct_name` is the // actual Rust name of the `t_struct`. If `struct_type` is `T_ARGS` then all struct fields are // necessary. Otherwise, the field's default optionality is used. void render_struct_sync_read(const string &struct_name, t_struct *tstruct, t_rs_generator::e_struct_type struct_type); // Write the rust function that deserializes a single type (i.e. i32 etc.) from its wire representation. // Set `is_boxed` to `true` if the resulting value should be wrapped in a `Box::new(...)`. void render_type_sync_read(const string &type_var, t_type *ttype, bool is_boxed = false); // Read the wire representation of a list and convert it to its corresponding rust implementation. // The deserialized list is stored in `list_variable`. void render_list_sync_read(t_list *tlist, const string &list_variable); // Read the wire representation of a set and convert it to its corresponding rust implementation. // The deserialized set is stored in `set_variable`. void render_set_sync_read(t_set *tset, const string &set_variable); // Read the wire representation of a map and convert it to its corresponding rust implementation. // The deserialized map is stored in `map_variable`. void render_map_sync_read(t_map *tmap, const string &map_variable); // Return a temporary variable used to store values when deserializing nested containers. string struct_field_read_temp_variable(t_field* tfield); // Top-level function that calls the various render functions necessary to write the rust representation // of a thrift union (i.e. an enum). void render_union(t_struct* tstruct); // Write the enum corresponding to the Thrift union. void render_union_definition(const string& union_name, t_struct* tstruct); // Write the enum impl (with read/write functions) for the Thrift union. void render_union_impl(const string& union_name, t_struct* tstruct); // Write the `ENUM::write_to_out_protocol` function. void render_union_sync_write(const string &union_name, t_struct *tstruct); // Write the `ENUM::read_from_in_protocol` function. void render_union_sync_read(const string &union_name, t_struct *tstruct); // Top-level function that calls the various render functions necessary to write the rust representation // of a Thrift client. void render_sync_client(t_service* tservice); // Write the trait with the service-call methods for `tservice`. void render_sync_client_trait(t_service *tservice); // Write the trait to be implemented by the client impl if end users can use it to make service calls. void render_sync_client_marker_trait(t_service *tservice); // Write the code to create the Thrift service sync client struct and its matching 'impl' block. void render_sync_client_definition_and_impl(const string& client_impl_name); // Write the code to create the `SyncClient::new` functions as well as any other functions // callers would like to use on the Thrift service sync client. void render_sync_client_lifecycle_functions(const string& client_struct); // Write the code to create the impl block for the `TThriftClient` trait. Since generated // Rust Thrift clients perform all their operations using methods defined in this trait, we // have to implement it for the client structs. void render_sync_client_tthriftclient_impl(const string &client_impl_name); // Write the marker traits for any service(s) being extended, including the one for the current // service itself (i.e. `tservice`) void render_sync_client_marker_trait_impls(t_service *tservice, const string &impl_struct_name); // Generate a list of all the traits this Thrift client struct extends. string sync_client_marker_traits_for_extension(t_service *tservice); // Top-level function that writes the code to make the Thrift service calls. void render_sync_client_process_impl(t_service* tservice); // Write the actual function that calls out to the remote service and processes its response. void render_sync_send_recv_wrapper(t_function* tfunc); // Write the `send` functionality for a Thrift service call represented by a `t_service->t_function`. void render_sync_send(t_function* tfunc); // Write the `recv` functionality for a Thrift service call represented by a `t_service->t_function`. // This method is only rendered if the function is *not* oneway. void render_sync_recv(t_function* tfunc); void render_sync_processor(t_service *tservice); void render_sync_handler_trait(t_service *tservice); void render_sync_processor_definition_and_impl(t_service *tservice); void render_sync_process_delegation_functions(t_service *tservice); void render_sync_process_function(t_function *tfunc, const string &handler_type); void render_process_match_statements(t_service* tservice); void render_sync_handler_succeeded(t_function *tfunc); void render_sync_handler_failed(t_function *tfunc); void render_sync_handler_failed_user_exception_branch(t_function *tfunc); void render_sync_handler_failed_application_exception_branch(t_function *tfunc, const string &app_err_var); void render_sync_handler_failed_default_exception_branch(t_function *tfunc); void render_sync_handler_send_exception_response(t_function *tfunc, const string &err_var); void render_service_call_structs(t_service* tservice); void render_service_call_args_struct(t_function* tfunc); void render_service_call_result_value_struct(t_function* tfunc); string handler_successful_return_struct(t_function* tfunc); // Writes the result of `render_thrift_error_struct` wrapped in an `Err(thrift::Error(...))`. void render_thrift_error( const string& error_kind, const string& error_struct, const string& sub_error_kind, const string& error_message ); // Write a thrift::Error variant struct. Error structs take the form: // ``` // pub struct error_struct { // kind: sub_error_kind, // message: error_message, // } // ``` // A concrete example is: // ``` // pub struct ApplicationError { // kind: ApplicationErrorKind::Unknown, // message: "This is some error message", // } // ``` void render_thrift_error_struct( const string& error_struct, const string& sub_error_kind, const string& error_message ); // Return a string containing all the unpacked service call args given a service call function // `t_function`. Prepends the args with either `&mut self` or `&self` and includes the arg types // in the returned string, for example: // `fn foo(&mut self, field_0: String)`. string rust_sync_service_call_declaration(t_function* tfunc, bool self_is_mutable); // Return a string containing all the unpacked service call args given a service call function // `t_function`. Only includes the arg names, each of which is prefixed with the optional prefix // `field_prefix`, for example: `self.field_0`. string rust_sync_service_call_invocation(t_function* tfunc, const string& field_prefix = ""); // Return a string containing all fields in the struct `tstruct` for use in a function declaration. // Each field is followed by its type, for example: `field_0: String`. string struct_to_declaration(t_struct* tstruct, t_rs_generator::e_struct_type struct_type); // Return a string containing all fields in the struct `tstruct` for use in a function call, // for example: `field_0: String`. string struct_to_invocation(t_struct* tstruct, const string& field_prefix = ""); // Write the documentation for a struct, service-call or other documentation-annotated element. void render_rustdoc(t_doc* tdoc); // Return `true` if the true type of `ttype` is a thrift double, `false` otherwise. bool is_double(t_type* ttype); // Return a string representing the rust type given a `t_type`. string to_rust_type(t_type* ttype); // Return a string representing the `const` rust type given a `t_type` string to_rust_const_type(t_type* ttype); // Return a string representing the rift `protocol::TType` given a `t_type`. string to_rust_field_type_enum(t_type* ttype); // Return the default value to be used when initializing a struct field which has `OPT_IN_REQ_OUT` // optionality. string opt_in_req_out_value(t_type* ttype); // Return `true` if we can write a const of the form `pub const FOO: ...`. bool can_generate_simple_const(t_type* ttype); // Return `true` if we cannot write a standard Rust constant (because the type needs some allocation). bool can_generate_const_holder(t_type* ttype); // Return `true` if this type is a void, and should be represented by the rust `()` type. bool is_void(t_type* ttype); t_field::e_req actual_field_req(t_field* tfield, t_rs_generator::e_struct_type struct_type); // Return `true` if this `t_field::e_req` is either `t_field::T_OPTIONAL` or `t_field::T_OPT_IN_REQ_OUT` // and needs to be wrapped by an `Option`, `false` otherwise. bool is_optional(t_field::e_req req); // Return `true` if the service call has arguments, `false` otherwise. bool has_args(t_function* tfunc); // Return `true` if a service call has non-`()` arguments, `false` otherwise. bool has_non_void_args(t_function* tfunc); // Return `pub ` (notice trailing whitespace!) if the struct should be public, `` (empty string) otherwise. string visibility_qualifier(t_rs_generator::e_struct_type struct_type); // Returns the namespace prefix for a given Thrift service. If the type is defined in the presently-computed // Thrift program, then an empty string is returned. string rust_namespace(t_service* tservice); // Returns the namespace prefix for a given Thrift type. If the type is defined in the presently-computed // Thrift program, then an empty string is returned. string rust_namespace(t_type* ttype); // Returns the camel-cased name for a Rust struct type. Handles the case where `tstruct->get_name()` is // a reserved word. string rust_struct_name(t_struct* tstruct); // Returns the snake-cased name for a Rust field or local variable. Handles the case where // `tfield->get_name()` is a reserved word. string rust_field_name(t_field* tstruct); // Returns the camel-cased name for a Rust union type. Handles the case where `tstruct->get_name()` is // a reserved word. string rust_union_field_name(t_field* tstruct); // Converts any variable name into a 'safe' variant that does not clash with any Rust reserved keywords. string rust_safe_name(const string& name); // Return `true` if the name is a reserved Rust keyword, `false` otherwise. bool is_reserved(const string& name); // Return the name of the function that users will invoke to make outgoing service calls. string service_call_client_function_name(t_function* tfunc); // Return the name of the function that users will have to implement to handle incoming service calls. string service_call_handler_function_name(t_function* tfunc); // Return the name of the struct used to pack the arguments for the thrift service call. string service_call_args_struct_name(t_function* tfunc); // Return the name of the struct used to pack the return value // and user-defined exceptions for the thrift service call. string service_call_result_struct_name(t_function* tfunc); string rust_sync_client_marker_trait_name(t_service* tservice); // Return the trait name for the sync service client given a `t_service`. string rust_sync_client_trait_name(t_service* tservice); // Return the name for the sync service client struct given a `t_service`. string rust_sync_client_impl_name(t_service* tservice); // Return the trait name that users will have to implement for the server half of a Thrift service. string rust_sync_handler_trait_name(t_service* tservice); // Return the struct name for the server half of a Thrift service. string rust_sync_processor_name(t_service* tservice); // Return the struct name for the struct that contains all the service-call implementations for // the server half of a Thrift service. string rust_sync_processor_impl_name(t_service *tservice); // Return the variant name for an enum variant string rust_enum_variant_name(const string& name); // Properly uppercase names for use in Rust. string rust_upper_case(const string& name); // Snake-case field, parameter and function names and make them Rust friendly. string rust_snake_case(const string& name); // Camel-case type/variant names and make them Rust friendly. string rust_camel_case(const string& name); // Replace all instances of `search_string` with `replace_string` in `target`. void string_replace(string& target, const string& search_string, const string& replace_string); // Adjust field identifier to correctly handle unspecified field identifiers // THRIFT-4953 string rust_safe_field_id(int32_t id); }; void t_rs_generator::init_generator() { // make output directory for this thrift program MKDIR(gen_dir_.c_str()); // create the file into which we're going to write the generated code string f_gen_name = gen_dir_ + "/" + rust_snake_case(get_program()->get_name()) + ".rs"; f_gen_.open(f_gen_name.c_str()); // header comment f_gen_ << "// " << autogen_summary() << endl; f_gen_ << "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING" << endl; f_gen_ << endl; render_attributes_and_includes(); } void t_rs_generator::render_attributes_and_includes() { // turn off some compiler/clippy warnings // code always includes BTreeMap/BTreeSet/OrderedFloat f_gen_ << "#![allow(unused_imports)]" << endl; // code might not include imports from crates f_gen_ << "#![allow(unused_extern_crates)]" << endl; // constructors take *all* struct parameters, which can trigger the "too many arguments" warning // some auto-gen'd types can be deeply nested. clippy recommends factoring them out which is hard to autogen // FIXME: re-enable the 'vec_box' lint see: [THRIFT-5364](https://issues.apache.org/jira/browse/THRIFT-5364) // This can happen because we automatically generate a Vec> when the type is a typedef // and it's a forward typedef. This (typedef + forward typedef) can happen in two situations: // 1. When the type is recursive // 2. When you define types out of order f_gen_ << "#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box)]" << endl; // prevent rustfmt from running against this file // lines are too long, code is (thankfully!) not visual-indented, etc. // can't use #[rustfmt::skip] see: https://github.com/rust-lang/rust/issues/54726 f_gen_ << "#![cfg_attr(rustfmt, rustfmt_skip)]" << endl; f_gen_ << endl; // add standard includes f_gen_ << "use std::cell::RefCell;" << endl; f_gen_ << "use std::collections::{BTreeMap, BTreeSet};" << endl; f_gen_ << "use std::convert::{From, TryFrom};" << endl; f_gen_ << "use std::default::Default;" << endl; f_gen_ << "use std::error::Error;" << endl; f_gen_ << "use std::fmt;" << endl; f_gen_ << "use std::fmt::{Display, Formatter};" << endl; f_gen_ << "use std::rc::Rc;" << endl; f_gen_ << endl; f_gen_ << "use thrift::OrderedFloat;" << endl; f_gen_ << "use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient};" << endl; f_gen_ << "use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType};" << endl; f_gen_ << "use thrift::protocol::field_id;" << endl; f_gen_ << "use thrift::protocol::verify_expected_message_type;" << endl; f_gen_ << "use thrift::protocol::verify_expected_sequence_number;" << endl; f_gen_ << "use thrift::protocol::verify_expected_service_call;" << endl; f_gen_ << "use thrift::protocol::verify_required_field_exists;" << endl; f_gen_ << "use thrift::server::TProcessor;" << endl; f_gen_ << endl; // add all the program includes // NOTE: this is more involved than you would expect because of service extension // Basically, I have to find the closure of all the services and include their modules at the top-level set> referenced_modules; // set // first, start by adding explicit thrift includes const vector includes = get_program()->get_includes(); vector::const_iterator includes_iter; for(includes_iter = includes.begin(); includes_iter != includes.end(); ++includes_iter) { referenced_modules.insert(std::make_pair((*includes_iter)->get_name(), (*includes_iter)->get_namespace("rs"))); } // next, recursively iterate through all the services and add the names of any programs they reference const vector services = get_program()->get_services(); vector::const_iterator service_iter; for (service_iter = services.begin(); service_iter != services.end(); ++service_iter) { compute_service_referenced_modules(*service_iter, referenced_modules); } // finally, write all the "pub use..." declarations if (!referenced_modules.empty()) { set>::iterator module_iter; for (module_iter = referenced_modules.begin(); module_iter != referenced_modules.end(); ++module_iter) { string module_name((*module_iter).first); string module_namespace((*module_iter).second); string_replace(module_namespace, ".", "::"); if (module_namespace.empty()) { f_gen_ << "use crate::" << rust_snake_case(module_name) << ";" << endl; } else { f_gen_ << "use crate::" << module_namespace << "::" << rust_snake_case(module_name) << ";" << endl; } } f_gen_ << endl; } } void t_rs_generator::compute_service_referenced_modules( t_service *tservice, set> &referenced_modules ) { t_service* extends = tservice->get_extends(); if (extends) { if (extends->get_program() != get_program()) { referenced_modules.insert(std::make_pair(extends->get_program()->get_name(), extends->get_program()->get_namespace("rs"))); } compute_service_referenced_modules(extends, referenced_modules); } } void t_rs_generator::close_generator() { f_gen_.close(); } //----------------------------------------------------------------------------- // // Consts // // NOTE: consider using macros to generate constants // //----------------------------------------------------------------------------- // This is worse than it should be because constants // aren't (sensibly) limited to scalar types void t_rs_generator::generate_const(t_const* tconst) { string name = tconst->get_name(); t_type* ttype = tconst->get_type(); t_const_value* tvalue = tconst->get_value(); if (can_generate_simple_const(ttype)) { render_const_value(name, ttype, tvalue); } else if (can_generate_const_holder(ttype)) { render_const_value_holder(name, ttype, tvalue); } else { throw "cannot generate const for " + name; } } void t_rs_generator::render_const_value(const string& name, t_type* ttype, t_const_value* tvalue) { if (!can_generate_simple_const(ttype)) { throw "cannot generate simple rust constant for " + ttype->get_name(); } f_gen_ << "pub const " << rust_upper_case(name) << ": " << to_rust_const_type(ttype) << " = "; render_const_value(ttype, tvalue, false); f_gen_ << ";" << endl; f_gen_ << endl; } void t_rs_generator::render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue) { if (!can_generate_const_holder(ttype)) { throw "cannot generate constant holder for " + ttype->get_name(); } string holder_name("Const" + rust_camel_case(name)); f_gen_ << indent() << "pub struct " << holder_name << ";" << endl; f_gen_ << indent() << "impl " << holder_name << " {" << endl; indent_up(); f_gen_ << indent() << "pub fn const_value() -> " << to_rust_type(ttype) << " {" << endl; indent_up(); render_const_value(ttype, tvalue); indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned) { if (ttype->is_base_type()) { t_base_type* tbase_type = (t_base_type*)ttype; switch (tbase_type->get_base()) { case t_base_type::TYPE_STRING: if (tbase_type->is_binary()) { if (is_owned) { f_gen_ << "\"" << tvalue->get_string() << "\""<< ".to_owned().into_bytes()"; } else { f_gen_ << "b\"" << tvalue->get_string() << "\""; } } else { f_gen_ << "\"" << tvalue->get_string() << "\""; if (is_owned) { f_gen_ << ".to_owned()"; } } break; case t_base_type::TYPE_BOOL: f_gen_ << (tvalue->get_integer() ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: f_gen_ << tvalue->get_integer(); break; case t_base_type::TYPE_DOUBLE: f_gen_ << "OrderedFloat::from(" << tvalue->get_double() << "_f64)"; break; default: throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base()); } } else if (ttype->is_typedef()) { render_const_value(get_true_type(ttype), tvalue); } else if (ttype->is_enum()) { f_gen_ << indent() << "{" << endl; indent_up(); f_gen_ << indent() << to_rust_type(ttype) << "::try_from(" << tvalue->get_integer() << ").expect(\"expecting valid const value\")" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } else if (ttype->is_struct() || ttype->is_xception()) { render_const_struct(ttype, tvalue); } else if (ttype->is_container()) { f_gen_ << indent() << "{" << endl; indent_up(); if (ttype->is_list()) { render_const_list(ttype, tvalue); } else if (ttype->is_set()) { render_const_set(ttype, tvalue); } else if (ttype->is_map()) { render_const_map(ttype, tvalue); } else { throw "cannot generate const container value for " + ttype->get_name(); } indent_down(); f_gen_ << indent() << "}" << endl; } else { throw "cannot generate const value for " + ttype->get_name(); } } void t_rs_generator::render_const_struct(t_type* ttype, t_const_value*) { if (((t_struct*)ttype)->is_union()) { f_gen_ << indent() << "{" << endl; indent_up(); f_gen_ << indent() << "unimplemented!()" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } else { f_gen_ << indent() << "{" << endl; indent_up(); f_gen_ << indent() << "unimplemented!()" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } } void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) { t_type* elem_type = ((t_list*)ttype)->get_elem_type(); f_gen_ << indent() << "let mut l: Vec<" << to_rust_type(elem_type) << "> = Vec::new();" << endl; const vector& elems = tvalue->get_list(); vector::const_iterator elem_iter; for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { t_const_value* elem_value = (*elem_iter); render_container_const_value("l.push", elem_type, elem_value); } f_gen_ << indent() << "l" << endl; } void t_rs_generator::render_const_set(t_type* ttype, t_const_value* tvalue) { t_type* elem_type = ((t_set*)ttype)->get_elem_type(); f_gen_ << indent() << "let mut s: BTreeSet<" << to_rust_type(elem_type) << "> = BTreeSet::new();" << endl; const vector& elems = tvalue->get_list(); vector::const_iterator elem_iter; for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { t_const_value* elem_value = (*elem_iter); render_container_const_value("s.insert", elem_type, elem_value); } f_gen_ << indent() << "s" << endl; } void t_rs_generator::render_const_map(t_type* ttype, t_const_value* tvalue) { t_type* key_type = ((t_map*)ttype)->get_key_type(); t_type* val_type = ((t_map*)ttype)->get_val_type(); f_gen_ << indent() << "let mut m: BTreeMap<" << to_rust_type(key_type) << ", " << to_rust_type(val_type) << "> = BTreeMap::new();" << endl; const map& elems = tvalue->get_map(); map::const_iterator elem_iter; for (elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { t_const_value* key_value = elem_iter->first; t_const_value* val_value = elem_iter->second; if (get_true_type(key_type)->is_base_type()) { f_gen_ << indent() << "let k = "; render_const_value(key_type, key_value); f_gen_ << ";" << endl; } else { f_gen_ << indent() << "let k = {" << endl; indent_up(); render_const_value(key_type, key_value); indent_down(); f_gen_ << indent() << "};" << endl; } if (get_true_type(val_type)->is_base_type()) { f_gen_ << indent() << "let v = "; render_const_value(val_type, val_value); f_gen_ << ";" << endl; } else { f_gen_ << indent() << "let v = {" << endl; indent_up(); render_const_value(val_type, val_value); indent_down(); f_gen_ << indent() << "};" << endl; } f_gen_ << indent() << "m.insert(k, v);" << endl; } f_gen_ << indent() << "m" << endl; } void t_rs_generator::render_container_const_value( const string& insert_function, t_type* ttype, t_const_value* tvalue ) { if (get_true_type(ttype)->is_base_type()) { f_gen_ << indent() << insert_function << "("; render_const_value(ttype, tvalue); f_gen_ << ");" << endl; } else { f_gen_ << indent() << insert_function << "(" << endl; indent_up(); render_const_value(ttype, tvalue); indent_down(); f_gen_ << indent() << ");" << endl; } } //----------------------------------------------------------------------------- // // Typedefs // //----------------------------------------------------------------------------- void t_rs_generator::generate_typedef(t_typedef* ttypedef) { std::string actual_type = to_rust_type(ttypedef->get_type()); f_gen_ << "pub type " << rust_safe_name(ttypedef->get_symbolic()) << " = " << actual_type << ";" << endl; f_gen_ << endl; } //----------------------------------------------------------------------------- // // Enums // //----------------------------------------------------------------------------- void t_rs_generator::generate_enum(t_enum* tenum) { string enum_name(rust_camel_case(tenum->get_name())); render_enum_definition(tenum, enum_name); render_enum_impl(tenum, enum_name); render_enum_conversion(tenum, enum_name); } void t_rs_generator::render_enum_definition(t_enum* tenum, const string& enum_name) { render_rustdoc((t_doc*) tenum); f_gen_ << "#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl; f_gen_ << "pub struct " << enum_name << "(pub i32);" << endl; f_gen_ << endl; } void t_rs_generator::render_enum_impl(t_enum* tenum, const string& enum_name) { f_gen_ << "impl " << enum_name << " {" << endl; indent_up(); vector constants = tenum->get_constants(); // associated constants for each IDL-defined enum variant { vector::iterator constants_iter; for (constants_iter = constants.begin(); constants_iter != constants.end(); ++constants_iter) { t_enum_value* val = (*constants_iter); render_rustdoc((t_doc*) val); f_gen_ << indent() << "pub const " << rust_enum_variant_name(val->get_name()) << ": " << enum_name << " = " << enum_name << "(" << val->get_value() << ")" << ";" << endl; } } // array containing all IDL-defined enum variants { f_gen_ << indent() << "pub const ENUM_VALUES: &'static [Self] = &[" << endl; indent_up(); vector::iterator constants_iter; for (constants_iter = constants.begin(); constants_iter != constants.end(); ++constants_iter) { t_enum_value* val = (*constants_iter); f_gen_ << indent() << "Self::" << rust_enum_variant_name(val->get_name()) << "," << endl; } indent_down(); f_gen_ << indent() << "];" << endl; } f_gen_ << indent() << "#[allow(clippy::trivially_copy_pass_by_ref)]" << endl; f_gen_ << indent() << "pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {" << endl; indent_up(); f_gen_ << indent() << "o_prot.write_i32(self.0)" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<" << enum_name << "> {" << endl; indent_up(); f_gen_ << indent() << "let enum_value = i_prot.read_i32()?;" << endl; f_gen_ << indent() << "Ok(" << enum_name << "::from(enum_value)" << ")" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_enum_conversion(t_enum* tenum, const string& enum_name) { // From trait: i32 -> ENUM_TYPE f_gen_ << "impl From for " << enum_name << " {" << endl; indent_up(); f_gen_ << indent() << "fn from(i: i32) -> Self {" << endl; indent_up(); f_gen_ << indent() << "match i {" << endl; indent_up(); vector constants = tenum->get_constants(); vector::iterator constants_iter; for (constants_iter = constants.begin(); constants_iter != constants.end(); ++constants_iter) { t_enum_value* val = (*constants_iter); f_gen_ << indent() << val->get_value() << " => " << enum_name << "::" << rust_enum_variant_name(val->get_name()) << "," << endl; } f_gen_ << indent() << "_ => " << enum_name << "(i)" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; // From trait: &i32 -> ENUM_TYPE f_gen_ << "impl From<&i32> for " << enum_name << " {" << endl; indent_up(); f_gen_ << indent() << "fn from(i: &i32) -> Self {" << endl; indent_up(); f_gen_ << indent() << enum_name << "::from(*i)" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; // From trait: ENUM_TYPE -> int f_gen_ << "impl From<" << enum_name << "> for i32 {" << endl; indent_up(); f_gen_ << indent() << "fn from(e: " << enum_name << ") -> i32 {" << endl; indent_up(); f_gen_ << indent() << "e.0" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; // From trait: &ENUM_TYPE -> int f_gen_ << "impl From<&" << enum_name << "> for i32 {" << endl; indent_up(); f_gen_ << indent() << "fn from(e: &" << enum_name << ") -> i32 {" << endl; indent_up(); f_gen_ << indent() << "e.0" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } //----------------------------------------------------------------------------- // // Structs, Unions and Exceptions // //----------------------------------------------------------------------------- void t_rs_generator::generate_xception(t_struct* txception) { render_struct(rust_struct_name(txception), txception, t_rs_generator::T_EXCEPTION); } void t_rs_generator::generate_struct(t_struct* tstruct) { if (tstruct->is_union()) { render_union(tstruct); } else if (tstruct->is_struct()) { render_struct(rust_struct_name(tstruct), tstruct, t_rs_generator::T_REGULAR); } else { throw "cannot generate struct for exception"; } } void t_rs_generator::render_struct( const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type ) { render_type_comment(struct_name); render_struct_definition(struct_name, tstruct, struct_type); render_struct_impl(struct_name, tstruct, struct_type); if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) { render_struct_default_trait_impl(struct_name, tstruct); } if (struct_type == t_rs_generator::T_EXCEPTION) { render_exception_struct_error_trait_impls(struct_name, tstruct); } } void t_rs_generator::render_struct_definition( const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type ) { render_rustdoc((t_doc*) tstruct); f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl; f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl; // render the members vector members = tstruct->get_sorted_members(); if (!members.empty()) { indent_up(); vector::iterator members_iter; for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); t_field::e_req member_req = actual_field_req(member, struct_type); string rust_type = to_rust_type(member->get_type()); rust_type = is_optional(member_req) ? "Option<" + rust_type + ">" : rust_type; render_rustdoc((t_doc*) member); f_gen_ << indent() << visibility_qualifier(struct_type) << rust_field_name(member) << ": " << rust_type << "," << endl; } indent_down(); } f_gen_ << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct) { // error::Error trait f_gen_ << "impl Error for " << struct_name << " {}" << endl; f_gen_ << endl; // convert::From trait f_gen_ << "impl From<" << struct_name << "> for thrift::Error {" << endl; indent_up(); f_gen_ << indent() << "fn from(e: " << struct_name << ") -> Self {" << endl; indent_up(); f_gen_ << indent() << "thrift::Error::User(Box::new(e))" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; // fmt::Display trait f_gen_ << "impl Display for " << struct_name << " {" << endl; indent_up(); f_gen_ << indent() << "fn fmt(&self, f: &mut Formatter) -> fmt::Result {" << endl; indent_up(); f_gen_ << indent() << "write!(f, " << "\"remote service threw " << tstruct->get_name() << "\"" // use *original* name << ")" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct) { bool has_required_field = false; const vector& members = tstruct->get_sorted_members(); vector::const_iterator members_iter; for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = *members_iter; if (!is_optional(member->get_req())) { has_required_field = true; break; } } if (has_required_field) { return; } f_gen_ << "impl Default for " << struct_name << " {" << endl; indent_up(); f_gen_ << indent() << "fn default() -> Self {" << endl; indent_up(); if (members.empty()) { f_gen_ << indent() << struct_name << "{}" << endl; } else { f_gen_ << indent() << struct_name << "{" << endl; indent_up(); for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field *member = (*members_iter); string member_name(rust_field_name(member)); f_gen_ << indent() << member_name << ": " << opt_in_req_out_value(member->get_type()) << "," << endl; } indent_down(); f_gen_ << indent() << "}" << endl; } indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_struct_impl( const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type ) { f_gen_ << "impl " << struct_name << " {" << endl; indent_up(); if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) { render_struct_constructor(struct_name, tstruct, struct_type); } render_struct_sync_read(struct_name, tstruct, struct_type); render_struct_sync_write(tstruct, struct_type); if (struct_type == t_rs_generator::T_RESULT) { render_result_struct_to_result_method(tstruct); } indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_struct_constructor( const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type ) { const vector& members = tstruct->get_sorted_members(); vector::const_iterator members_iter; // build the convenience type parameters that allows us to pass unwrapped values to a constructor and // have them automatically converted into Option bool first_arg = true; ostringstream generic_type_parameters; ostringstream generic_type_qualifiers; for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); t_field::e_req member_req = actual_field_req(member, struct_type); if (is_optional(member_req)) { if (first_arg) { first_arg = false; } else { generic_type_parameters << ", "; generic_type_qualifiers << ", "; } generic_type_parameters << "F" << rust_safe_field_id(member->get_key()); generic_type_qualifiers << "F" << rust_safe_field_id(member->get_key()) << ": Intoget_type()) << ">>"; } } string type_parameter_string = generic_type_parameters.str(); if (type_parameter_string.length() != 0) { type_parameter_string = "<" + type_parameter_string + ">"; } string type_qualifier_string = generic_type_qualifiers.str(); if (type_qualifier_string.length() != 0) { type_qualifier_string = "where " + type_qualifier_string + " "; } // now build the actual constructor arg list // when we're building this list we have to use the type parameters in place of the actual type names // if necessary ostringstream args; first_arg = true; for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); t_field::e_req member_req = actual_field_req(member, struct_type); string member_name(rust_field_name(member)); if (first_arg) { first_arg = false; } else { args << ", "; } if (is_optional(member_req)) { args << member_name << ": " << "F" << rust_safe_field_id(member->get_key()); } else { args << member_name << ": " << to_rust_type(member->get_type()); } } string arg_string = args.str(); string visibility(visibility_qualifier(struct_type)); f_gen_ << indent() << visibility << "fn new" << type_parameter_string << "(" << arg_string << ") -> " << struct_name << " " << type_qualifier_string << "{" << endl; indent_up(); if (members.empty()) { f_gen_ << indent() << struct_name << " {}" << endl; } else { f_gen_ << indent() << struct_name << " {" << endl; indent_up(); for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); t_field::e_req member_req = actual_field_req(member, struct_type); string member_name(rust_field_name(member)); if (is_optional(member_req)) { f_gen_ << indent() << member_name << ": " << member_name << ".into()," << endl; } else { f_gen_ << indent() << member_name << "," << endl; } } indent_down(); f_gen_ << indent() << "}" << endl; } indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_result_struct_to_result_method(t_struct* tstruct) { // we don't use the rust struct name in this method, just the service call name string service_call_name = tstruct->get_name(); // check that we actually have a result size_t index = service_call_name.find(RESULT_STRUCT_SUFFIX, 0); if (index == std::string::npos) { throw "result struct " + service_call_name + " missing result suffix"; } else { service_call_name.replace(index, 6, ""); } const vector& members = tstruct->get_sorted_members(); vector::const_iterator members_iter; // find out what the call's expected return type was string rust_return_type = "()"; for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); if (member->get_name() == SERVICE_RESULT_VARIABLE) { // don't have to check safe name here rust_return_type = to_rust_type(member->get_type()); break; } } // NOTE: ideally I would generate the branches and render them separately // I tried this however, and the resulting code was harder to understand // maintaining a rendered branch count (while a little ugly) got me the // rendering I wanted with code that was reasonably understandable f_gen_ << indent() << "fn ok_or(self) -> thrift::Result<" << rust_return_type << "> {" << endl; indent_up(); int rendered_branch_count = 0; // render the exception branches for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* tfield = (*members_iter); if (tfield->get_name() != SERVICE_RESULT_VARIABLE) { // don't have to check safe name here string field_name("self." + rust_field_name(tfield)); string branch_statement = rendered_branch_count == 0 ? "if" : "} else if"; f_gen_ << indent() << branch_statement << " " << field_name << ".is_some() {" << endl; indent_up(); f_gen_ << indent() << "Err(thrift::Error::User(Box::new(" << field_name << ".unwrap())))" << endl; indent_down(); rendered_branch_count++; } } // render the return value branches if (rust_return_type == "()") { if (rendered_branch_count == 0) { // we have the unit return and this service call has no user-defined // exceptions. this means that we've a trivial return (happens with oneways) f_gen_ << indent() << "Ok(())" << endl; } else { // we have the unit return, but there are user-defined exceptions // if we've gotten this far then we have the default return (i.e. call successful) f_gen_ << indent() << "} else {" << endl; indent_up(); f_gen_ << indent() << "Ok(())" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } } else { string branch_statement = rendered_branch_count == 0 ? "if" : "} else if"; f_gen_ << indent() << branch_statement << " self." << SERVICE_RESULT_VARIABLE << ".is_some() {" << endl; indent_up(); f_gen_ << indent() << "Ok(self." << SERVICE_RESULT_VARIABLE << ".unwrap())" << endl; indent_down(); f_gen_ << indent() << "} else {" << endl; indent_up(); // if we haven't found a valid return value *or* a user exception // then we're in trouble; return a default error render_thrift_error( "Application", "ApplicationError", "ApplicationErrorKind::MissingResult", "\"no result received for " + service_call_name + "\"" ); indent_down(); f_gen_ << indent() << "}" << endl; } indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_union(t_struct* tstruct) { string union_name(rust_struct_name(tstruct)); render_type_comment(union_name); render_union_definition(union_name, tstruct); render_union_impl(union_name, tstruct); } void t_rs_generator::render_union_definition(const string& union_name, t_struct* tstruct) { const vector& members = tstruct->get_sorted_members(); if (members.empty()) { throw "cannot generate rust enum with 0 members"; // may be valid thrift, but it's invalid rust } f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl; f_gen_ << "pub enum " << union_name << " {" << endl; indent_up(); vector::const_iterator member_iter; for(member_iter = members.begin(); member_iter != members.end(); ++member_iter) { t_field* tfield = (*member_iter); f_gen_ << indent() << rust_union_field_name(tfield) << "(" << to_rust_type(tfield->get_type()) << ")," << endl; } indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_union_impl(const string& union_name, t_struct* tstruct) { f_gen_ << "impl " << union_name << " {" << endl; indent_up(); render_union_sync_read(union_name, tstruct); render_union_sync_write(union_name, tstruct); indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } //----------------------------------------------------------------------------- // // Sync Struct Write // //----------------------------------------------------------------------------- void t_rs_generator::render_struct_sync_write( t_struct *tstruct, t_rs_generator::e_struct_type struct_type ) { f_gen_ << indent() << visibility_qualifier(struct_type) << "fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {" << endl; indent_up(); // write struct header to output protocol // note: use the *original* struct name here f_gen_ << indent() << "let struct_ident = TStructIdentifier::new(\"" + tstruct->get_name() + "\");" << endl; f_gen_ << indent() << "o_prot.write_struct_begin(&struct_ident)?;" << endl; // write struct members to output protocol vector members = tstruct->get_sorted_members(); if (!members.empty()) { vector::iterator members_iter; for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); t_field::e_req member_req = actual_field_req(member, struct_type); string member_var("self." + rust_field_name(member)); render_struct_field_sync_write(member_var, false, member, member_req); } } // write struct footer to output protocol f_gen_ << indent() << "o_prot.write_field_stop()?;" << endl; f_gen_ << indent() << "o_prot.write_struct_end()" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_union_sync_write(const string &union_name, t_struct *tstruct) { f_gen_ << indent() << "pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {" << endl; indent_up(); // write struct header to output protocol // note: use the *original* struct name here f_gen_ << indent() << "let struct_ident = TStructIdentifier::new(\"" + tstruct->get_name() + "\");" << endl; f_gen_ << indent() << "o_prot.write_struct_begin(&struct_ident)?;" << endl; // write the enum field to the output protocol vector members = tstruct->get_sorted_members(); if (!members.empty()) { f_gen_ << indent() << "match *self {" << endl; indent_up(); vector::iterator members_iter; for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); t_field::e_req member_req = t_field::T_REQUIRED; t_type* ttype = member->get_type(); if (ttype->is_typedef()) { // get the actual type of typedef ttype = ((t_typedef*)ttype)->get_type(); } string match_var((ttype->is_base_type() && !ttype->is_string()) ? "f" : "ref f"); f_gen_ << indent() << union_name << "::" << rust_union_field_name(member) << "(" << match_var << ") => {" << endl; indent_up(); render_struct_field_sync_write("f", true, member, member_req); indent_down(); f_gen_ << indent() << "}," << endl; } indent_down(); f_gen_ << indent() << "}" << endl; } // write struct footer to output protocol f_gen_ << indent() << "o_prot.write_field_stop()?;" << endl; f_gen_ << indent() << "o_prot.write_struct_end()" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_struct_field_sync_write( const string &field_var, bool field_var_is_ref, t_field *tfield, t_field::e_req req ) { t_type* field_type = tfield->get_type(); t_type* actual_type = get_true_type(field_type); ostringstream field_stream; field_stream << "TFieldIdentifier::new(" << "\"" << tfield->get_name() << "\"" << ", " // note: use *original* name << to_rust_field_type_enum(field_type) << ", " << tfield->get_key() << ")"; string field_ident_string = field_stream.str(); if (is_optional(req)) { string let_var((actual_type->is_base_type() && !actual_type->is_string()) ? "fld_var" : "ref fld_var"); f_gen_ << indent() << "if let Some(" << let_var << ") = " << field_var << " {" << endl; indent_up(); f_gen_ << indent() << "o_prot.write_field_begin(&" << field_ident_string << ")?;" << endl; render_type_sync_write("fld_var", true, field_type); f_gen_ << indent() << "o_prot.write_field_end()?" << endl; indent_down(); /* FIXME: rethink how I deal with OPT_IN_REQ_OUT if (req == t_field::T_OPT_IN_REQ_OUT) { f_gen_ << indent() << "let field_ident = " << field_ident_string << ";" << endl; f_gen_ << indent() << "o_prot.write_field_begin(&field_ident)?;" << endl; f_gen_ << indent() << "o_prot.write_field_end()?;" << endl; }*/ f_gen_ << indent() << "}" << endl; } else { f_gen_ << indent() << "o_prot.write_field_begin(&" << field_ident_string << ")?;" << endl; render_type_sync_write(field_var, field_var_is_ref, tfield->get_type()); f_gen_ << indent() << "o_prot.write_field_end()?;" << endl; } } void t_rs_generator::render_type_sync_write(const string &type_var, bool type_var_is_ref, t_type *ttype) { if (ttype->is_base_type()) { t_base_type* tbase_type = (t_base_type*)ttype; switch (tbase_type->get_base()) { case t_base_type::TYPE_VOID: throw "cannot write field of type TYPE_VOID to output protocol"; case t_base_type::TYPE_STRING: { string ref(type_var_is_ref ? "" : "&"); if (tbase_type->is_binary()) { f_gen_ << indent() << "o_prot.write_bytes(" + ref + type_var + ")?;" << endl; } else { f_gen_ << indent() << "o_prot.write_string(" + ref + type_var + ")?;" << endl; } return; } case t_base_type::TYPE_BOOL: f_gen_ << indent() << "o_prot.write_bool(" + type_var + ")?;" << endl; return; case t_base_type::TYPE_I8: f_gen_ << indent() << "o_prot.write_i8(" + type_var + ")?;" << endl; return; case t_base_type::TYPE_I16: f_gen_ << indent() << "o_prot.write_i16(" + type_var + ")?;" << endl; return; case t_base_type::TYPE_I32: f_gen_ << indent() << "o_prot.write_i32(" + type_var + ")?;" << endl; return; case t_base_type::TYPE_I64: f_gen_ << indent() << "o_prot.write_i64(" + type_var + ")?;" << endl; return; case t_base_type::TYPE_DOUBLE: f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl; return; } } else if (ttype->is_typedef()) { t_typedef* ttypedef = (t_typedef*) ttype; render_type_sync_write(type_var, type_var_is_ref, ttypedef->get_type()); return; } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { f_gen_ << indent() << type_var + ".write_to_out_protocol(o_prot)?;" << endl; return; } else if (ttype->is_map()) { render_map_sync_write(type_var, type_var_is_ref, (t_map *) ttype); return; } else if (ttype->is_set()) { render_set_sync_write(type_var, type_var_is_ref, (t_set *) ttype); return; } else if (ttype->is_list()) { render_list_sync_write(type_var, type_var_is_ref, (t_list *) ttype); return; } throw "cannot write unsupported type " + ttype->get_name(); } void t_rs_generator::render_list_sync_write(const string &list_var, bool list_var_is_ref, t_list *tlist) { t_type* elem_type = tlist->get_elem_type(); f_gen_ << indent() << "o_prot.write_list_begin(" << "&TListIdentifier::new(" << to_rust_field_type_enum(elem_type) << ", " << list_var << ".len() as i32" << ")" << ")?;" << endl; string ref(list_var_is_ref ? "" : "&"); f_gen_ << indent() << "for e in " << ref << list_var << " {" << endl; indent_up(); render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type); indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "o_prot.write_list_end()?;" << endl; } void t_rs_generator::render_set_sync_write(const string &set_var, bool set_var_is_ref, t_set *tset) { t_type* elem_type = tset->get_elem_type(); f_gen_ << indent() << "o_prot.write_set_begin(" << "&TSetIdentifier::new(" << to_rust_field_type_enum(elem_type) << ", " << set_var << ".len() as i32" << ")" << ")?;" << endl; string ref(set_var_is_ref ? "" : "&"); f_gen_ << indent() << "for e in " << ref << set_var << " {" << endl; indent_up(); render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type); indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "o_prot.write_set_end()?;" << endl; } void t_rs_generator::render_map_sync_write(const string &map_var, bool map_var_is_ref, t_map *tmap) { t_type* key_type = tmap->get_key_type(); t_type* val_type = tmap->get_val_type(); f_gen_ << indent() << "o_prot.write_map_begin(" << "&TMapIdentifier::new(" << to_rust_field_type_enum(key_type) << ", " << to_rust_field_type_enum(val_type) << ", " << map_var << ".len() as i32)" << ")?;" << endl; string ref(map_var_is_ref ? "" : "&"); f_gen_ << indent() << "for (k, v) in " << ref << map_var << " {" << endl; indent_up(); render_type_sync_write(string_container_write_variable(key_type, "k"), true, key_type); render_type_sync_write(string_container_write_variable(val_type, "v"), true, val_type); indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "o_prot.write_map_end()?;" << endl; } string t_rs_generator::string_container_write_variable(t_type* ttype, const string& base_var) { bool type_needs_deref = needs_deref_on_container_write(ttype); bool type_is_double = is_double(ttype); string write_variable; if (type_is_double && type_needs_deref) { write_variable = "(*" + base_var + ")"; } else if (type_needs_deref) { write_variable = "*" + base_var; } else { write_variable = base_var; } return write_variable; } bool t_rs_generator::needs_deref_on_container_write(t_type* ttype) { ttype = get_true_type(ttype); return ttype->is_base_type() && !ttype->is_string(); } //----------------------------------------------------------------------------- // // Sync Struct Read // //----------------------------------------------------------------------------- void t_rs_generator::render_struct_sync_read( const string &struct_name, t_struct *tstruct, t_rs_generator::e_struct_type struct_type ) { f_gen_ << indent() << visibility_qualifier(struct_type) << "fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<" << struct_name << "> {" << endl; indent_up(); f_gen_ << indent() << "i_prot.read_struct_begin()?;" << endl; // create temporary variables: one for each field in the struct const vector members = tstruct->get_sorted_members(); vector::const_iterator members_iter; for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); t_field::e_req member_req = actual_field_req(member, struct_type); f_gen_ << indent() << "let mut " << struct_field_read_temp_variable(member) << ": Option<" << to_rust_type(member->get_type()) << "> = "; if (member_req == t_field::T_OPT_IN_REQ_OUT) { f_gen_ << opt_in_req_out_value(member->get_type()) << ";"; } else { f_gen_ << "None;"; } f_gen_ << endl; } // now loop through the fields we've received f_gen_ << indent() << "loop {" << endl; // start loop indent_up(); // break out if you've found the Stop field f_gen_ << indent() << "let field_ident = i_prot.read_field_begin()?;" << endl; f_gen_ << indent() << "if field_ident.field_type == TType::Stop {" << endl; indent_up(); f_gen_ << indent() << "break;" << endl; indent_down(); f_gen_ << indent() << "}" << endl; // now read all the fields found f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl; f_gen_ << indent() << "match field_id {" << endl; // start match indent_up(); for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* tfield = (*members_iter); f_gen_ << indent() << rust_safe_field_id(tfield->get_key()) << " => {" << endl; indent_up(); render_type_sync_read("val", tfield->get_type()); f_gen_ << indent() << struct_field_read_temp_variable(tfield) << " = Some(val);" << endl; indent_down(); f_gen_ << indent() << "}," << endl; } // default case (skip fields) f_gen_ << indent() << "_ => {" << endl; indent_up(); f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl; indent_down(); f_gen_ << indent() << "}," << endl; indent_down(); f_gen_ << indent() << "};" << endl; // finish match f_gen_ << indent() << "i_prot.read_field_end()?;" << endl; indent_down(); f_gen_ << indent() << "}" << endl; // finish loop f_gen_ << indent() << "i_prot.read_struct_end()?;" << endl; // read message footer from the wire // verify that all required fields exist for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* tfield = (*members_iter); t_field::e_req req = actual_field_req(tfield, struct_type); if (!is_optional(req)) { f_gen_ << indent() << "verify_required_field_exists(" << "\"" << struct_name << "." << rust_field_name(tfield) << "\"" << ", " << "&" << struct_field_read_temp_variable(tfield) << ")?;" << endl; } } // construct the struct if (members.size() == 0) { f_gen_ << indent() << "let ret = " << struct_name << " {};" << endl; } else { f_gen_ << indent() << "let ret = " << struct_name << " {" << endl; indent_up(); for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* tfield = (*members_iter); t_field::e_req req = actual_field_req(tfield, struct_type); string field_name(rust_field_name(tfield)); string field_key = struct_field_read_temp_variable(tfield); if (is_optional(req)) { f_gen_ << indent() << field_name << ": " << field_key << "," << endl; } else { f_gen_ << indent() << field_name << ": " << field_key << ".expect(\"auto-generated code should have checked for presence of required fields\")" << "," << endl; } } indent_down(); f_gen_ << indent() << "};" << endl; } // return the constructed value f_gen_ << indent() << "Ok(ret)" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_union_sync_read(const string &union_name, t_struct *tstruct) { f_gen_ << indent() << "pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<" << union_name << "> {" << endl; indent_up(); // create temporary variables to hold the // completed union as well as a count of fields read f_gen_ << indent() << "let mut ret: Option<" << union_name << "> = None;" << endl; f_gen_ << indent() << "let mut received_field_count = 0;" << endl; // read the struct preamble f_gen_ << indent() << "i_prot.read_struct_begin()?;" << endl; // now loop through the fields we've received f_gen_ << indent() << "loop {" << endl; // start loop indent_up(); // break out if you've found the Stop field f_gen_ << indent() << "let field_ident = i_prot.read_field_begin()?;" << endl; f_gen_ << indent() << "if field_ident.field_type == TType::Stop {" << endl; indent_up(); f_gen_ << indent() << "break;" << endl; indent_down(); f_gen_ << indent() << "}" << endl; // now read all the fields found f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl; f_gen_ << indent() << "match field_id {" << endl; // start match indent_up(); const vector members = tstruct->get_sorted_members(); vector::const_iterator members_iter; for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); f_gen_ << indent() << rust_safe_field_id(member->get_key()) << " => {" << endl; indent_up(); render_type_sync_read("val", member->get_type()); f_gen_ << indent() << "if ret.is_none() {" << endl; indent_up(); f_gen_ << indent() << "ret = Some(" << union_name << "::" << rust_union_field_name(member) << "(val));" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "received_field_count += 1;" << endl; indent_down(); f_gen_ << indent() << "}," << endl; } // default case (skip fields) f_gen_ << indent() << "_ => {" << endl; indent_up(); f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl; f_gen_ << indent() << "received_field_count += 1;" << endl; indent_down(); f_gen_ << indent() << "}," << endl; indent_down(); f_gen_ << indent() << "};" << endl; // finish match f_gen_ << indent() << "i_prot.read_field_end()?;" << endl; indent_down(); f_gen_ << indent() << "}" << endl; // finish loop f_gen_ << indent() << "i_prot.read_struct_end()?;" << endl; // finish reading message from wire // return the value or an error f_gen_ << indent() << "if received_field_count == 0 {" << endl; indent_up(); render_thrift_error( "Protocol", "ProtocolError", "ProtocolErrorKind::InvalidData", "\"received empty union from remote " + union_name + "\"" ); indent_down(); f_gen_ << indent() << "} else if received_field_count > 1 {" << endl; indent_up(); render_thrift_error( "Protocol", "ProtocolError", "ProtocolErrorKind::InvalidData", "\"received multiple fields for union from remote " + union_name + "\"" ); indent_down(); f_gen_ << indent() << "} else {" << endl; indent_up(); f_gen_ << indent() << "Ok(ret.expect(\"return value should have been constructed\"))" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } // Construct the rust representation of all supported types from the wire. void t_rs_generator::render_type_sync_read(const string &type_var, t_type *ttype, bool is_boxed) { if (ttype->is_base_type()) { t_base_type* tbase_type = (t_base_type*)ttype; switch (tbase_type->get_base()) { case t_base_type::TYPE_VOID: throw "cannot read field of type TYPE_VOID from input protocol"; case t_base_type::TYPE_STRING: if (tbase_type->is_binary()) { f_gen_ << indent() << "let " << type_var << " = i_prot.read_bytes()?;" << endl; } else { f_gen_ << indent() << "let " << type_var << " = i_prot.read_string()?;" << endl; } return; case t_base_type::TYPE_BOOL: f_gen_ << indent() << "let " << type_var << " = i_prot.read_bool()?;" << endl; return; case t_base_type::TYPE_I8: f_gen_ << indent() << "let " << type_var << " = i_prot.read_i8()?;" << endl; return; case t_base_type::TYPE_I16: f_gen_ << indent() << "let " << type_var << " = i_prot.read_i16()?;" << endl; return; case t_base_type::TYPE_I32: f_gen_ << indent() << "let " << type_var << " = i_prot.read_i32()?;" << endl; return; case t_base_type::TYPE_I64: f_gen_ << indent() << "let " << type_var << " = i_prot.read_i64()?;" << endl; return; case t_base_type::TYPE_DOUBLE: f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl; return; } } else if (ttype->is_typedef()) { // FIXME: not a fan of separate `is_boxed` parameter // This is problematic because it's an optional parameter, and only comes // into play once. The core issue is that I lose an important piece of type // information (whether the type is a fwd ref) by unwrapping the typedef'd // type and making the recursive call using it. I can't modify or wrap the // generated string after the fact because it's written directly into the file, // so I have to pass this parameter along. Going with this approach because it // seems like the lowest-cost option to easily support recursive types. t_typedef* ttypedef = (t_typedef*)ttype; render_type_sync_read(type_var, ttypedef->get_type(), ttypedef->is_forward_typedef()); return; } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { string read_call(to_rust_type(ttype) + "::read_from_in_protocol(i_prot)?"); read_call = is_boxed ? "Box::new(" + read_call + ")" : read_call; f_gen_ << indent() << "let " << type_var << " = " << read_call << ";" << endl; return; } else if (ttype->is_map()) { render_map_sync_read((t_map *) ttype, type_var); return; } else if (ttype->is_set()) { render_set_sync_read((t_set *) ttype, type_var); return; } else if (ttype->is_list()) { render_list_sync_read((t_list *) ttype, type_var); return; } throw "cannot read unsupported type " + ttype->get_name(); } // Construct the rust representation of a list from the wire. void t_rs_generator::render_list_sync_read(t_list *tlist, const string &list_var) { t_type* elem_type = tlist->get_elem_type(); f_gen_ << indent() << "let list_ident = i_prot.read_list_begin()?;" << endl; f_gen_ << indent() << "let mut " << list_var << ": " << to_rust_type((t_type*) tlist) << " = Vec::with_capacity(list_ident.size as usize);" << endl; f_gen_ << indent() << "for _ in 0..list_ident.size {" << endl; indent_up(); string list_elem_var = tmp("list_elem_"); render_type_sync_read(list_elem_var, elem_type); f_gen_ << indent() << list_var << ".push(" << list_elem_var << ");" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "i_prot.read_list_end()?;" << endl; } // Construct the rust representation of a set from the wire. void t_rs_generator::render_set_sync_read(t_set *tset, const string &set_var) { t_type* elem_type = tset->get_elem_type(); f_gen_ << indent() << "let set_ident = i_prot.read_set_begin()?;" << endl; f_gen_ << indent() << "let mut " << set_var << ": " << to_rust_type((t_type*) tset) << " = BTreeSet::new();" << endl; f_gen_ << indent() << "for _ in 0..set_ident.size {" << endl; indent_up(); string set_elem_var = tmp("set_elem_"); render_type_sync_read(set_elem_var, elem_type); f_gen_ << indent() << set_var << ".insert(" << set_elem_var << ");" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "i_prot.read_set_end()?;" << endl; } // Construct the rust representation of a map from the wire. void t_rs_generator::render_map_sync_read(t_map *tmap, const string &map_var) { t_type* key_type = tmap->get_key_type(); t_type* val_type = tmap->get_val_type(); f_gen_ << indent() << "let map_ident = i_prot.read_map_begin()?;" << endl; f_gen_ << indent() << "let mut " << map_var << ": " << to_rust_type((t_type*) tmap) << " = BTreeMap::new();" << endl; f_gen_ << indent() << "for _ in 0..map_ident.size {" << endl; indent_up(); string key_elem_var = tmp("map_key_"); render_type_sync_read(key_elem_var, key_type); string val_elem_var = tmp("map_val_"); render_type_sync_read(val_elem_var, val_type); f_gen_ << indent() << map_var << ".insert(" << key_elem_var << ", " << val_elem_var << ");" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "i_prot.read_map_end()?;" << endl; } string t_rs_generator::struct_field_read_temp_variable(t_field* tfield) { std::ostringstream foss; foss << "f_" << rust_safe_field_id(tfield->get_key()); return foss.str(); } //----------------------------------------------------------------------------- // // Sync Client // //----------------------------------------------------------------------------- void t_rs_generator::generate_service(t_service* tservice) { render_sync_client(tservice); render_sync_processor(tservice); render_service_call_structs(tservice); } void t_rs_generator::render_service_call_structs(t_service* tservice) { const std::vector functions = tservice->get_functions(); std::vector::const_iterator func_iter; // thrift args for service calls are packed // into a struct that's transmitted over the wire, so // generate structs for those too // // thrift returns are *also* packed into a struct // that's passed over the wire, so, generate the struct // for that too. Note that this result struct *also* // contains the exceptions as well for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { t_function* tfunc = (*func_iter); render_service_call_args_struct(tfunc); if (!tfunc->is_oneway()) { render_service_call_result_value_struct(tfunc); } } } void t_rs_generator::render_sync_client(t_service* tservice) { string client_impl_name(rust_sync_client_impl_name(tservice)); render_type_comment(tservice->get_name() + " service client"); // note: use *original* name render_sync_client_trait(tservice); render_sync_client_marker_trait(tservice); render_sync_client_definition_and_impl(client_impl_name); render_sync_client_tthriftclient_impl(client_impl_name); render_sync_client_marker_trait_impls(tservice, client_impl_name); f_gen_ << endl; render_sync_client_process_impl(tservice); } void t_rs_generator::render_sync_client_trait(t_service *tservice) { string extension = ""; if (tservice->get_extends()) { t_service* extends = tservice->get_extends(); extension = " : " + rust_namespace(extends) + rust_sync_client_trait_name(extends); } render_rustdoc((t_doc*) tservice); f_gen_ << "pub trait " << rust_sync_client_trait_name(tservice) << extension << " {" << endl; indent_up(); const std::vector functions = tservice->get_functions(); std::vector::const_iterator func_iter; for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { t_function* tfunc = (*func_iter); string func_name = service_call_client_function_name(tfunc); string func_args = rust_sync_service_call_declaration(tfunc, true); string func_return = to_rust_type(tfunc->get_returntype()); render_rustdoc((t_doc*) tfunc); f_gen_ << indent() << "fn " << func_name << func_args << " -> thrift::Result<" << func_return << ">;" << endl; } indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_sync_client_marker_trait(t_service *tservice) { f_gen_ << indent() << "pub trait " << rust_sync_client_marker_trait_name(tservice) << " {}" << endl; f_gen_ << endl; } void t_rs_generator::render_sync_client_marker_trait_impls(t_service *tservice, const string &impl_struct_name) { f_gen_ << indent() << "impl " << SYNC_CLIENT_GENERIC_BOUND_VARS << " " << rust_namespace(tservice) << rust_sync_client_marker_trait_name(tservice) << " for " << impl_struct_name << SYNC_CLIENT_GENERIC_BOUND_VARS << " " << SYNC_CLIENT_GENERIC_BOUNDS << " {}" << endl; t_service* extends = tservice->get_extends(); if (extends) { render_sync_client_marker_trait_impls(extends, impl_struct_name); } } void t_rs_generator::render_sync_client_definition_and_impl(const string& client_impl_name) { // render the definition for the client struct f_gen_ << "pub struct " << client_impl_name << SYNC_CLIENT_GENERIC_BOUND_VARS << " " << SYNC_CLIENT_GENERIC_BOUNDS << " {" << endl; indent_up(); f_gen_ << indent() << "_i_prot: IP," << endl; f_gen_ << indent() << "_o_prot: OP," << endl; f_gen_ << indent() << "_sequence_number: i32," << endl; indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; // render the struct implementation // this includes the new() function as well as the helper send/recv methods for each service call f_gen_ << "impl " << SYNC_CLIENT_GENERIC_BOUND_VARS << " " << client_impl_name << SYNC_CLIENT_GENERIC_BOUND_VARS << " " << SYNC_CLIENT_GENERIC_BOUNDS << " {" << endl; indent_up(); render_sync_client_lifecycle_functions(client_impl_name); indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_sync_client_lifecycle_functions(const string& client_struct) { f_gen_ << indent() << "pub fn new(input_protocol: IP, output_protocol: OP) -> " << client_struct << SYNC_CLIENT_GENERIC_BOUND_VARS << " {" << endl; indent_up(); f_gen_ << indent() << client_struct << " { _i_prot: input_protocol, _o_prot: output_protocol, _sequence_number: 0 }" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_sync_client_tthriftclient_impl(const string &client_impl_name) { f_gen_ << indent() << "impl " << SYNC_CLIENT_GENERIC_BOUND_VARS << " TThriftClient for " << client_impl_name << SYNC_CLIENT_GENERIC_BOUND_VARS << " " << SYNC_CLIENT_GENERIC_BOUNDS << " {" << endl; indent_up(); f_gen_ << indent() << "fn i_prot_mut(&mut self) -> &mut dyn TInputProtocol { &mut self._i_prot }" << endl; f_gen_ << indent() << "fn o_prot_mut(&mut self) -> &mut dyn TOutputProtocol { &mut self._o_prot }" << endl; f_gen_ << indent() << "fn sequence_number(&self) -> i32 { self._sequence_number }" << endl; f_gen_ << indent() << "fn increment_sequence_number(&mut self) -> i32 { self._sequence_number += 1; self._sequence_number }" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_sync_client_process_impl(t_service* tservice) { string marker_extension = "" + sync_client_marker_traits_for_extension(tservice); f_gen_ << "impl " << rust_sync_client_trait_name(tservice) << " for C {" << endl; indent_up(); const std::vector functions = tservice->get_functions(); std::vector::const_iterator func_iter; for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { t_function* func = (*func_iter); render_sync_send_recv_wrapper(func); } indent_down(); f_gen_ << "}" << endl; f_gen_ << endl; } string t_rs_generator::sync_client_marker_traits_for_extension(t_service *tservice) { string marker_extension; t_service* extends = tservice->get_extends(); if (extends) { marker_extension = " + " + rust_namespace(extends) + rust_sync_client_marker_trait_name(extends); marker_extension = marker_extension + sync_client_marker_traits_for_extension(extends); } return marker_extension; } void t_rs_generator::render_sync_send_recv_wrapper(t_function* tfunc) { string func_name = service_call_client_function_name(tfunc); string func_decl_args = rust_sync_service_call_declaration(tfunc, true); string func_call_args = rust_sync_service_call_invocation(tfunc); string func_return = to_rust_type(tfunc->get_returntype()); f_gen_ << indent() << "fn " << func_name << func_decl_args << " -> thrift::Result<" << func_return << "> {" << endl; indent_up(); f_gen_ << indent() << "(" << endl; indent_up(); render_sync_send(tfunc); indent_down(); f_gen_ << indent() << ")?;" << endl; if (tfunc->is_oneway()) { f_gen_ << indent() << "Ok(())" << endl; } else { render_sync_recv(tfunc); } indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_sync_send(t_function* tfunc) { f_gen_ << indent() << "{" << endl; indent_up(); // increment the sequence number and generate the call header string message_type = tfunc->is_oneway() ? "TMessageType::OneWay" : "TMessageType::Call"; f_gen_ << indent() << "self.increment_sequence_number();" << endl; f_gen_ << indent() << "let message_ident = " << "TMessageIdentifier::new(\"" << tfunc->get_name() << "\", " // note: use *original* name << message_type << ", " << "self.sequence_number());" << endl; // pack the arguments into the containing struct that we'll write out over the wire // note that this struct is generated even if we have 0 args ostringstream struct_definition; vector members = tfunc->get_arglist()->get_sorted_members(); vector::iterator members_iter; for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* member = (*members_iter); string member_name(rust_field_name(member)); struct_definition << member_name << ", "; } string struct_fields = struct_definition.str(); if (struct_fields.size() > 0) { struct_fields = struct_fields.substr(0, struct_fields.size() - 2); // strip trailing comma } f_gen_ << indent() << "let call_args = " << service_call_args_struct_name(tfunc) << " { " << struct_fields << " };" << endl; // write everything over the wire f_gen_ << indent() << "self.o_prot_mut().write_message_begin(&message_ident)?;" << endl; f_gen_ << indent() << "call_args.write_to_out_protocol(self.o_prot_mut())?;" << endl; // written even if we have 0 args f_gen_ << indent() << "self.o_prot_mut().write_message_end()?;" << endl; f_gen_ << indent() << "self.o_prot_mut().flush()" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_sync_recv(t_function* tfunc) { f_gen_ << indent() << "{" << endl; indent_up(); f_gen_ << indent() << "let message_ident = self.i_prot_mut().read_message_begin()?;" << endl; f_gen_ << indent() << "verify_expected_sequence_number(self.sequence_number(), message_ident.sequence_number)?;" << endl; f_gen_ << indent() << "verify_expected_service_call(\"" << tfunc->get_name() <<"\", &message_ident.name)?;" << endl; // note: use *original* name // FIXME: replace with a "try" block f_gen_ << indent() << "if message_ident.message_type == TMessageType::Exception {" << endl; indent_up(); f_gen_ << indent() << "let remote_error = thrift::Error::read_application_error_from_in_protocol(self.i_prot_mut())?;" << endl; f_gen_ << indent() << "self.i_prot_mut().read_message_end()?;" << endl; f_gen_ << indent() << "return Err(thrift::Error::Application(remote_error))" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "verify_expected_message_type(TMessageType::Reply, message_ident.message_type)?;" << endl; f_gen_ << indent() << "let result = " << service_call_result_struct_name(tfunc) << "::read_from_in_protocol(self.i_prot_mut())?;" << endl; f_gen_ << indent() << "self.i_prot_mut().read_message_end()?;" << endl; f_gen_ << indent() << "result.ok_or()" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } string t_rs_generator::rust_sync_service_call_declaration(t_function* tfunc, bool self_is_mutable) { ostringstream func_args; if (self_is_mutable) { func_args << "(&mut self"; } else { func_args << "(&self"; } if (has_args(tfunc)) { func_args << ", "; // put comma after "self" func_args << struct_to_declaration(tfunc->get_arglist(), T_ARGS); } func_args << ")"; return func_args.str(); } string t_rs_generator::rust_sync_service_call_invocation(t_function* tfunc, const string& field_prefix) { ostringstream func_args; func_args << "("; if (has_args(tfunc)) { func_args << struct_to_invocation(tfunc->get_arglist(), field_prefix); } func_args << ")"; return func_args.str(); } string t_rs_generator::struct_to_declaration(t_struct* tstruct, t_rs_generator::e_struct_type struct_type) { ostringstream args; bool first_arg = true; std::vector fields = tstruct->get_sorted_members(); std::vector::iterator field_iter; for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) { t_field* tfield = (*field_iter); t_field::e_req field_req = actual_field_req(tfield, struct_type); string rust_type = to_rust_type(tfield->get_type()); rust_type = is_optional(field_req) ? "Option<" + rust_type + ">" : rust_type; if (first_arg) { first_arg = false; } else { args << ", "; } args << rust_field_name(tfield) << ": " << rust_type; } return args.str(); } string t_rs_generator::struct_to_invocation(t_struct* tstruct, const string& field_prefix) { ostringstream args; bool first_arg = true; std::vector fields = tstruct->get_sorted_members(); std::vector::iterator field_iter; for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) { t_field* tfield = (*field_iter); if (first_arg) { first_arg = false; } else { args << ", "; } args << field_prefix << rust_field_name(tfield); } return args.str(); } void t_rs_generator::render_service_call_args_struct(t_function* tfunc) { string args_struct_name(service_call_args_struct_name(tfunc)); render_struct(args_struct_name, tfunc->get_arglist(), t_rs_generator::T_ARGS); } void t_rs_generator::render_service_call_result_value_struct(t_function* tfunc) { string result_struct_name = service_call_result_struct_name(tfunc); t_struct result(program_, result_struct_name); t_field return_value(tfunc->get_returntype(), SERVICE_RESULT_VARIABLE, 0); return_value.set_req(t_field::T_OPTIONAL); if (!tfunc->get_returntype()->is_void()) { result.append(&return_value); } t_struct* exceptions = tfunc->get_xceptions(); const vector& exception_types = exceptions->get_members(); vector::const_iterator exception_iter; for(exception_iter = exception_types.begin(); exception_iter != exception_types.end(); ++exception_iter) { t_field* exception_type = *exception_iter; exception_type->set_req(t_field::T_OPTIONAL); result.append(exception_type); } render_struct(result_struct_name, &result, t_rs_generator::T_RESULT); } //----------------------------------------------------------------------------- // // Sync Processor // //----------------------------------------------------------------------------- void t_rs_generator::render_sync_processor(t_service *tservice) { render_type_comment(tservice->get_name() + " service processor"); // note: use *original* name render_sync_handler_trait(tservice); render_sync_processor_definition_and_impl(tservice); } void t_rs_generator::render_sync_handler_trait(t_service *tservice) { string extension = ""; if (tservice->get_extends() != nullptr) { t_service* extends = tservice->get_extends(); extension = " : " + rust_namespace(extends) + rust_sync_handler_trait_name(extends); } const std::vector functions = tservice->get_functions(); std::vector::const_iterator func_iter; render_rustdoc((t_doc*) tservice); f_gen_ << "pub trait " << rust_sync_handler_trait_name(tservice) << extension << " {" << endl; indent_up(); for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { t_function* tfunc = (*func_iter); string func_name = service_call_handler_function_name(tfunc); string func_args = rust_sync_service_call_declaration(tfunc, false); string func_return = to_rust_type(tfunc->get_returntype()); render_rustdoc((t_doc*) tfunc); f_gen_ << indent() << "fn " << func_name << func_args << " -> thrift::Result<" << func_return << ">;" << endl; } indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_sync_processor_definition_and_impl(t_service *tservice) { string service_processor_name = rust_sync_processor_name(tservice); string handler_trait_name = rust_sync_handler_trait_name(tservice); // struct f_gen_ << indent() << "pub struct " << service_processor_name << " {" << endl; indent_up(); f_gen_ << indent() << "handler: H," << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; // delegating impl f_gen_ << indent() << "impl " << service_processor_name << " {" << endl; indent_up(); f_gen_ << indent() << "pub fn new(handler: H) -> " << service_processor_name << " {" << endl; indent_up(); f_gen_ << indent() << service_processor_name << " {" << endl; indent_up(); f_gen_ << indent() << "handler," << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << indent() << "}" << endl; render_sync_process_delegation_functions(tservice); indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; // actual impl string service_actual_processor_name = rust_sync_processor_impl_name(tservice); f_gen_ << indent() << "pub struct " << service_actual_processor_name << ";" << endl; f_gen_ << endl; f_gen_ << indent() << "impl " << service_actual_processor_name << " {" << endl; indent_up(); vector functions = tservice->get_functions(); vector::iterator func_iter; for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { t_function* tfunc = (*func_iter); render_sync_process_function(tfunc, handler_trait_name); } indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; // processor impl f_gen_ << indent() << "impl TProcessor for " << service_processor_name << " {" << endl; indent_up(); f_gen_ << indent() << "fn process(&self, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {" << endl; indent_up(); f_gen_ << indent() << "let message_ident = i_prot.read_message_begin()?;" << endl; f_gen_ << indent() << "let res = match &*message_ident.name {" << endl; // [sigh] explicit deref coercion indent_up(); render_process_match_statements(tservice); f_gen_ << indent() << "method => {" << endl; indent_up(); render_thrift_error( "Application", "ApplicationError", "ApplicationErrorKind::UnknownMethod", "format!(\"unknown method {}\", method)" ); indent_down(); f_gen_ << indent() << "}," << endl; indent_down(); f_gen_ << indent() << "};" << endl; f_gen_ << indent() << "thrift::server::handle_process_result(&message_ident, res, o_prot)" << endl; indent_down(); f_gen_ << indent() << "}" << endl; indent_down(); f_gen_ << indent() << "}" << endl; f_gen_ << endl; } void t_rs_generator::render_sync_process_delegation_functions(t_service *tservice) { string actual_processor(rust_namespace(tservice) + rust_sync_processor_impl_name(tservice)); vector functions = tservice->get_functions(); vector::iterator func_iter; for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { t_function* tfunc = (*func_iter); string function_name("process_" + rust_snake_case(tfunc->get_name())); f_gen_ << indent() << "fn " << function_name << "(&self, " << "incoming_sequence_number: i32, " << "i_prot: &mut dyn TInputProtocol, " << "o_prot: &mut dyn TOutputProtocol) " << "-> thrift::Result<()> {" << endl; indent_up(); f_gen_ << indent() << actual_processor << "::" << function_name << "(" << "&self.handler, " << "incoming_sequence_number, " << "i_prot, " << "o_prot" << ")" << endl; indent_down(); f_gen_ << indent() << "}" << endl; } t_service* extends = tservice->get_extends(); if (extends) { render_sync_process_delegation_functions(extends); } } void t_rs_generator::render_process_match_statements(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator func_iter; for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) { t_function* tfunc = (*func_iter); f_gen_ << indent() << "\"" << tfunc->get_name() << "\"" << " => {" << endl; // note: use *original* name indent_up(); f_gen_ << indent() << "self.process_" << rust_snake_case(tfunc->get_name()) << "(message_ident.sequence_number, i_prot, o_prot)" << endl; indent_down(); f_gen_ << indent() << "}," << endl; } t_service* extends = tservice->get_extends(); if (extends) { render_process_match_statements(extends); } } void t_rs_generator::render_sync_process_function(t_function *tfunc, const string &handler_type) { string sequence_number_param("incoming_sequence_number"); string output_protocol_param("o_prot"); if (tfunc->is_oneway()) { sequence_number_param = "_"; output_protocol_param = "_"; } f_gen_ << indent() << "pub fn process_" << rust_snake_case(tfunc->get_name()) << "" << "(handler: &H, " << sequence_number_param << ": i32, " << "i_prot: &mut dyn TInputProtocol, " << output_protocol_param << ": &mut dyn TOutputProtocol) " << "-> thrift::Result<()> {" << endl; indent_up(); // *always* read arguments from the input protocol f_gen_ << indent() << "let " << (has_non_void_args(tfunc) ? "args" : "_") << " = " << service_call_args_struct_name(tfunc) << "::read_from_in_protocol(i_prot)?;" << endl; f_gen_ << indent() << "match handler." << service_call_handler_function_name(tfunc) << rust_sync_service_call_invocation(tfunc, "args.") << " {" << endl; // start match indent_up(); // handler succeeded string handler_return_variable = tfunc->is_oneway() || tfunc->get_returntype()->is_void() ? "_" : "handler_return"; f_gen_ << indent() << "Ok(" << handler_return_variable << ") => {" << endl; indent_up(); render_sync_handler_succeeded(tfunc); indent_down(); f_gen_ << indent() << "}," << endl; // handler failed f_gen_ << indent() << "Err(e) => {" << endl; indent_up(); render_sync_handler_failed(tfunc); indent_down(); f_gen_ << indent() << "}," << endl; indent_down(); f_gen_ << indent() << "}" << endl; // end match indent_down(); f_gen_ << indent() << "}" << endl; // end function } void t_rs_generator::render_sync_handler_succeeded(t_function *tfunc) { if (tfunc->is_oneway()) { f_gen_ << indent() << "Ok(())" << endl; } else { f_gen_ << indent() << "let message_ident = TMessageIdentifier::new(" << "\"" << tfunc->get_name() << "\", " // note: use *original* name << "TMessageType::Reply, " << "incoming_sequence_number);" << endl; f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl; f_gen_ << indent() << "let ret = " << handler_successful_return_struct(tfunc) <<";" << endl; f_gen_ << indent() << "ret.write_to_out_protocol(o_prot)?;" << endl; f_gen_ << indent() << "o_prot.write_message_end()?;" << endl; f_gen_ << indent() << "o_prot.flush()" << endl; } } void t_rs_generator::render_sync_handler_failed(t_function *tfunc) { string err_var("e"); f_gen_ << indent() << "match " << err_var << " {" << endl; indent_up(); // if there are any user-defined exceptions for this service call handle them first if (tfunc->get_xceptions() != nullptr && tfunc->get_xceptions()->get_sorted_members().size() > 0) { string user_err_var("usr_err"); f_gen_ << indent() << "thrift::Error::User(" << user_err_var << ") => {" << endl; indent_up(); render_sync_handler_failed_user_exception_branch(tfunc); indent_down(); f_gen_ << indent() << "}," << endl; } // application error string app_err_var("app_err"); f_gen_ << indent() << "thrift::Error::Application(" << app_err_var << ") => {" << endl; indent_up(); render_sync_handler_failed_application_exception_branch(tfunc, app_err_var); indent_down(); f_gen_ << indent() << "}," << endl; // default case f_gen_ << indent() << "_ => {" << endl; indent_up(); render_sync_handler_failed_default_exception_branch(tfunc); indent_down(); f_gen_ << indent() << "}," << endl; indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_sync_handler_failed_user_exception_branch(t_function *tfunc) { if (tfunc->get_xceptions() == nullptr || tfunc->get_xceptions()->get_sorted_members().empty()) { throw "cannot render user exception branches if no user exceptions defined"; } const vector txceptions = tfunc->get_xceptions()->get_sorted_members(); vector::const_iterator xception_iter; int branches_rendered = 0; // run through all user-defined exceptions for (xception_iter = txceptions.begin(); xception_iter != txceptions.end(); ++xception_iter) { t_field* xception_field = (*xception_iter); string if_statement(branches_rendered == 0 ? "if usr_err" : "} else if usr_err"); string exception_type(to_rust_type(xception_field->get_type())); f_gen_ << indent() << if_statement << ".downcast_ref::<" << exception_type << ">().is_some() {" << endl; indent_up(); f_gen_ << indent() << "let err = usr_err.downcast::<" << exception_type << ">().expect(\"downcast already checked\");" << endl; // render the members of the return struct ostringstream members; bool has_result_variable = !(tfunc->is_oneway() || tfunc->get_returntype()->is_void()); if (has_result_variable) { members << SERVICE_RESULT_VARIABLE << ": None, "; } vector::const_iterator xception_members_iter; for(xception_members_iter = txceptions.begin(); xception_members_iter != txceptions.end(); ++xception_members_iter) { t_field* member = (*xception_members_iter); string member_name(rust_field_name(member)); if (member == xception_field) { members << member_name << ": Some(*err), "; } else { members << member_name << ": None, "; } } string member_string = members.str(); member_string.replace(member_string.size() - 2, 2, " "); // trim trailing comma // now write out the return struct f_gen_ << indent() << "let ret_err = " << service_call_result_struct_name(tfunc) << "{ " << member_string << "};" << endl; f_gen_ << indent() << "let message_ident = " << "TMessageIdentifier::new(" << "\"" << tfunc->get_name() << "\", " // note: use *original* name << "TMessageType::Reply, " << "incoming_sequence_number);" << endl; f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl; f_gen_ << indent() << "ret_err.write_to_out_protocol(o_prot)?;" << endl; f_gen_ << indent() << "o_prot.write_message_end()?;" << endl; f_gen_ << indent() << "o_prot.flush()" << endl; indent_down(); branches_rendered++; } // the catch all, if somehow it was a user exception that we don't support f_gen_ << indent() << "} else {" << endl; indent_up(); // FIXME: same as default block below f_gen_ << indent() << "let ret_err = {" << endl; indent_up(); render_thrift_error_struct("ApplicationError", "ApplicationErrorKind::Unknown", "usr_err.to_string()"); indent_down(); f_gen_ << indent() << "};" << endl; render_sync_handler_send_exception_response(tfunc, "ret_err"); indent_down(); f_gen_ << indent() << "}" << endl; } void t_rs_generator::render_sync_handler_failed_application_exception_branch( t_function *tfunc, const string &app_err_var ) { if (tfunc->is_oneway()) { f_gen_ << indent() << "Err(thrift::Error::Application(" << app_err_var << "))" << endl; } else { render_sync_handler_send_exception_response(tfunc, app_err_var); } } void t_rs_generator::render_sync_handler_failed_default_exception_branch(t_function *tfunc) { f_gen_ << indent() << "let ret_err = {" << endl; indent_up(); render_thrift_error_struct("ApplicationError", "ApplicationErrorKind::Unknown", "e.to_string()"); indent_down(); f_gen_ << indent() << "};" << endl; if (tfunc->is_oneway()) { f_gen_ << indent() << "Err(thrift::Error::Application(ret_err))" << endl; } else { render_sync_handler_send_exception_response(tfunc, "ret_err"); } } void t_rs_generator::render_sync_handler_send_exception_response(t_function *tfunc, const string &err_var) { f_gen_ << indent() << "let message_ident = TMessageIdentifier::new(" << "\"" << tfunc->get_name() << "\", " // note: use *original* name << "TMessageType::Exception, " << "incoming_sequence_number);" << endl; f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl; f_gen_ << indent() << "thrift::Error::write_application_error_to_out_protocol(&" << err_var << ", o_prot)?;" << endl; f_gen_ << indent() << "o_prot.write_message_end()?;" << endl; f_gen_ << indent() << "o_prot.flush()" << endl; } string t_rs_generator::handler_successful_return_struct(t_function* tfunc) { int member_count = 0; ostringstream return_struct; return_struct << service_call_result_struct_name(tfunc) << " { "; // actual return if (!tfunc->get_returntype()->is_void()) { return_struct << "result_value: Some(handler_return)"; member_count++; } // any user-defined exceptions if (tfunc->get_xceptions() != nullptr) { t_struct* txceptions = tfunc->get_xceptions(); const vector members = txceptions->get_sorted_members(); vector::const_iterator members_iter; for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) { t_field* xception_field = (*members_iter); if (member_count > 0) { return_struct << ", "; } return_struct << rust_field_name(xception_field) << ": None"; member_count++; } } return_struct << " }"; return return_struct.str(); } //----------------------------------------------------------------------------- // // Utility // //----------------------------------------------------------------------------- void t_rs_generator::render_type_comment(const string& type_name) { f_gen_ << "//" << endl; f_gen_ << "// " << type_name << endl; f_gen_ << "//" << endl; f_gen_ << endl; } // NOTE: do *not* put in an extra newline after doc is generated. // This is because rust docs have to abut the line they're documenting. void t_rs_generator::render_rustdoc(t_doc* tdoc) { if (!tdoc->has_doc()) { return; } generate_docstring_comment(f_gen_, "", "/// ", tdoc->get_doc(), ""); } void t_rs_generator::render_thrift_error( const string& error_kind, const string& error_struct, const string& sub_error_kind, const string& error_message ) { f_gen_ << indent() << "Err(" << endl; indent_up(); f_gen_ << indent() << "thrift::Error::" << error_kind << "(" << endl; indent_up(); render_thrift_error_struct(error_struct, sub_error_kind, error_message); indent_down(); f_gen_ << indent() << ")" << endl; indent_down(); f_gen_ << indent() << ")" << endl; } void t_rs_generator::render_thrift_error_struct( const string& error_struct, const string& sub_error_kind, const string& error_message ) { f_gen_ << indent() << error_struct << "::new(" << endl; indent_up(); f_gen_ << indent() << sub_error_kind << "," << endl; f_gen_ << indent() << error_message << endl; indent_down(); f_gen_ << indent() << ")" << endl; } bool t_rs_generator::is_double(t_type* ttype) { ttype = get_true_type(ttype); if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); if (tbase == t_base_type::TYPE_DOUBLE) { return true; } } return false; } string t_rs_generator::to_rust_type(t_type* ttype) { // ttype = get_true_type(ttype); <-- recurses through as many typedef layers as necessary if (ttype->is_base_type()) { t_base_type* tbase_type = ((t_base_type*)ttype); switch (tbase_type->get_base()) { case t_base_type::TYPE_VOID: return "()"; case t_base_type::TYPE_STRING: if (tbase_type->is_binary()) { return "Vec"; } else { return "String"; } case t_base_type::TYPE_BOOL: return "bool"; case t_base_type::TYPE_I8: return "i8"; case t_base_type::TYPE_I16: return "i16"; case t_base_type::TYPE_I32: return "i32"; case t_base_type::TYPE_I64: return "i64"; case t_base_type::TYPE_DOUBLE: return "OrderedFloat"; } } else if (ttype->is_typedef()) { t_typedef* ttypedef = (t_typedef*)ttype; string rust_type = rust_namespace(ttype) + ttypedef->get_symbolic(); rust_type = ttypedef->is_forward_typedef() ? "Box<" + rust_type + ">" : rust_type; return rust_type; } else if (ttype->is_enum()) { return rust_namespace(ttype) + rust_camel_case(ttype->get_name()); } else if (ttype->is_struct() || ttype->is_xception()) { return rust_namespace(ttype) + rust_camel_case(ttype->get_name()); } else if (ttype->is_map()) { t_map* tmap = (t_map*)ttype; return "BTreeMap<" + to_rust_type(tmap->get_key_type()) + ", " + to_rust_type(tmap->get_val_type()) + ">"; } else if (ttype->is_set()) { t_set* tset = (t_set*)ttype; return "BTreeSet<" + to_rust_type(tset->get_elem_type()) + ">"; } else if (ttype->is_list()) { t_list* tlist = (t_list*)ttype; return "Vec<" + to_rust_type(tlist->get_elem_type()) + ">"; } throw "cannot find rust type for " + ttype->get_name(); } string t_rs_generator::to_rust_const_type(t_type* ttype) { if (ttype->is_base_type()) { t_base_type* tbase_type = ((t_base_type*)ttype); if (tbase_type->get_base() == t_base_type::TYPE_STRING) { if (tbase_type->is_binary()) { return "&[u8]"; } else { return "&str"; } } } return to_rust_type(ttype); } string t_rs_generator::to_rust_field_type_enum(t_type* ttype) { ttype = get_true_type(ttype); if (ttype->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "will not generate protocol::TType for TYPE_VOID"; case t_base_type::TYPE_STRING: // both strings and binary are actually encoded as TType::String return "TType::String"; case t_base_type::TYPE_BOOL: return "TType::Bool"; case t_base_type::TYPE_I8: return "TType::I08"; case t_base_type::TYPE_I16: return "TType::I16"; case t_base_type::TYPE_I32: return "TType::I32"; case t_base_type::TYPE_I64: return "TType::I64"; case t_base_type::TYPE_DOUBLE: return "TType::Double"; } } else if (ttype->is_enum()) { return "TType::I32"; } else if (ttype->is_struct() || ttype->is_xception()) { return "TType::Struct"; } else if (ttype->is_map()) { return "TType::Map"; } else if (ttype->is_set()) { return "TType::Set"; } else if (ttype->is_list()) { return "TType::List"; } throw "cannot find TType for " + ttype->get_name(); } string t_rs_generator::opt_in_req_out_value(t_type* ttype) { ttype = get_true_type(ttype); if (ttype->is_base_type()) { t_base_type* tbase_type = ((t_base_type*)ttype); switch (tbase_type->get_base()) { case t_base_type::TYPE_VOID: throw "cannot generate OPT_IN_REQ_OUT value for void"; case t_base_type::TYPE_STRING: if (tbase_type->is_binary()) { return "Some(Vec::new())"; } else { return "Some(\"\".to_owned())"; } case t_base_type::TYPE_BOOL: return "Some(false)"; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: return "Some(0)"; case t_base_type::TYPE_DOUBLE: return "Some(OrderedFloat::from(0.0))"; } } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { return "None"; } else if (ttype->is_list()) { return "Some(Vec::new())"; } else if (ttype->is_set()) { return "Some(BTreeSet::new())"; } else if (ttype->is_map()) { return "Some(BTreeMap::new())"; } throw "cannot generate opt-in-req-out value for type " + ttype->get_name(); } bool t_rs_generator::can_generate_simple_const(t_type* ttype) { t_type* actual_type = get_true_type(ttype); if (actual_type->is_base_type()) { t_base_type* tbase_type = (t_base_type*)actual_type; return !(tbase_type->get_base() == t_base_type::TYPE_DOUBLE); } else { return false; } } bool t_rs_generator::can_generate_const_holder(t_type* ttype) { t_type* actual_type = get_true_type(ttype); return !can_generate_simple_const(actual_type) && !actual_type->is_service(); } bool t_rs_generator::is_void(t_type* ttype) { return ttype->is_base_type() && ((t_base_type*)ttype)->get_base() == t_base_type::TYPE_VOID; } bool t_rs_generator::is_optional(t_field::e_req req) { return req == t_field::T_OPTIONAL || req == t_field::T_OPT_IN_REQ_OUT; } t_field::e_req t_rs_generator::actual_field_req(t_field* tfield, t_rs_generator::e_struct_type struct_type) { return struct_type == t_rs_generator::T_ARGS ? t_field::T_REQUIRED : tfield->get_req(); } bool t_rs_generator::has_args(t_function* tfunc) { return tfunc->get_arglist() != nullptr && !tfunc->get_arglist()->get_sorted_members().empty(); } bool t_rs_generator::has_non_void_args(t_function* tfunc) { bool has_non_void_args = false; const vector args = tfunc->get_arglist()->get_sorted_members(); vector::const_iterator args_iter; for (args_iter = args.begin(); args_iter != args.end(); ++args_iter) { t_field* tfield = (*args_iter); if (!tfield->get_type()->is_void()) { has_non_void_args = true; break; } } return has_non_void_args; } string t_rs_generator::visibility_qualifier(t_rs_generator::e_struct_type struct_type) { switch(struct_type) { case t_rs_generator::T_ARGS: case t_rs_generator::T_RESULT: return ""; default: return "pub "; } } string t_rs_generator::rust_namespace(t_service* tservice) { if (tservice->get_program()->get_name() != get_program()->get_name()) { return rust_snake_case(tservice->get_program()->get_name()) + "::"; } else { return ""; } } string t_rs_generator::rust_namespace(t_type* ttype) { if (ttype->get_program()->get_name() != get_program()->get_name()) { return rust_snake_case(ttype->get_program()->get_name()) + "::"; } else { return ""; } } bool t_rs_generator::is_reserved(const string& name) { return RUST_RESERVED_WORDS_SET.find(name) != RUST_RESERVED_WORDS_SET.end(); } string t_rs_generator::rust_struct_name(t_struct* tstruct) { string base_struct_name(rust_camel_case(tstruct->get_name())); return rust_safe_name(base_struct_name); } string t_rs_generator::rust_field_name(t_field* tfield) { string base_field_name(rust_snake_case(tfield->get_name())); return rust_safe_name(base_field_name); } string t_rs_generator::rust_union_field_name(t_field* tfield) { string base_field_name(rust_camel_case(tfield->get_name())); return rust_safe_name(base_field_name); } string t_rs_generator::rust_safe_name(const string& name) { if (is_reserved(name)) { return name + "_"; } else { return name; } } string t_rs_generator::service_call_client_function_name(t_function* tfunc) { return rust_snake_case(tfunc->get_name()); } string t_rs_generator::service_call_handler_function_name(t_function* tfunc) { return "handle_" + rust_snake_case(tfunc->get_name()); } string t_rs_generator::service_call_args_struct_name(t_function* tfunc) { // Thrift automatically appends `Args` to the arglist name. No need to do it here. return rust_camel_case(service_name_) + rust_camel_case(tfunc->get_arglist()->get_name()); } string t_rs_generator::service_call_result_struct_name(t_function* tfunc) { return rust_camel_case(service_name_) + rust_camel_case(tfunc->get_name()) + RESULT_STRUCT_SUFFIX; } string t_rs_generator::rust_sync_client_marker_trait_name(t_service* tservice) { return "T" + rust_camel_case(tservice->get_name()) + "SyncClientMarker"; } string t_rs_generator::rust_sync_client_trait_name(t_service* tservice) { return "T" + rust_camel_case(tservice->get_name()) + "SyncClient"; } string t_rs_generator::rust_sync_client_impl_name(t_service* tservice) { return rust_camel_case(tservice->get_name()) + "SyncClient"; } string t_rs_generator::rust_sync_handler_trait_name(t_service* tservice) { return rust_camel_case(tservice->get_name()) + "SyncHandler"; } string t_rs_generator::rust_sync_processor_name(t_service* tservice) { return rust_camel_case(tservice->get_name()) + "SyncProcessor"; } string t_rs_generator::rust_sync_processor_impl_name(t_service *tservice) { return "T" + rust_camel_case(tservice->get_name()) + "ProcessFunctions"; } string t_rs_generator::rust_enum_variant_name(const string &name) { bool all_uppercase = true; for (char i : name) { if (isalpha(i) && islower(i)) { all_uppercase = false; break; } } if (all_uppercase) { return name; } else { string modified_name(uppercase(underscore(name))); string_replace(modified_name, "__", "_"); return modified_name; } } string t_rs_generator::rust_upper_case(const string& name) { bool all_uppercase = true; for (char i : name) { if (isalpha(i) && islower(i)) { all_uppercase = false; break; } } if (all_uppercase) { return name; } else { string str(uppercase(underscore(name))); string_replace(str, "__", "_"); return str; } } string t_rs_generator::rust_snake_case(const string& name) { string str(decapitalize(underscore(name))); string_replace(str, "__", "_"); return str; } string t_rs_generator::rust_camel_case(const string& name) { string str(capitalize(camelcase(name))); string_replace(str, "_", ""); return str; } string t_rs_generator::rust_safe_field_id(int32_t id) { string id_str = std::to_string(abs(id)); if (id >= 0) { return id_str; } else { string str("neg"); str += id_str; return str; } } void t_rs_generator::string_replace(string& target, const string& search_string, const string& replace_string) { if (target.empty()) { return; } size_t match_len = search_string.length(); size_t replace_len = replace_string.length(); size_t search_idx = 0; size_t match_idx; while ((match_idx = target.find(search_string, search_idx)) != string::npos) { target.replace(match_idx, match_len, replace_string); search_idx = match_idx + replace_len; } } THRIFT_REGISTER_GENERATOR( rs, "Rust", "\n") // no Rust-generator-specific options thrift-0.16.0/compiler/cpp/src/thrift/generate/t_st_generator.cc000066400000000000000000001000521420101504100246630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ #include #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/version.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ofstream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * Smalltalk code generator. * */ class t_st_generator : public t_oop_generator { public: t_st_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_oop_generator(program) { (void)option_string; temporary_var = 0; std::map::const_iterator iter; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option st:" + iter->first; } out_dir_base_ = "gen-st"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_const(t_const* tconst) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void generate_class_side_definition(); void generate_force_consts(); std::string render_const_value(t_type* type, t_const_value* value); /** * Struct generation code */ void generate_st_struct(std::ostream& out, t_struct* tstruct, bool is_exception); void generate_accessors(std::ostream& out, t_struct* tstruct); /** * Service-level generation functions */ void generate_service_client(t_service* tservice); void generate_send_method(t_function* tfunction); void generate_recv_method(t_function* tfunction); std::string map_reader(t_map* tmap); std::string list_reader(t_list* tlist); std::string set_reader(t_set* tset); std::string struct_reader(t_struct* tstruct, std::string clsName); std::string map_writer(t_map* tmap, std::string name); std::string list_writer(t_list* tlist, std::string name); std::string set_writer(t_set* tset, std::string name); std::string struct_writer(t_struct* tstruct, std::string fname); std::string write_val(t_type* t, std::string fname); std::string read_val(t_type* t); /** * Helper rendering functions */ std::string st_autogen_comment(); void st_class_def(std::ostream& out, std::string name); void st_method(std::ostream& out, std::string cls, std::string name); void st_method(std::ostream& out, std::string cls, std::string name, std::string category); void st_close_method(std::ostream& out); void st_class_method(std::ostream& out, std::string cls, std::string name); void st_class_method(std::ostream& out, std::string cls, std::string name, std::string category); void st_setter(std::ostream& out, std::string cls, std::string name, std::string type); void st_getter(std::ostream& out, std::string cls, std::string name); void st_accessors(std::ostream& out, std::string cls, std::string name, std::string type); std::string class_name(); static bool is_valid_namespace(const std::string& sub_namespace); std::string client_class_name(); std::string prefix(std::string name); std::string declare_field(t_field* tfield); std::string type_name(t_type* ttype); std::string function_signature(t_function* tfunction); std::string argument_list(t_struct* tstruct); std::string function_types_comment(t_function* fn); std::string type_to_enum(t_type* ttype); std::string a_type(t_type* type); bool is_vowel(char c); std::string temp_name(); std::string generated_category(); private: /** * File streams */ int temporary_var; ofstream_with_content_based_conditional_update f_; }; /** * Prepares for file generation by opening up the necessary file output * streams. * * @param tprogram The program to generate */ void t_st_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); temporary_var = 0; // Make output file string f_name = get_out_dir() + "/" + program_name_ + ".st"; f_.open(f_name.c_str()); // Print header f_ << st_autogen_comment() << endl; st_class_def(f_, program_name_); generate_class_side_definition(); // Generate enums vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } } string t_st_generator::class_name() { return capitalize(program_name_); } bool t_st_generator::is_valid_namespace(const std::string& sub_namespace) { return sub_namespace == "prefix" || sub_namespace == "category"; } string t_st_generator::prefix(string class_name) { string prefix = program_->get_namespace("smalltalk.prefix"); string name = capitalize(class_name); name = prefix.empty() ? name : (prefix + name); return name; } string t_st_generator::client_class_name() { return capitalize(service_name_) + "Client"; } /** * Autogen'd comment */ string t_st_generator::st_autogen_comment() { return std::string("'") + "Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "\n" + "DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "'!\n"; } void t_st_generator::generate_force_consts() { f_ << prefix(class_name()) << " enums keysAndValuesDo: [:k :v | " << prefix(class_name()) << " enums at: k put: v value].!" << endl; f_ << prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " << prefix(class_name()) << " constants at: k put: v value].!" << endl; } void t_st_generator::close_generator() { generate_force_consts(); f_.close(); } string t_st_generator::generated_category() { string cat = program_->get_namespace("smalltalk.category"); // For compatibility with the Thrift grammar, the category must // be punctuated by dots. Replaces them with dashes here. for (char & iter : cat) { if (iter == '.') { iter = '-'; } } return cat.size() ? cat : "Generated-" + class_name(); } /** * Generates a typedef. This is not done in Smalltalk, types are all implicit. * * @param ttypedef The type definition */ void t_st_generator::generate_typedef(t_typedef* ttypedef) { (void)ttypedef; } void t_st_generator::st_class_def(std::ostream& out, string name) { out << "Object subclass: #" << prefix(name) << endl; indent_up(); out << indent() << "instanceVariableNames: ''" << endl << indent() << "classVariableNames: ''" << endl << indent() << "poolDictionaries: ''" << endl << indent() << "category: '" << generated_category() << "'!" << endl << endl; } void t_st_generator::st_method(std::ostream& out, string cls, string name) { st_method(out, cls, name, "as yet uncategorized"); } void t_st_generator::st_class_method(std::ostream& out, string cls, string name) { st_method(out, cls + " class", name); } void t_st_generator::st_class_method(std::ostream& out, string cls, string name, string category) { st_method(out, cls, name, category); } void t_st_generator::st_method(std::ostream& out, string cls, string name, string category) { char timestr[50]; time_t rawtime; struct tm* tinfo; time(&rawtime); tinfo = localtime(&rawtime); strftime(timestr, 50, "%m/%d/%Y %H:%M", tinfo); out << "!" << prefix(cls) << " methodsFor: '" + category + "' stamp: 'thrift " << timestr << "'!\n" << name << endl; indent_up(); out << indent(); } void t_st_generator::st_close_method(std::ostream& out) { out << "! !" << endl << endl; indent_down(); } void t_st_generator::st_setter(std::ostream& out, string cls, string name, string type = "anObject") { st_method(out, cls, name + ": " + type); out << name << " := " + type; st_close_method(out); } void t_st_generator::st_getter(std::ostream& out, string cls, string name) { st_method(out, cls, name + ""); out << "^ " << name; st_close_method(out); } void t_st_generator::st_accessors(std::ostream& out, string cls, string name, string type = "anObject") { st_setter(out, cls, name, type); st_getter(out, cls, name); } void t_st_generator::generate_class_side_definition() { f_ << prefix(class_name()) << " class" << endl << "\tinstanceVariableNames: 'constants enums'!" << endl << endl; st_accessors(f_, class_name() + " class", "enums"); st_accessors(f_, class_name() + " class", "constants"); f_ << prefix(class_name()) << " enums: Dictionary new!" << endl; f_ << prefix(class_name()) << " constants: Dictionary new!" << endl; f_ << endl; } /** * Generates code for an enumerated type. Done using a class to scope * the values. * * @param tenum The enumeration */ void t_st_generator::generate_enum(t_enum* tenum) { string cls_name = program_name_ + capitalize(tenum->get_name()); f_ << prefix(class_name()) << " enums at: '" << tenum->get_name() << "' put: [" << "(Dictionary new " << endl; vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); f_ << "\tat: '" << (*c_iter)->get_name() << "' put: " << value << ";" << endl; } f_ << "\tyourself)]!" << endl << endl; } /** * Generate a constant value */ void t_st_generator::generate_const(t_const* tconst) { t_type* type = tconst->get_type(); string name = tconst->get_name(); t_const_value* value = tconst->get_value(); f_ << prefix(class_name()) << " constants at: '" << name << "' put: [" << render_const_value(type, value) << "]!" << endl << endl; } /** * Prints the value of a constant with the given type. Note that type checking * is NOT performed in this function as it is always run beforehand using the * validate_types method in main.cc */ string t_st_generator::render_const_value(t_type* type, t_const_value* value) { type = get_true_type(type); std::ostringstream out; if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << '"' << get_escaped_string(value) << '"'; break; case t_base_type::TYPE_BOOL: out << (value->get_integer() > 0 ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << value->get_integer(); break; case t_base_type::TYPE_DOUBLE: if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { indent(out) << value->get_integer(); } else if (type->is_struct() || type->is_xception()) { out << "(" << capitalize(type->get_name()) << " new " << endl; indent_up(); const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } out << indent() << v_iter->first->get_string() << ": " << render_const_value(field_type, v_iter->second) << ";" << endl; } out << indent() << "yourself)"; indent_down(); } else if (type->is_map()) { t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); out << "(Dictionary new" << endl; indent_up(); indent_up(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent() << indent(); out << "at: " << render_const_value(ktype, v_iter->first); out << " put: "; out << render_const_value(vtype, v_iter->second); out << ";" << endl; } out << indent() << indent() << "yourself)"; indent_down(); indent_down(); } else if (type->is_list() || type->is_set()) { t_type* etype; if (type->is_list()) { etype = ((t_list*)type)->get_elem_type(); } else { etype = ((t_set*)type)->get_elem_type(); } if (type->is_set()) { out << "(Set new" << endl; } else { out << "(OrderedCollection new" << endl; } indent_up(); indent_up(); const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { out << indent() << indent(); out << "add: " << render_const_value(etype, *v_iter); out << ";" << endl; } out << indent() << indent() << "yourself)"; indent_down(); indent_down(); } else { throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); } return out.str(); } /** * Generates a Smalltalk struct */ void t_st_generator::generate_struct(t_struct* tstruct) { generate_st_struct(f_, tstruct, false); } /** * Generates a struct definition for a thrift exception. Basically the same * as a struct but extends the Exception class. * * @param txception The struct definition */ void t_st_generator::generate_xception(t_struct* txception) { generate_st_struct(f_, txception, true); } /** * Generates a smalltalk class to represent a struct */ void t_st_generator::generate_st_struct(std::ostream& out, t_struct* tstruct, bool is_exception = false) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; if (is_exception) out << "Error"; else out << "Object"; out << " subclass: #" << prefix(type_name(tstruct)) << endl << "\tinstanceVariableNames: '"; if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (m_iter != members.begin()) out << " "; out << camelcase((*m_iter)->get_name()); } } out << "'\n" << "\tclassVariableNames: ''\n" << "\tpoolDictionaries: ''\n" << "\tcategory: '" << generated_category() << "'!\n\n"; generate_accessors(out, tstruct); } bool t_st_generator::is_vowel(char c) { switch (tolower(c)) { case 'a': case 'e': case 'i': case 'o': case 'u': return true; } return false; } string t_st_generator::a_type(t_type* type) { string prefix; if (is_vowel(type_name(type)[0])) prefix = "an"; else prefix = "a"; return prefix + capitalize(type_name(type)); } void t_st_generator::generate_accessors(std::ostream& out, t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; string type; string prefix; if (members.size() > 0) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { st_accessors(out, capitalize(type_name(tstruct)), camelcase((*m_iter)->get_name()), a_type((*m_iter)->get_type())); } out << endl; } } /** * Generates a thrift service. * * @param tservice The service definition */ void t_st_generator::generate_service(t_service* tservice) { generate_service_client(tservice); // generate_service_server(tservice); } string t_st_generator::temp_name() { std::ostringstream out; out << "temp" << temporary_var++; return out.str(); } string t_st_generator::map_writer(t_map* tmap, string fname) { std::ostringstream out; string key = temp_name(); string val = temp_name(); out << "[oprot writeMapBegin: (TMap new keyType: " << type_to_enum(tmap->get_key_type()) << "; valueType: " << type_to_enum(tmap->get_val_type()) << "; size: " << fname << " size)." << endl; indent_up(); out << indent() << fname << " keysAndValuesDo: [:" << key << " :" << val << " |" << endl; indent_up(); out << indent() << write_val(tmap->get_key_type(), key) << "." << endl << indent() << write_val(tmap->get_val_type(), val); indent_down(); out << "]." << endl << indent() << "oprot writeMapEnd] value"; indent_down(); return out.str(); } string t_st_generator::map_reader(t_map* tmap) { std::ostringstream out; string desc = temp_name(); string val = temp_name(); out << "[|" << desc << " " << val << "| " << endl; indent_up(); out << indent() << desc << " := iprot readMapBegin." << endl << indent() << val << " := Dictionary new." << endl << indent() << desc << " size timesRepeat: [" << endl; indent_up(); out << indent() << val << " at: " << read_val(tmap->get_key_type()) << " put: " << read_val(tmap->get_val_type()); indent_down(); out << "]." << endl << indent() << "iprot readMapEnd." << endl << indent() << val << "] value"; indent_down(); return out.str(); } string t_st_generator::list_writer(t_list* tlist, string fname) { std::ostringstream out; string val = temp_name(); out << "[oprot writeListBegin: (TList new elemType: " << type_to_enum(tlist->get_elem_type()) << "; size: " << fname << " size)." << endl; indent_up(); out << indent() << fname << " do: [:" << val << "|" << endl; indent_up(); out << indent() << write_val(tlist->get_elem_type(), val) << endl; indent_down(); out << "]." << endl << indent() << "oprot writeListEnd] value"; indent_down(); return out.str(); } string t_st_generator::list_reader(t_list* tlist) { std::ostringstream out; string desc = temp_name(); string val = temp_name(); out << "[|" << desc << " " << val << "| " << desc << " := iprot readListBegin." << endl; indent_up(); out << indent() << val << " := OrderedCollection new." << endl << indent() << desc << " size timesRepeat: [" << endl; indent_up(); out << indent() << val << " add: " << read_val(tlist->get_elem_type()); indent_down(); out << "]." << endl << indent() << "iprot readListEnd." << endl << indent() << val << "] value"; indent_down(); return out.str(); } string t_st_generator::set_writer(t_set* tset, string fname) { std::ostringstream out; string val = temp_name(); out << "[oprot writeSetBegin: (TSet new elemType: " << type_to_enum(tset->get_elem_type()) << "; size: " << fname << " size)." << endl; indent_up(); out << indent() << fname << " do: [:" << val << "|" << endl; indent_up(); out << indent() << write_val(tset->get_elem_type(), val) << endl; indent_down(); out << "]." << endl << indent() << "oprot writeSetEnd] value"; indent_down(); return out.str(); } string t_st_generator::set_reader(t_set* tset) { std::ostringstream out; string desc = temp_name(); string val = temp_name(); out << "[|" << desc << " " << val << "| " << desc << " := iprot readSetBegin." << endl; indent_up(); out << indent() << val << " := Set new." << endl << indent() << desc << " size timesRepeat: [" << endl; indent_up(); out << indent() << val << " add: " << read_val(tset->get_elem_type()); indent_down(); out << "]." << endl << indent() << "iprot readSetEnd." << endl << indent() << val << "] value"; indent_down(); return out.str(); } string t_st_generator::struct_writer(t_struct* tstruct, string sname) { std::ostringstream out; const vector& fields = tstruct->get_sorted_members(); vector::const_iterator fld_iter; out << "[oprot writeStructBegin: " << "(TStruct new name: '" + tstruct->get_name() + "')." << endl; indent_up(); for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { bool optional = (*fld_iter)->get_req() == t_field::T_OPTIONAL; string fname = camelcase((*fld_iter)->get_name()); string accessor = sname + " " + camelcase(fname); if (optional) { out << indent() << accessor << " ifNotNil: [" << endl; indent_up(); } out << indent() << "oprot writeFieldBegin: (TField new name: '" << fname << "'; type: " << type_to_enum((*fld_iter)->get_type()) << "; id: " << (*fld_iter)->get_key() << ")." << endl; out << indent() << write_val((*fld_iter)->get_type(), accessor) << "." << endl << indent() << "oprot writeFieldEnd"; if (optional) { out << "]"; indent_down(); } out << "." << endl; } out << indent() << "oprot writeFieldStop; writeStructEnd] value"; indent_down(); return out.str(); } string t_st_generator::struct_reader(t_struct* tstruct, string clsName = "") { std::ostringstream out; const vector& fields = tstruct->get_members(); vector::const_iterator fld_iter; string val = temp_name(); string desc = temp_name(); string found = temp_name(); if (clsName.size() == 0) { clsName = tstruct->get_name(); } out << "[|" << desc << " " << val << "|" << endl; indent_up(); // This is nasty, but without it we'll break things by prefixing TResult. string name = ((capitalize(clsName) == "TResult") ? capitalize(clsName) : prefix(clsName)); out << indent() << val << " := " << name << " new." << endl; out << indent() << "iprot readStructBegin." << endl << indent() << "[" << desc << " := iprot readFieldBegin." << endl << indent() << desc << " type = TType stop] whileFalse: [|" << found << "|" << endl; indent_up(); for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { out << indent() << desc << " id = " << (*fld_iter)->get_key() << " ifTrue: [" << endl; indent_up(); out << indent() << found << " := true." << endl << indent() << val << " " << camelcase((*fld_iter)->get_name()) << ": " << read_val((*fld_iter)->get_type()); indent_down(); out << "]." << endl; } out << indent() << found << " ifNil: [iprot skip: " << desc << " type]]." << endl; indent_down(); out << indent() << "oprot readStructEnd." << endl << indent() << val << "] value"; indent_down(); return out.str(); } string t_st_generator::write_val(t_type* t, string fname) { t = get_true_type(t); if (t->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)t)->get_base(); switch (tbase) { case t_base_type::TYPE_DOUBLE: return "iprot writeDouble: " + fname + " asFloat"; break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: return "iprot write" + capitalize(type_name(t)) + ": " + fname + " asInteger"; default: return "iprot write" + capitalize(type_name(t)) + ": " + fname; } } else if (t->is_map()) { return map_writer((t_map*)t, fname); } else if (t->is_struct() || t->is_xception()) { return struct_writer((t_struct*)t, fname); } else if (t->is_list()) { return list_writer((t_list*)t, fname); } else if (t->is_set()) { return set_writer((t_set*)t, fname); } else if (t->is_enum()) { return "iprot writeI32: " + fname; } else { throw "Sorry, I don't know how to write this: " + type_name(t); } } string t_st_generator::read_val(t_type* t) { t = get_true_type(t); if (t->is_base_type()) { return "iprot read" + capitalize(type_name(t)); } else if (t->is_map()) { return map_reader((t_map*)t); } else if (t->is_struct() || t->is_xception()) { return struct_reader((t_struct*)t); } else if (t->is_list()) { return list_reader((t_list*)t); } else if (t->is_set()) { return set_reader((t_set*)t); } else if (t->is_enum()) { return "iprot readI32"; } else { throw "Sorry, I don't know how to read this: " + type_name(t); } } void t_st_generator::generate_send_method(t_function* function) { string funname = function->get_name(); string signature = function_signature(function); t_struct* arg_struct = function->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; st_method(f_, client_class_name(), "send" + capitalize(signature)); f_ << "oprot writeMessageBegin:" << endl; indent_up(); f_ << indent() << "(TCallMessage new" << endl; indent_up(); f_ << indent() << "name: '" << funname << "'; " << endl << indent() << "seqid: self nextSeqid)." << endl; indent_down(); indent_down(); f_ << indent() << "oprot writeStructBegin: " << "(TStruct new name: '" + capitalize(camelcase(funname)) + "_args')." << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { string fname = camelcase((*fld_iter)->get_name()); f_ << indent() << "oprot writeFieldBegin: (TField new name: '" << fname << "'; type: " << type_to_enum((*fld_iter)->get_type()) << "; id: " << (*fld_iter)->get_key() << ")." << endl; f_ << indent() << write_val((*fld_iter)->get_type(), fname) << "." << endl << indent() << "oprot writeFieldEnd." << endl; } f_ << indent() << "oprot writeFieldStop; writeStructEnd; writeMessageEnd." << endl; f_ << indent() << "oprot transport flush"; st_close_method(f_); } // We only support receiving TResult structures (so this won't work on the server side) void t_st_generator::generate_recv_method(t_function* function) { string funname = camelcase(function->get_name()); string signature = function_signature(function); t_struct result(program_, "TResult"); t_field success(function->get_returntype(), "success", 0); result.append(&success); t_struct* xs = function->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { // duplicate the field, but call it "exception"... we don't need a dynamic name t_field* exception = new t_field((*f_iter)->get_type(), "exception", (*f_iter)->get_key()); result.append(exception); } st_method(f_, client_class_name(), "recv" + capitalize(funname)); f_ << "| f msg res | " << endl << indent() << "msg := oprot readMessageBegin." << endl << indent() << "self validateRemoteMessage: msg." << endl << indent() << "res := " << struct_reader(&result) << "." << endl << indent() << "oprot readMessageEnd." << endl << indent() << "oprot transport flush." << endl << indent() << "res exception ifNotNil: [res exception signal]." << endl << indent() << "^ res"; st_close_method(f_); } string t_st_generator::function_types_comment(t_function* fn) { std::ostringstream out; const vector& fields = fn->get_arglist()->get_members(); vector::const_iterator f_iter; out << "\""; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { out << camelcase((*f_iter)->get_name()) << ": " << type_name((*f_iter)->get_type()); if ((f_iter + 1) != fields.end()) { out << ", "; } } out << "\""; return out.str(); } /** * Generates a service client definition. * * @param tservice The service to generate a server for. */ void t_st_generator::generate_service_client(t_service* tservice) { string extends = ""; string extends_client = "TClient"; vector functions = tservice->get_functions(); vector::iterator f_iter; if (tservice->get_extends() != nullptr) { extends = type_name(tservice->get_extends()); extends_client = extends + "Client"; } f_ << extends_client << " subclass: #" << prefix(client_class_name()) << endl << "\tinstanceVariableNames: ''\n" << "\tclassVariableNames: ''\n" << "\tpoolDictionaries: ''\n" << "\tcategory: '" << generated_category() << "'!\n\n"; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = camelcase((*f_iter)->get_name()); string signature = function_signature(*f_iter); st_method(f_, client_class_name(), signature); f_ << function_types_comment(*f_iter) << endl << indent() << "self send" << capitalize(signature) << "." << endl; if (!(*f_iter)->is_oneway()) { f_ << indent() << "^ self recv" << capitalize(funname) << " success " << endl; } st_close_method(f_); generate_send_method(*f_iter); if (!(*f_iter)->is_oneway()) { generate_recv_method(*f_iter); } } } /** * Renders a function signature of the form 'type name(args)' * * @param tfunction Function definition * @return String of rendered function definition */ string t_st_generator::function_signature(t_function* tfunction) { return camelcase(tfunction->get_name()) + capitalize(argument_list(tfunction->get_arglist())); } /** * Renders a field list */ string t_st_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { first = false; } else { result += " "; } string name = camelcase((*f_iter)->get_name()); result += name + ": " + name; } return result; } string t_st_generator::type_name(t_type* ttype) { string prefix = ""; t_program* program = ttype->get_program(); if (program != nullptr && program != program_) { if (!ttype->is_service()) { prefix = program->get_name() + "_types."; } } string name = ttype->get_name(); if (ttype->is_struct() || ttype->is_xception()) { name = capitalize(ttype->get_name()); } return prefix + name; } /* Convert t_type to Smalltalk type code */ string t_st_generator::type_to_enum(t_type* type) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return "TType string"; case t_base_type::TYPE_BOOL: return "TType bool"; case t_base_type::TYPE_I8: return "TType byte"; case t_base_type::TYPE_I16: return "TType i16"; case t_base_type::TYPE_I32: return "TType i32"; case t_base_type::TYPE_I64: return "TType i64"; case t_base_type::TYPE_DOUBLE: return "TType double"; } } else if (type->is_enum()) { return "TType i32"; } else if (type->is_struct() || type->is_xception()) { return "TType struct"; } else if (type->is_map()) { return "TType map"; } else if (type->is_set()) { return "TType set"; } else if (type->is_list()) { return "TType list"; } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_swift_generator.cc000066400000000000000000003227741420101504100254120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_oop_generator.h" using std::map; using std::ostream; using std::ostringstream; using std::set; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * Swift 3 code generator. * * Designed from the Swift/Cocoa code generator(s) */ class t_swift_generator : public t_oop_generator { public: t_swift_generator(t_program* program, const map& parsed_options, const string& option_string) : t_oop_generator(program) { update_keywords(); (void)option_string; map::const_iterator iter; log_unexpected_ = false; async_clients_ = false; debug_descriptions_ = false; no_strict_ = false; namespaced_ = false; gen_cocoa_ = false; promise_kit_ = false; safe_enums_ = false; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("log_unexpected") == 0) { log_unexpected_ = true; } else if( iter->first.compare("async_clients") == 0) { async_clients_ = true; } else if( iter->first.compare("no_strict") == 0) { no_strict_ = true; } else if( iter->first.compare("debug_descriptions") == 0) { debug_descriptions_ = true; } else if( iter->first.compare("namespaced") == 0) { namespaced_ = true; } else if( iter->first.compare("cocoa") == 0) { gen_cocoa_ = true; } else if( iter->first.compare("safe_enums") == 0) { safe_enums_ = true; } else if( iter->first.compare("promise_kit") == 0) { if (gen_cocoa_ == false) { throw "PromiseKit only available with Swift 2.x, use `cocoa` option" + iter->first; } promise_kit_ = true; } else { throw "unknown option swift:" + iter->first; } } out_dir_base_ = "gen-swift"; } /** * Init and close methods */ void init_generator() override; void close_generator() override; void generate_consts(vector consts) override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_struct(t_struct* tstruct) override; void generate_xception(t_struct* txception) override; void generate_service(t_service* tservice) override; void render_const_value(ostream& out, t_type* type, t_const_value* value); void generate_swift_struct(ostream& out, t_struct* tstruct, bool is_private); void generate_swift_struct_init(ostream& out, t_struct* tstruct, bool all, bool is_private); void generate_swift_struct_implementation(ostream& out, t_struct* tstruct, bool is_result, bool is_private); void generate_swift_struct_hashable_extension(ostream& out, t_struct* tstruct, bool is_private); void generate_swift_struct_equatable_extension(ostream& out, t_struct* tstruct, bool is_private); void generate_swift_struct_thrift_extension(ostream& out, t_struct* tstruct, bool is_result, bool is_private); void generate_swift_struct_reader(ostream& out, t_struct* tstruct, bool is_private); void generate_swift_struct_printable_extension(ostream& out, t_struct* tstruct); void generate_swift_union_reader(ostream& out, t_struct* tstruct); string function_result_helper_struct_type(t_service *tservice, t_function* tfunction); string function_args_helper_struct_type(t_service* tservice, t_function* tfunction); void generate_function_helpers(t_service *tservice, t_function* tfunction); /** * Service-level generation functions */ void generate_swift_service_protocol(ostream& out, t_service* tservice); void generate_swift_service_protocol_async(ostream& out, t_service* tservice); void generate_swift_service_client(ostream& out, t_service* tservice); void generate_swift_service_client_async(ostream& out, t_service* tservice); void generate_swift_service_client_send_function_implementation(ostream& out, t_service* tservice, t_function* tfunction, bool needs_protocol); void generate_swift_service_client_send_function_invocation(ostream& out, t_function* tfunction); void generate_swift_service_client_send_async_function_invocation(ostream& out, t_function* tfunction); void generate_swift_service_client_recv_function_implementation(ostream& out, t_service* tservice, t_function* tfunction, bool needs_protocol); void generate_swift_service_client_implementation(ostream& out, t_service* tservice); void generate_swift_service_client_async_implementation(ostream& out, t_service* tservice); void generate_swift_service_server(ostream& out, t_service* tservice); void generate_swift_service_server_implementation(ostream& out, t_service* tservice); void generate_swift_service_helpers(t_service* tservice); /** * Helper rendering functions */ string swift_imports(); string swift_thrift_imports(); string type_name(t_type* ttype, bool is_optional=false, bool is_forced=false); string base_type_name(t_base_type* tbase); string declare_property(t_field* tfield, bool is_private); string function_signature(t_function* tfunction); string async_function_signature(t_function* tfunction); string argument_list(t_struct* tstruct, string protocol_name, bool is_internal); string type_to_enum(t_type* ttype, bool qualified=false); string maybe_escape_identifier(const string& identifier); void populate_reserved_words(); /** Swift 3 specific */ string enum_case_name(t_enum_value* tenum_case, bool declaration); string enum_const_name(string enum_identifier); void function_docstring(ostream& out, t_function* tfunction); void async_function_docstring(ostream& out, t_function* tfunction); void generate_docstring(ostream& out, string& doc); /** Swift 2/Cocoa carryover */ string promise_function_signature(t_function* tfunction); string function_name(t_function* tfunction); void generate_old_swift_struct_writer(ostream& out,t_struct* tstruct, bool is_private); void generate_old_swift_struct_result_writer(ostream& out, t_struct* tstruct); /** Swift 2/Cocoa backwards compatibility*/ void generate_old_enum(t_enum* tenum); void generate_old_swift_struct(ostream& out, t_struct* tstruct, bool is_private); void generate_old_swift_service_client_async_implementation(ostream& out, t_service* tservice); static std::string get_real_swift_module(const t_program* program) { std::string real_module = program->get_namespace("swift"); if (real_module.empty()) { return program->get_name(); } return real_module; } private: void block_open(ostream& out) { out << " {" << endl; indent_up(); } void block_close(ostream& out, bool end_line=true) { indent_down(); indent(out) << "}"; if (end_line) out << endl; } bool field_is_optional(t_field* tfield) { bool opt = tfield->get_req() == t_field::T_OPTIONAL; if (tfield->annotations_.find("swift.nullable") != tfield->annotations_.end() && tfield->get_req() != t_field::T_REQUIRED) { opt = true; } if (gen_cocoa_) { // Backwards compatibility, only if its actually "optional" opt = tfield->get_req() == t_field::T_OPTIONAL; } return opt; } bool struct_has_required_fields(t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!field_is_optional(*m_iter)) { return true; } } return false; } bool struct_has_optional_fields(t_struct* tstruct) { const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (field_is_optional(*m_iter)) { return true; } } return false; } string constants_declarations_; /** * File streams */ ofstream_with_content_based_conditional_update f_decl_; ofstream_with_content_based_conditional_update f_impl_; bool log_unexpected_; bool async_clients_; bool debug_descriptions_; bool no_strict_; bool namespaced_; bool safe_enums_; set swift_reserved_words_; /** Swift 2/Cocoa compatibility */ bool gen_cocoa_; bool promise_kit_; protected: std::set lang_keywords() const override { return {}; } }; /** * Prepares for file generation by opening up the necessary file output * streams. */ void t_swift_generator::init_generator() { // Make output directory string module = get_real_swift_module(program_); string out_dir = get_out_dir(); string module_path = out_dir; string name = program_name_; if (namespaced_ && !module.empty()) { module_path = module_path + "/" + module; name = module; } MKDIR(module_path.c_str()); populate_reserved_words(); // we have a .swift declarations file... string f_decl_name = name + ".swift"; string f_decl_fullname = module_path + "/" + f_decl_name; f_decl_.open(f_decl_fullname.c_str()); f_decl_ << autogen_comment() << endl; f_decl_ << swift_imports() << swift_thrift_imports() << endl; // ...and a .swift implementation extensions file string f_impl_name = name + "+Exts.swift"; string f_impl_fullname = module_path + "/" + f_impl_name; f_impl_.open(f_impl_fullname.c_str()); f_impl_ << autogen_comment() << endl; f_impl_ << swift_imports() << swift_thrift_imports() << endl; } /** * Prints standard Cocoa imports * * @return List of imports for Cocoa libraries */ string t_swift_generator::swift_imports() { vector includes_list; includes_list.emplace_back("Foundation"); ostringstream includes; vector::const_iterator i_iter; for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) { includes << "import " << *i_iter << endl; } if (namespaced_) { const vector& program_includes = program_->get_includes(); for (auto program_include : program_includes) { includes << ("import " + get_real_swift_module(program_include)) << endl; } } includes << endl; return includes.str(); } /** * Prints Thrift runtime imports * * @return List of imports necessary for Thrift runtime */ string t_swift_generator::swift_thrift_imports() { vector includes_list; includes_list.emplace_back("Thrift"); if (gen_cocoa_ && promise_kit_) { includes_list.emplace_back("PromiseKit"); } ostringstream includes; vector::const_iterator i_iter; for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) { includes << "import " << *i_iter << endl; } includes << endl; return includes.str(); } /** * Finish up generation. */ void t_swift_generator::close_generator() { // stick our constants declarations at the end of the header file // since they refer to things we are defining. f_decl_ << constants_declarations_ << endl; } /** * Generates a typedef. This is just a simple 1-liner in Swift * * @param ttypedef The type definition */ void t_swift_generator::generate_typedef(t_typedef* ttypedef) { f_decl_ << indent() << "public typealias " << ttypedef->get_symbolic() << " = " << type_name(ttypedef->get_type()) << endl; f_decl_ << endl; } /** * Generates code for an enumerated type. In Swift, this is * essentially the same as the thrift definition itself, using * Swift syntax. Conforms to TEnum which * implementes read/write. * * @param tenum The enumeration */ void t_swift_generator::generate_enum(t_enum* tenum) { if (gen_cocoa_) { generate_old_enum(tenum); return; } f_decl_ << indent() << "public enum " << tenum->get_name() << " : TEnum"; block_open(f_decl_); vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { f_decl_ << indent() << "case " << enum_case_name((*c_iter), true) << endl; } // unknown associated value case for safety and similar behavior to other languages if (safe_enums_) { f_decl_ << indent() << "case unknown(Int32)" << endl; } f_decl_ << endl; // TSerializable read(from:) f_decl_ << indent() << "public static func read(from proto: TProtocol) throws -> " << tenum->get_name(); block_open(f_decl_); f_decl_ << indent() << "let raw: Int32 = try proto.read()" << endl; f_decl_ << indent() << "let new = " << tenum->get_name() << "(rawValue: raw)" << endl; f_decl_ << indent() << "if let unwrapped = new {" << endl; indent_up(); f_decl_ << indent() << "return unwrapped" << endl; indent_down(); f_decl_ << indent() << "} else {" << endl; indent_up(); f_decl_ << indent() << "throw TProtocolError(error: .invalidData," << endl; f_decl_ << indent() << " message: \"Invalid enum value (\\(raw)) for \\(" << tenum->get_name() << ".self)\")" << endl; indent_down(); f_decl_ << indent() << "}" << endl; block_close(f_decl_); // empty init for TSerializable f_decl_ << endl; f_decl_ << indent() << "public init()"; block_open(f_decl_); f_decl_ << indent() << "self = ." << enum_case_name(constants.front(), false) << endl; block_close(f_decl_); f_decl_ << endl; // rawValue getter f_decl_ << indent() << "public var rawValue: Int32"; block_open(f_decl_); f_decl_ << indent() << "switch self {" << endl; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { f_decl_ << indent() << "case ." << enum_case_name((*c_iter), true) << ": return " << (*c_iter)->get_value() << endl; } if (safe_enums_) { f_decl_ << indent() << "case .unknown(let value): return value" << endl; } f_decl_ << indent() << "}" << endl; block_close(f_decl_); f_decl_ << endl; // convenience rawValue initalizer f_decl_ << indent() << "public init?(rawValue: Int32)"; block_open(f_decl_); f_decl_ << indent() << "switch rawValue {" << endl;; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { f_decl_ << indent() << "case " << (*c_iter)->get_value() << ": self = ." << enum_case_name((*c_iter), true) << endl; } if (!safe_enums_) { f_decl_ << indent() << "default: return nil" << endl; } else { f_decl_ << indent() << "default: self = .unknown(rawValue)" << endl; } f_decl_ << indent() << "}" << endl; block_close(f_decl_); block_close(f_decl_); f_decl_ << endl; } /** * Generates code for an enumerated type. This is for Swift 2.x/Cocoa * backwards compatibility * * @param tenum The enumeration */ void t_swift_generator::generate_old_enum(t_enum* tenum) { f_decl_ << indent() << "public enum " << tenum->get_name() << " : Int32"; block_open(f_decl_); vector constants = tenum->get_constants(); vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { f_decl_ << indent() << "case " << (*c_iter)->get_name() << " = " << (*c_iter)->get_value() << endl; } f_decl_ << endl; f_decl_ << indent() << "public init() { self.init(rawValue: " << constants.front()->get_value() << ")! }" << endl; block_close(f_decl_); f_decl_ << endl; f_impl_ << indent() << "extension " << tenum->get_name() << " : TEnum"; block_open(f_impl_); f_impl_ << endl; f_impl_ << indent() << "public static func readValueFromProtocol(proto: TProtocol) throws -> " << tenum->get_name(); block_open(f_impl_); f_impl_ << indent() << "var raw = Int32()" << endl << indent() << "try proto.readI32(&raw)" << endl << indent() << "return " << tenum->get_name() << "(rawValue: raw)!" << endl; block_close(f_impl_); f_impl_ << endl; f_impl_ << indent() << "public static func writeValue(value: " << tenum->get_name() << ", toProtocol proto: TProtocol) throws"; block_open(f_impl_); f_impl_ << indent() << "try proto.writeI32(value.rawValue)" << endl; block_close(f_impl_); f_impl_ << endl; block_close(f_impl_); f_impl_ << endl; } string t_swift_generator::enum_case_name(t_enum_value* tenum_case, bool declaration) { string name = tenum_case->get_name(); // force to lowercase for Swift style, maybe escape if its a keyword std::transform(name.begin(), name.end(), name.begin(), ::tolower); if (declaration) { name = maybe_escape_identifier(name); } return name; } /** * Renders a constant enum value by transforming the value portion to lowercase * for Swift style. */ string t_swift_generator::enum_const_name(string enum_identifier) { string::iterator it; for (it = enum_identifier.begin(); it < enum_identifier.end(); ++it) { if ((*it) == '.') { break; } } std::transform(it, enum_identifier.end(), it, ::tolower); return enum_identifier; } /** * Generates public constants for all Thrift constants. * * @param consts Constants to generate */ void t_swift_generator::generate_consts(vector consts) { ostringstream const_interface; // Public constants for base types & strings vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { t_type* type = (*c_iter)->get_type(); const_interface << "public let " << capitalize((*c_iter)->get_name()) << " : " << type_name(type) << " = "; render_const_value(const_interface, type, (*c_iter)->get_value()); const_interface << endl << endl; } // this gets spit into the header file in ::close_generator constants_declarations_ = const_interface.str(); } /** * Generates a struct definition for a thrift data type. This is a struct * with public members. Optional types are used for optional properties to * allow them to be tested for availability. Separate inits are included for * required properties & all properties. * * Generates extensions to provide conformance to TStruct, TSerializable, * Hashable & Equatable * * @param tstruct The struct definition */ void t_swift_generator::generate_struct(t_struct* tstruct) { generate_swift_struct(f_decl_, tstruct, false); generate_swift_struct_implementation(f_impl_, tstruct, false, false); } /** * Exceptions are structs, but they conform to Error * * @param tstruct The struct definition */ void t_swift_generator::generate_xception(t_struct* txception) { generate_swift_struct(f_decl_, txception, false); generate_swift_struct_implementation(f_impl_, txception, false, false); } void t_swift_generator::generate_docstring(ostream& out, string& doc) { if (doc != "") { std::vector strings; std::string::size_type pos = 0; std::string::size_type prev = 0; while (((pos = doc.find("\n", prev)) != std::string::npos) || ((pos = doc.find("\r", prev)) != std::string::npos) || ((pos = doc.find("\r\n", prev)) != std::string::npos)) { strings.push_back(doc.substr(prev, pos - prev)); prev = pos + 1; } // To get the last substring (or only, if delimiter is not found) strings.push_back(doc.substr(prev)); vector::const_iterator d_iter; for (d_iter = strings.begin(); d_iter != strings.end(); ++d_iter) { if ((*d_iter) != "") { out << indent() << "/// " << (*d_iter) << endl; } } } } /** * Generate the interface for a struct. Only properties and * init methods are included. * * @param tstruct The struct definition * @param is_private * Is the struct public or private */ void t_swift_generator::generate_swift_struct(ostream& out, t_struct* tstruct, bool is_private) { if (gen_cocoa_) { generate_old_swift_struct(out, tstruct, is_private); return; } string doc = tstruct->get_doc(); generate_docstring(out, doc); // properties const vector& members = tstruct->get_members(); vector::const_iterator m_iter; if (tstruct->is_union()) { // special, unions out << indent() << "public enum " << tstruct->get_name(); block_open(out); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << endl; string doc = (*m_iter)->get_doc(); generate_docstring(out, doc); out << indent() << "case " << maybe_escape_identifier((*m_iter)->get_name()) << "(val: " << type_name((*m_iter)->get_type(), false) << ")" << endl; } } else { // Normal structs string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public"; out << indent() << visibility << " final class " << tstruct->get_name(); if (tstruct->is_xception()) { out << " : Swift.Error"; // Error seems to be a common exception name in thrift } block_open(out); vector sorted = members; sort(sorted.begin(), sorted.end(), [](t_field *a, t_field *b) { return (a->get_key() < b->get_key()); } ); for (m_iter = sorted.begin(); m_iter != sorted.end(); ++m_iter) { out << endl; // TODO: Defaults string doc = (*m_iter)->get_doc(); generate_docstring(out, doc); out << indent() << declare_property(*m_iter, is_private) << endl; } out << endl; out << endl; if (!struct_has_required_fields(tstruct)) { indent(out) << visibility << " init() { }" << endl; } if (struct_has_required_fields(tstruct)) { generate_swift_struct_init(out, tstruct, false, is_private); } if (struct_has_optional_fields(tstruct)) { generate_swift_struct_init(out, tstruct, true, is_private); } } block_close(out); out << endl; } /** * Legacy Swift2/Cocoa generator * * @param tstruct * @param is_private */ void t_swift_generator::generate_old_swift_struct(ostream& out, t_struct* tstruct, bool is_private) { string visibility = is_private ? "private" : "public"; out << indent() << visibility << " final class " << tstruct->get_name(); if (tstruct->is_xception()) { out << " : ErrorType"; } block_open(out); // properties const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { out << endl; out << indent() << declare_property(*m_iter, is_private) << endl; } out << endl; // init indent(out) << visibility << " init()"; block_open(out); block_close(out); out << endl; if (struct_has_required_fields(tstruct)) { generate_swift_struct_init(out, tstruct, false, is_private); } if (struct_has_optional_fields(tstruct)) { generate_swift_struct_init(out, tstruct, true, is_private); } block_close(out); out << endl; } /** * Generate struct init for properties * * @param tstruct The structure definition * @param all Generate init with all or just required properties * @param is_private * Is the initializer public or private */ void t_swift_generator::generate_swift_struct_init(ostream& out, t_struct* tstruct, bool all, bool is_private) { string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public"; indent(out) << visibility << " init("; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; bool first=true; for (m_iter = members.begin(); m_iter != members.end();) { if (all || !field_is_optional(*m_iter)) { if (first) { first = false; } else { out << ", "; } out << (*m_iter)->get_name() << ": " << maybe_escape_identifier(type_name((*m_iter)->get_type(), field_is_optional(*m_iter))); } ++m_iter; } out << ")"; block_open(out); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!gen_cocoa_) { bool should_set = all; should_set = should_set || !field_is_optional((*m_iter)); if (should_set) { out << indent() << "self." << maybe_escape_identifier((*m_iter)->get_name()) << " = " << maybe_escape_identifier((*m_iter)->get_name()) << endl; } } else { /** legacy Swift2/Cocoa */ if (all || (*m_iter)->get_req() == t_field::T_REQUIRED || (*m_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) { out << indent() << "self." << maybe_escape_identifier((*m_iter)->get_name()) << " = " << maybe_escape_identifier((*m_iter)->get_name()) << endl; } } } block_close(out); out << endl; } /** * Generate the hashable protocol implmentation * * @param tstruct The structure definition * @param is_private * Is the struct public or private */ void t_swift_generator::generate_swift_struct_hashable_extension(ostream& out, t_struct* tstruct, bool is_private) { string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public"; indent(out) << "extension " << tstruct->get_name() << " : Hashable"; block_open(out); out << endl; indent(out) << visibility << " func hash(into hasher: inout Hasher)"; block_open(out); const vector& members = tstruct->get_members(); vector::const_iterator m_iter; if (!members.empty()) { if (!tstruct->is_union()) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* tfield = *m_iter; indent(out) << "hasher.combine(" << maybe_escape_identifier(tfield->get_name()) << ")" << endl; } } else { indent(out) << "switch self {" << endl; for (m_iter = members.begin(); m_iter != members.end(); m_iter++) { t_field *tfield = *m_iter; indent(out) << "case ." << tfield->get_name() << "(let val): hasher.combine(val)" << endl; } indent(out) << "}" << endl << endl; } } block_close(out); out << endl; block_close(out); out << endl; } /** * Generate the equatable protocol implementation * * @param tstruct The structure definition * @param is_private * Is the struct public or private */ void t_swift_generator::generate_swift_struct_equatable_extension(ostream& out, t_struct* tstruct, bool is_private) { string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public"; indent(out) << visibility << " func ==(lhs: " << type_name(tstruct) << ", rhs: " << type_name(tstruct) << ") -> Bool"; block_open(out); indent(out) << "return"; const vector& members = tstruct->get_members(); vector::const_iterator m_iter; if (members.size()) { if (!tstruct->is_union()) { out << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end();) { t_field* tfield = *m_iter; indent(out) << "(lhs." << maybe_escape_identifier(tfield->get_name()) << (gen_cocoa_ ? " ?" : " ") << "== rhs." << maybe_escape_identifier(tfield->get_name()) << ")"; // swift 2 ?== operator not in 3? if (++m_iter != members.end()) { out << " &&"; } out << endl; } indent_down(); } else { block_open(out); indent(out) << "switch (lhs, rhs) {" << endl; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { t_field* tfield = *m_iter; indent(out) << "case (." << tfield->get_name() << "(let lval), ." << tfield->get_name() << "(let rval)): return lval == rval" << endl; } indent(out) << "default: return false" << endl; indent(out) << "}" << endl; indent_down(); indent(out) << "}()" << endl; } } else { out << " true" << endl; } block_close(out); out << endl; } /** * Generate struct implementation. Produces extensions that * fulfill the requisite protocols to complete the value. * * @param tstruct The struct definition * @param is_result * If this is a result it needs a different writer * @param is_private * Is the struct public or private */ void t_swift_generator::generate_swift_struct_implementation(ostream& out, t_struct* tstruct, bool is_result, bool is_private) { generate_swift_struct_equatable_extension(out, tstruct, is_private); if (!is_private && !is_result && !gen_cocoa_) { // old compiler didn't use debug_descriptions, OR it with gen_cocoa_ so the flag doesn't matter w/ cocoa generate_swift_struct_printable_extension(out, tstruct); } generate_swift_struct_hashable_extension(out, tstruct, is_private); generate_swift_struct_thrift_extension(out, tstruct, is_result, is_private); out << endl << endl; } /** * Generate the TStruct protocol implementation. * * @param tstruct The structure definition * @param is_result * Is the struct a result value * @param is_private * Is the struct public or private */ void t_swift_generator::generate_swift_struct_thrift_extension(ostream& out, t_struct* tstruct, bool is_result, bool is_private) { indent(out) << "extension " << tstruct->get_name() << " : TStruct"; block_open(out); out << endl; if (!gen_cocoa_) { /** Swift 3, no writer we just write field ID's */ string access = (is_private) ? (gen_cocoa_ ? "private" : "fileprivate") : "public"; // generate fieldID's dictionary out << indent() << access << " static var fieldIds: [String: Int32]"; block_open(out); out << indent() << "return ["; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; bool wrote = false; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { wrote = true; out << "\"" << (*f_iter)->get_name() << "\": " << (*f_iter)->get_key() << ", "; } if (!wrote) { // pad a colon out << ":"; } out << "]" << endl; block_close(out); out << endl; out << indent() << access << " static var structName: String { return \"" << tstruct->get_name() << "\" }" << endl << endl; if (tstruct->is_union()) { generate_swift_union_reader(out, tstruct); } else { generate_swift_struct_reader(out, tstruct, is_private); } } else { /** Legacy Swift2/Cocoa */ generate_swift_struct_reader(out, tstruct, is_private); if (is_result) { generate_old_swift_struct_result_writer(out, tstruct); } else { generate_old_swift_struct_writer(out, tstruct, is_private); } } block_close(out); out << endl; } void t_swift_generator::generate_swift_union_reader(ostream& out, t_struct* tstruct) { indent(out) << "public static func read(from proto: TProtocol) throws -> " << tstruct->get_name(); block_open(out); indent(out) << "_ = try proto.readStructBegin()" << endl; indent(out) << "var ret: " << tstruct->get_name() << "?"; out << endl; indent(out) << "fields: while true"; block_open(out); out << endl; indent(out) << "let (_, fieldType, fieldID) = try proto.readFieldBegin()" << endl << endl; indent(out) << "switch (fieldID, fieldType)"; block_open(out); indent(out) << "case (_, .stop): break fields" << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case (" << (*f_iter)->get_key() << ", " << type_to_enum((*f_iter)->get_type()) << "):"; string padding = ""; t_type* type = get_true_type((*f_iter)->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: case t_base_type::TYPE_DOUBLE: padding = " "; break; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: padding = " "; break; case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: padding = " "; break; default: break; } } else if (type->is_enum() || type->is_set() || type->is_map()) { padding = " "; } else if (type->is_struct() || type->is_xception()) { padding = " "; } else if (type->is_list()) { padding = " "; } indent(out) << padding << "ret = " << tstruct->get_name() << "." << (*f_iter)->get_name() << "(val: " << "try " << type_name((*f_iter)->get_type(), false, false) << ".read(from: proto))" << endl; } indent(out) << "case let (_, unknownType): try proto.skip(type: unknownType)" << endl; block_close(out); indent(out) << "try proto.readFieldEnd()" << endl; block_close(out); out << endl; indent(out) << "try proto.readStructEnd()" << endl; indent(out) << "if let ret = ret"; block_open(out); indent(out) << "return ret" << endl; block_close(out); out << endl; indent(out) << "throw TProtocolError(error: .unknown, message: \"Missing required value for type: " << tstruct->get_name() << "\")"; block_close(out); out << endl; } /** * Generates a function to read a struct from * from a protocol. (TStruct compliance) * * @param tstruct The structure definition * @param is_private * Is the struct public or private */ void t_swift_generator::generate_swift_struct_reader(ostream& out, t_struct* tstruct, bool is_private) { if (!gen_cocoa_) { /** Swift 3 case */ string visibility = is_private ? "fileprivate" : "public"; indent(out) << visibility << " static func read(from proto: TProtocol) throws -> " << tstruct->get_name(); block_open(out); indent(out) << "_ = try proto.readStructBegin()" << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool optional = field_is_optional(*f_iter); indent(out) << "var " << maybe_escape_identifier((*f_iter)->get_name()) << ": " << type_name((*f_iter)->get_type(), optional, !optional) << endl; } out << endl; // Loop over reading in fields indent(out) << "fields: while true"; block_open(out); out << endl; indent(out) << "let (_, fieldType, fieldID) = try proto.readFieldBegin()" << endl << endl; indent(out) << "switch (fieldID, fieldType)"; block_open(out); indent(out) << "case (_, .stop): break fields" << endl; // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case (" << (*f_iter)->get_key() << ", " << type_to_enum((*f_iter)->get_type()) << "):"; string padding = ""; t_type* type = get_true_type((*f_iter)->get_type()); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: case t_base_type::TYPE_DOUBLE: padding = " "; break; case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: padding = " "; break; case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: padding = " "; break; default: break; } } else if (type->is_enum() || type->is_set() || type->is_map()) { padding = " "; } else if (type->is_struct() || type->is_xception()) { padding = " "; } else if (type->is_list()) { padding = " "; } out << padding << maybe_escape_identifier((*f_iter)->get_name()) << " = try " << type_name((*f_iter)->get_type(), false, false) << ".read(from: proto)" << endl; } indent(out) << "case let (_, unknownType): try proto.skip(type: unknownType)" << endl; block_close(out); out << endl; // Read field end marker indent(out) << "try proto.readFieldEnd()" << endl; block_close(out); out << endl; indent(out) << "try proto.readStructEnd()" << endl; if (struct_has_required_fields(tstruct)) { // performs various checks (e.g. check that all required fields are set) indent(out) << "// Required fields" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (field_is_optional(*f_iter)) { continue; } indent(out) << "try proto.validateValue(" << maybe_escape_identifier((*f_iter)->get_name()) << ", " << "named: \"" << (*f_iter)->get_name() << "\")" << endl; } } out << endl; indent(out) << "return " << tstruct->get_name() << "("; for (f_iter = fields.begin(); f_iter != fields.end();) { out << (*f_iter)->get_name() << ": " << maybe_escape_identifier((*f_iter)->get_name()); if (++f_iter != fields.end()) { out << ", "; } } } else { /** Legacy Swif2/Cocoa case */ string visibility = is_private ? "private" : "public"; indent(out) << visibility << " static func readValueFromProtocol(__proto: TProtocol) throws -> " << tstruct->get_name(); block_open(out); out << endl; indent(out) << "try __proto.readStructBegin()" << endl << endl; const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { bool optional = field_is_optional(*f_iter); indent(out) << "var " << maybe_escape_identifier((*f_iter)->get_name()) << " : " << type_name((*f_iter)->get_type(), optional, !optional) << endl; } out << endl; // Loop over reading in fields indent(out) << "fields: while true"; block_open(out); out << endl; indent(out) << "let (_, fieldType, fieldID) = try __proto.readFieldBegin()" << endl << endl; indent(out) << "switch (fieldID, fieldType)"; block_open(out); indent(out) << "case (_, .STOP):" << endl; indent_up(); indent(out) << "break fields" << endl << endl; indent_down(); // Generate deserialization code for known cases for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "case (" << (*f_iter)->get_key() << ", " << type_to_enum((*f_iter)->get_type()) << "):" << endl; indent_up(); indent(out) << maybe_escape_identifier((*f_iter)->get_name()) << " = try __proto.readValue() as " << type_name((*f_iter)->get_type()) << endl << endl; indent_down(); } indent(out) << "case let (_, unknownType):" << endl; indent_up(); indent(out) << "try __proto.skipType(unknownType)" << endl; indent_down(); block_close(out); out << endl; // Read field end marker indent(out) << "try __proto.readFieldEnd()" << endl; block_close(out); out << endl; indent(out) << "try __proto.readStructEnd()" << endl; out << endl; if (struct_has_required_fields(tstruct)) { // performs various checks (e.g. check that all required fields are set) indent(out) << "// Required fields" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (field_is_optional(*f_iter)) { continue; } indent(out) << "try __proto.validateValue(" << (*f_iter)->get_name() << ", " << "named: \"" << (*f_iter)->get_name() << "\")" << endl; } } out << endl; indent(out) << "return " << tstruct->get_name() << "("; for (f_iter = fields.begin(); f_iter != fields.end();) { out << (*f_iter)->get_name() << ": " << maybe_escape_identifier((*f_iter)->get_name()); if (++f_iter != fields.end()) { out << ", "; } } } out << ")" << endl; block_close(out); out << endl; } /** * Generates a function to write a struct to * a protocol. (TStruct compliance) ONLY FOR SWIFT2/COCOA * * @param tstruct The structure definition * @param is_private * Is the struct public or private */ void t_swift_generator::generate_old_swift_struct_writer(ostream& out, t_struct* tstruct, bool is_private) { string visibility = is_private ? "private" : "public"; indent(out) << visibility << " static func writeValue(__value: " << tstruct->get_name() << ", toProtocol __proto: TProtocol) throws"; block_open(out); out << endl; string name = tstruct->get_name(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; indent(out) << "try __proto.writeStructBeginWithName(\"" << name << "\")" << endl; out << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field *tfield = *f_iter; bool optional = field_is_optional(tfield); if (optional) { indent(out) << "if let " << maybe_escape_identifier(tfield->get_name()) << " = __value." << maybe_escape_identifier(tfield->get_name()); block_open(out); } indent(out) << "try __proto.writeFieldValue(" << (optional ? "" : "__value.") << maybe_escape_identifier(tfield->get_name()) << ", " << "name: \"" << tfield->get_name() << "\", " << "type: " << type_to_enum(tfield->get_type()) << ", " << "id: " << tfield->get_key() << ")" << endl; if (optional) { block_close(out); } out << endl; } indent(out) << "try __proto.writeFieldStop()" << endl << endl; indent(out) << "try __proto.writeStructEnd()" << endl; block_close(out); out << endl; } /** * Generates a function to read a struct from * from a protocol. (TStruct compliance) ONLY FOR SWIFT 2/COCOA * * This is specifically a function result. Only * the first available field is written. * * @param tstruct The structure definition */ void t_swift_generator::generate_old_swift_struct_result_writer(ostream& out, t_struct* tstruct) { indent(out) << "private static func writeValue(__value: " << tstruct->get_name() << ", toProtocol __proto: TProtocol) throws"; block_open(out); out << endl; string name = tstruct->get_name(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; indent(out) << "try __proto.writeStructBeginWithName(\"" << name << "\")" << endl; out << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field *tfield = *f_iter; indent(out) << "if let result = __value." << (*f_iter)->get_name(); block_open(out); indent(out) << "try __proto.writeFieldValue(result, " << "name: \"" << tfield->get_name() << "\", " << "type: " << type_to_enum(tfield->get_type()) << ", " << "id: " << tfield->get_key() << ")" << endl; block_close(out); } // Write the struct map indent(out) << "try __proto.writeFieldStop()" << endl << endl; indent(out) << "try __proto.writeStructEnd()" << endl; block_close(out); out << endl; } /** * Generates a description method for the given struct * * @param tstruct The struct definition */ void t_swift_generator::generate_swift_struct_printable_extension(ostream& out, t_struct* tstruct) { // Allow use of debugDescription so the app can add description via a cateogory/extension const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; indent(out) << "extension " << tstruct->get_name() << " : " << (debug_descriptions_ ? "CustomDebugStringConvertible" : "CustomStringConvertible"); block_open(out); out << endl; indent(out) << "public var description : String"; block_open(out); indent(out) << "var desc = \"" << tstruct->get_name(); if (!gen_cocoa_) { if (!tstruct->is_union()) { out << "(\"" << endl; for (f_iter = fields.begin(); f_iter != fields.end();) { indent(out) << "desc += \"" << (*f_iter)->get_name() << "=\\(String(describing: self." << maybe_escape_identifier((*f_iter)->get_name()) << "))"; if (++f_iter != fields.end()) { out << ", "; } out << "\"" << endl; } } else { out << ".\"" << endl; indent(out) << "switch self {" << endl; for (f_iter = fields.begin(); f_iter != fields.end();f_iter++) { indent(out) << "case ." << (*f_iter)->get_name() << "(let val): " << "desc += \"" << (*f_iter)->get_name() << "(val: \\(val))\"" << endl; } indent(out) << "}" << endl; } } else { out << "(\"" << endl; for (f_iter = fields.begin(); f_iter != fields.end();) { indent(out) << "desc += \"" << (*f_iter)->get_name() << "=\\(self." << maybe_escape_identifier((*f_iter)->get_name()) << ")"; if (++f_iter != fields.end()) { out << ", "; } out << "\"" << endl; } indent(out) << "desc += \")\"" << endl; } indent(out) << "return desc" << endl; block_close(out); out << endl; block_close(out); out << endl; } /** * Generates a thrift service. In Swift this consists of a * protocol definition and a client (with it's implementation * separated into exts file). * * @param tservice The service definition */ void t_swift_generator::generate_service(t_service* tservice) { generate_swift_service_protocol(f_decl_, tservice); generate_swift_service_client(f_decl_, tservice); if (async_clients_) { generate_swift_service_protocol_async(f_decl_, tservice); generate_swift_service_client_async(f_decl_, tservice); } generate_swift_service_server(f_decl_, tservice); generate_swift_service_helpers(tservice); generate_swift_service_client_implementation(f_impl_, tservice); if (async_clients_) { generate_swift_service_client_async_implementation(f_impl_, tservice); } generate_swift_service_server_implementation(f_impl_, tservice); } /** * Generates structs for all the service return types * * @param tservice The service */ void t_swift_generator::generate_swift_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_struct* ts = (*f_iter)->get_arglist(); string qname = function_args_helper_struct_type(tservice, *f_iter); t_struct qname_ts = t_struct(ts->get_program(), qname); const vector& members = ts->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { qname_ts.append(*m_iter); } generate_swift_struct(f_impl_, &qname_ts, true); generate_swift_struct_implementation(f_impl_, &qname_ts, false, true); generate_function_helpers(tservice, *f_iter); } } string t_swift_generator::function_result_helper_struct_type(t_service *tservice, t_function* tfunction) { if (tfunction->is_oneway()) { return tservice->get_name() + "_" + tfunction->get_name(); } else { return tservice->get_name() + "_" + tfunction->get_name() + "_result"; } } string t_swift_generator::function_args_helper_struct_type(t_service *tservice, t_function* tfunction) { return tservice->get_name() + "_" + tfunction->get_name() + "_args"; } /** * Generates a struct and helpers for a function. * * @param tfunction The function */ void t_swift_generator::generate_function_helpers(t_service *tservice, t_function* tfunction) { if (tfunction->is_oneway()) { return; } // create a result struct with a success field of the return type, // and a field for each type of exception thrown t_struct result(program_, function_result_helper_struct_type(tservice, tfunction)); if (!tfunction->get_returntype()->is_void()) { t_field* success = new t_field(tfunction->get_returntype(), "success", 0); success->set_req(t_field::T_OPTIONAL); result.append(success); } t_struct* xs = tfunction->get_xceptions(); const vector& fields = xs->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { t_field *x = *f_iter; t_field *ox = new t_field(x->get_type(), x->get_name(), x->get_key()); ox->set_req(t_field::T_OPTIONAL); result.append(ox); } // generate the result struct generate_swift_struct(f_impl_, &result, true); generate_swift_struct_implementation(f_impl_, &result, true, true); for (f_iter = result.get_members().begin(); f_iter != result.get_members().end(); ++f_iter) { delete *f_iter; } } /** * Generates a service protocol definition. * * @param tservice The service to generate a protocol definition for */ void t_swift_generator::generate_swift_service_protocol(ostream& out, t_service* tservice) { if (!gen_cocoa_) { string doc = tservice->get_doc(); generate_docstring(out, doc); indent(out) << "public protocol " << tservice->get_name(); t_service* parent = tservice->get_extends(); if (parent != nullptr) { out << " : " << parent->get_name(); } block_open(out); out << endl; vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { function_docstring(out, *f_iter); indent(out) << function_signature(*f_iter) << endl << endl; } } else { indent(out) << "public protocol " << tservice->get_name(); block_open(out); vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { out << endl; indent(out) << function_signature(*f_iter) << " // exceptions: "; t_struct* xs = (*f_iter)->get_xceptions(); const vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << type_name((*x_iter)->get_type()) + ", "; } out << endl; } } block_close(out); out << endl; } /** * Generates an asynchronous service protocol definition. * * @param tservice The service to generate a protocol definition for */ void t_swift_generator::generate_swift_service_protocol_async(ostream& out, t_service* tservice) { if (!gen_cocoa_) { string doc = tservice->get_doc(); generate_docstring(out, doc); } indent(out) << "public protocol " << tservice->get_name() << "Async"; block_open(out); if (!gen_cocoa_) { out << endl; } vector functions = tservice->get_functions(); vector::iterator f_iter; if (!gen_cocoa_) { for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { async_function_docstring(out, *f_iter); indent(out) << async_function_signature(*f_iter) << endl << endl; } } else { for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { out << endl; indent(out) << async_function_signature(*f_iter) << endl; if (promise_kit_) { indent(out) << promise_function_signature(*f_iter) << endl; } // out << endl; } } block_close(out); out << endl; } /** * Generates a service client interface definition. * * @param tservice The service to generate a client interface definition for */ void t_swift_generator::generate_swift_service_client(ostream& out, t_service* tservice) { if (!gen_cocoa_) { indent(out) << "open class " << tservice->get_name() << "Client";// : " // Inherit from ParentClient t_service* parent = tservice->get_extends(); out << " : " << ((parent == nullptr) ? "TClient" : parent->get_name() + "Client"); out << " /* , " << tservice->get_name() << " */"; block_open(out); out << endl; } else { // a indent(out) << "public class " << tservice->get_name() << "Client /* : " << tservice->get_name() << " */"; block_open(out); out << endl; indent(out) << "let __inProtocol : TProtocol" << endl << endl; indent(out) << "let __outProtocol : TProtocol" << endl << endl; indent(out) << "public init(inoutProtocol: TProtocol)"; block_open(out); indent(out) << "__inProtocol = inoutProtocol" << endl; indent(out) << "__outProtocol = inoutProtocol" << endl; block_close(out); out << endl; indent(out) << "public init(inProtocol: TProtocol, outProtocol: TProtocol)"; block_open(out); indent(out) << "__inProtocol = inProtocol" << endl; indent(out) << "__outProtocol = outProtocol" << endl; block_close(out); out << endl; } block_close(out); out << endl; } /** * Generates a service client interface definition. * * @param tservice The service to generate a client interface definition for */ void t_swift_generator::generate_swift_service_client_async(ostream& out, t_service* tservice) { if (!gen_cocoa_) { indent(out) << "open class " << tservice->get_name() << "AsyncClient";// : " // Inherit from ParentClient t_service* parent = tservice->get_extends(); out << " : " << ((parent == nullptr) ? "T" : parent->get_name()) + "AsyncClient"; out << " /* , " << tservice->get_name() << " */"; block_open(out); out << endl; } else { indent(out) << "public class " << tservice->get_name() << "AsyncClient /* : " << tservice->get_name() << " */"; block_open(out); out << endl; indent(out) << "let __protocolFactory : TProtocolFactory" << endl << endl; indent(out) << "let __transportFactory : TAsyncTransportFactory" << endl << endl; indent(out) << "public init(protocolFactory: TProtocolFactory, transportFactory: TAsyncTransportFactory)"; block_open(out); indent(out) << "__protocolFactory = protocolFactory" << endl; indent(out) << "__transportFactory = transportFactory" << endl; block_close(out); out << endl; } block_close(out); out << endl; } /** * Generates a service server interface definition. In other words, * the TProcess implementation for the service definition. * * @param tservice The service to generate a client interface definition for */ void t_swift_generator::generate_swift_service_server(ostream& out, t_service* tservice) { if (!gen_cocoa_) { indent(out) << "open class " << tservice->get_name() << "Processor /* " << tservice->get_name() << " */"; block_open(out); out << endl; out << indent() << "typealias ProcessorHandlerDictionary = " << "[String: (Int32, TProtocol, TProtocol, " << tservice->get_name() << ") throws -> Void]" << endl << endl << indent() << "public var service: " << tservice->get_name() << endl << endl << indent() << "public required init(service: " << tservice->get_name() << ")"; } else { indent(out) << "public class " << tservice->get_name() << "Processor : NSObject /* " << tservice->get_name() << " */"; block_open(out); out << endl; out << indent() << "typealias ProcessorHandlerDictionary = " << "[String: (Int, TProtocol, TProtocol, " << tservice->get_name() << ") throws -> Void]" << endl << endl << indent() << "let service : " << tservice->get_name() << endl << endl << indent() << "public init(service: " << tservice->get_name() << ")"; } block_open(out); indent(out) << "self.service = service" << endl; block_close(out); out << endl; block_close(out); out << endl; } /** * Generates a function that will send the arguments * for a service function via a protocol. * * @param tservice The service to generate * @param tfunction The function to generate * @param needs_protocol * Wether the first parameter must be a protocol or if * the protocol is to be assumed */ void t_swift_generator::generate_swift_service_client_send_function_implementation(ostream& out, t_service *tservice, t_function* tfunction, bool needs_protocol) { string funname = tfunction->get_name(); t_function send_function(g_type_bool, "send_" + tfunction->get_name(), tfunction->get_arglist()); string argsname = function_args_helper_struct_type(tservice, tfunction); t_struct* arg_struct = tfunction->get_arglist(); string proto = needs_protocol ? (gen_cocoa_ ? "__outProtocol" : "on outProtocol") : ""; // Open function indent(out) << "private func " << send_function.get_name() << "(" << argument_list(tfunction->get_arglist(), proto, true) << ") throws"; block_open(out); if (!gen_cocoa_) { // Serialize the request indent(out) << "try outProtocol.writeMessageBegin(name: \"" << funname << "\", " << "type: " << (tfunction->is_oneway() ? ".oneway" : ".call") << ", " << "sequenceID: 0)" << endl; indent(out) << "let args = " << argsname << "("; // write out function parameters const vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end();) { t_field *tfield = (*f_iter); out << tfield->get_name() << ": " << tfield->get_name(); if (++f_iter != fields.end()) { out << ", "; } } out << ")" << endl; indent(out) << "try args.write(to: outProtocol)" << endl; indent(out) << "try outProtocol.writeMessageEnd()" << endl; } else { out << endl; // Serialize the request indent(out) << "try __outProtocol.writeMessageBeginWithName(\"" << funname << "\", " << "type: " << (tfunction->is_oneway() ? ".ONEWAY" : ".CALL") << ", " << "sequenceID: 0)" << endl; out << endl; indent(out) << "let __args = " << argsname << "("; // write out function parameters const vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end();) { t_field *tfield = (*f_iter); out << tfield->get_name() << ": " << tfield->get_name(); if (++f_iter != fields.end()) { out << ", "; } } out << ")" << endl; indent(out) << "try " << argsname << ".writeValue(__args, toProtocol: __outProtocol)" << endl << endl; indent(out) << "try __outProtocol.writeMessageEnd()" << endl; } block_close(out); out << endl; } /** * Generates a function that will recv the result for a * service function via a protocol. * * @param tservice The service to generate * @param tfunction The function to generate * @param needs_protocol * Wether the first parameter must be a protocol or if * the protocol is to be assumed */ void t_swift_generator::generate_swift_service_client_recv_function_implementation(ostream& out, t_service* tservice, t_function* tfunction, bool needs_protocol) { // Open function indent(out) << "private func recv_" << tfunction->get_name() << "("; if (!gen_cocoa_) { if (needs_protocol) { out << "on inProtocol: TProtocol"; } out << ") throws"; if (!tfunction->get_returntype()->is_void()) { out << " -> " << type_name(tfunction->get_returntype()); } block_open(out); // check for an exception indent(out) << "try inProtocol.readResultMessageBegin() " << endl; string resultname = function_result_helper_struct_type(tservice, tfunction); indent(out); if (!tfunction->get_returntype()->is_void() || !tfunction->get_xceptions()->get_members().empty()) { out << "let result = "; } else { out << "_ = "; } string return_type_name = type_name(tfunction->get_returntype()); out << "try " << resultname << ".read(from: inProtocol)" << endl; indent(out) << "try inProtocol.readMessageEnd()" << endl << endl; // Careful, only return _result if not a void function if (!tfunction->get_returntype()->is_void()) { indent(out) << "if let success = result.success"; block_open(out); indent(out) << "return success" << endl; block_close(out); } t_struct* xs = tfunction->get_xceptions(); const vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { indent(out) << "if let " << (*x_iter)->get_name() << " = result." << (*x_iter)->get_name(); block_open(out); indent(out) << "throw " << (*x_iter)->get_name() << endl; block_close(out); } // If you get here it's an exception, unless a void function if (!tfunction->get_returntype()->is_void()) { indent(out) << "throw TApplicationError(error: .missingResult(methodName: \"" << tfunction->get_name() << "\"))" << endl; } } else { if (needs_protocol) { out << "__inProtocol: TProtocol"; } out << ") throws"; if (!tfunction->get_returntype()->is_void()) { out << " -> " << type_name(tfunction->get_returntype()); } block_open(out); // check for an exception out << endl; indent(out) << "try __inProtocol.readResultMessageBegin() " << endl << endl; string resultname = function_result_helper_struct_type(tservice, tfunction); indent(out); if (!tfunction->get_returntype()->is_void() || !tfunction->get_xceptions()->get_members().empty()) { out << "let __result = "; } out << "try " << resultname << ".readValueFromProtocol(__inProtocol)" << endl << endl; indent(out) << "try __inProtocol.readMessageEnd()" << endl << endl; // Careful, only return _result if not a void function if (!tfunction->get_returntype()->is_void()) { indent(out) << "if let __success = __result.success"; block_open(out); indent(out) << "return __success" << endl; block_close(out); } t_struct* xs = tfunction->get_xceptions(); const vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { indent(out) << "if let " << (*x_iter)->get_name() << " = __result." << (*x_iter)->get_name(); block_open(out); indent(out) << "throw " << (*x_iter)->get_name() << endl; block_close(out); } // If you get here it's an exception, unless a void function if (!tfunction->get_returntype()->is_void()) { indent(out) << "throw NSError(" << endl; indent_up(); indent(out) << "domain: TApplicationErrorDomain, " << endl; indent(out) << "code: Int(TApplicationError.MissingResult.rawValue)," << endl; indent(out) << "userInfo: [TApplicationErrorMethodKey: \"" << tfunction->get_name() << "\"])" << endl; indent_down(); } } // Close function block_close(out); out << endl; } /** * Generates an invocation of a given the send function for the * service function. * * @param tfunction The service to generate an implementation for */ void t_swift_generator::generate_swift_service_client_send_function_invocation(ostream& out, t_function* tfunction) { indent(out) << "try send_" << tfunction->get_name() << "("; t_struct* arg_struct = tfunction->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end();) { out << (*f_iter)->get_name() << ": " << (*f_iter)->get_name(); if (++f_iter != fields.end()) { out << ", "; } } out << ")" << endl; } /** * Generates an invocation of a given the send function for the * service function. This is for asynchronous protocols. * * @param tfunction The service to generate an implementation for */ void t_swift_generator::generate_swift_service_client_send_async_function_invocation(ostream& out, t_function* tfunction) { t_struct* arg_struct = tfunction->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; if (!gen_cocoa_) { indent(out) << "try send_" << tfunction->get_name() << "(on: proto"; } else { indent(out) << "try send_" << tfunction->get_name() << "(__protocol"; // } for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { out << ", " << (*f_iter)->get_name() << ": " << (*f_iter)->get_name(); } out << ")" << endl; } /** * Generates a service client protocol implementation via extension. * * @param tservice The service to generate an implementation for */ void t_swift_generator::generate_swift_service_client_implementation(ostream& out, t_service* tservice) { string name = tservice->get_name() + "Client"; indent(out) << "extension " << name << " : " << tservice->get_name(); block_open(out); out << endl; // generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, false); if (!(*f_iter)->is_oneway()) { generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, false); } // Open function indent(out) << "public " << function_signature(*f_iter); block_open(out); if (gen_cocoa_) { out << endl; } generate_swift_service_client_send_function_invocation(out, *f_iter); if (!gen_cocoa_) { indent(out) << "try outProtocol.transport.flush()" << endl; } else { out << endl; indent(out) << "try __outProtocol.transport().flush()" << endl << endl; } if (!(*f_iter)->is_oneway()) { if ((*f_iter)->get_returntype()->is_void()) { indent(out) << "try recv_" << (*f_iter)->get_name() << "()" << endl; } else { indent(out) << "return try recv_" << (*f_iter)->get_name() << "()" << endl; } } block_close(out); out << endl; } block_close(out); out << endl; } /** * Generates a service asynchronous client protocol implementation via extension. * * @param tservice The service to generate an implementation for */ void t_swift_generator::generate_swift_service_client_async_implementation(ostream& out, t_service* tservice) { if (gen_cocoa_) { generate_old_swift_service_client_async_implementation(out, tservice); return; } string name = tservice->get_name() + "AsyncClient"; string protocol_name = tservice->get_name() + "Async"; indent(out) << "extension " << name << " : " << protocol_name; block_open(out); out << endl; // generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, true); if (!(*f_iter)->is_oneway()) { generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, true); } indent(out) << "public " << async_function_signature(*f_iter); block_open(out); out << endl; out << indent() << "let transport = factory.newTransport()" << endl << indent() << "let proto = Protocol(on: transport)" << endl << endl; out << indent() << "do"; block_open(out); generate_swift_service_client_send_async_function_invocation(out, *f_iter); indent_down(); out << indent() << "} catch let error {" << endl; indent_up(); out << indent() << "completion(.error(error))" << endl; block_close(out); out << endl; bool ret_is_void = (*f_iter)->get_returntype()->is_void(); bool is_oneway = (*f_iter)->is_oneway(); string error_completion_call = "completion(.error(error))"; indent(out) << "transport.flush"; block_open(out); out << indent() << "(trans, error) in" << endl << endl; out << indent() << "if let error = error"; block_open(out); out << indent() << error_completion_call << endl; block_close(out); if (!is_oneway) { out << indent() << "do"; block_open(out); indent(out); if (!ret_is_void) { out << "let result = "; } out << "try self.recv_" << (*f_iter)->get_name() << "(on: proto)" << endl; out << indent() << (ret_is_void ? "completion(.success(Void()))" : "completion(.success(result))") << endl; indent_down(); out << indent() << "} catch let error {" << endl; indent_up(); out << indent() << error_completion_call << endl; block_close(out); } else { out << indent() << "completion(.success(Void()))" << endl; } block_close(out); block_close(out); } block_close(out); out << endl; } void t_swift_generator::generate_old_swift_service_client_async_implementation(ostream& out, t_service* tservice) { string name = tservice->get_name() + "AsyncClient"; string protocol_name = tservice->get_name() + "Async"; indent(out) << "extension " << name << " : " << protocol_name; block_open(out); out << endl; // generate client method implementations vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, true); if (!(*f_iter)->is_oneway()) { generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, true); } indent(out) << "public " << async_function_signature(*f_iter); block_open(out); out << endl; out << indent() << "let __transport = __transportFactory.newTransport()" << endl << indent() << "let __protocol = __protocolFactory.newProtocolOnTransport(__transport)" << endl << endl; generate_swift_service_client_send_async_function_invocation(out, *f_iter); out << endl; indent(out) << "__transport.flushWithCompletion("; if ((*f_iter)->is_oneway()) { out << "success, failure: failure)" << endl; } else { block_open(out); indent(out) << "do"; block_open(out); indent(out); if (!(*f_iter)->get_returntype()->is_void()) { out << "let result = "; } out << "try self.recv_" << (*f_iter)->get_name() << "(__protocol)" << endl; out << indent() << "success("; if (!(*f_iter)->get_returntype()->is_void()) { out << "result"; } out << ")" << endl; block_close(out); indent(out) << "catch let error"; block_open(out); indent(out) << "failure(error as NSError)" << endl; block_close(out); block_close(out); indent(out) << ", failure: failure)" << endl; } block_close(out); out << endl; // Promise function if (promise_kit_) { indent(out) << "public " << promise_function_signature(*f_iter); block_open(out); out << indent() << "let (__promise, __fulfill, __reject) = Promise<" << type_name((*f_iter)->get_returntype()) << ">.pendingPromise()" << endl << endl << indent() << "let __transport = __transportFactory.newTransport()" << endl << indent() << "let __protocol = __protocolFactory.newProtocolOnTransport(__transport)" << endl << endl; generate_swift_service_client_send_async_function_invocation(out, *f_iter); out << endl; indent(out) << "__transport.flushWithCompletion("; if ((*f_iter)->is_oneway()) { out << "{ __fulfill() }, failure: { __reject($0) })" << endl; } else { block_open(out); indent(out) << "do"; block_open(out); indent(out); if (!(*f_iter)->get_returntype()->is_void()) { out << "let result = "; } out << "try self.recv_" << (*f_iter)->get_name() << "(__protocol)" << endl; out << indent() << "__fulfill("; if (!(*f_iter)->get_returntype()->is_void()) { out << "result"; } out << ")" << endl; block_close(out); indent(out) << "catch let error"; block_open(out); indent(out) << "__reject(error)" << endl; block_close(out); block_close(out); indent(out) << ", failure: { error in " << endl; indent_up(); indent(out) << "__reject(error)" << endl; indent_down(); indent(out) << "})" << endl; } indent(out) << "return __promise" << endl; block_close(out); out << endl; } } block_close(out); out << endl; } /** * Generates a service server implementation. * * Implemented by generating a block for each service function that * handles the processing of that function. The blocks are stored in * a map and looked up via function/message name. * * @param tservice The service to generate an implementation for */ void t_swift_generator::generate_swift_service_server_implementation(ostream& out, t_service* tservice) { string name = tservice->get_name() + "Processor"; indent(out) << "extension " << name << " : TProcessor"; block_open(out); out << endl; indent(out) << "static let processorHandlers" << (gen_cocoa_ ? " " : "") << ": ProcessorHandlerDictionary ="; block_open(out); out << endl; out << indent() << "var processorHandlers = ProcessorHandlerDictionary()" << endl << endl; // generate method map for routing incoming calls vector functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { t_function* tfunction = *f_iter; string args_type = function_args_helper_struct_type(tservice, *f_iter); out << indent() << "processorHandlers[\"" << tfunction->get_name() << "\"] = { sequenceID, inProtocol, outProtocol, handler in" << endl << endl; indent_up(); if (!gen_cocoa_) { out << indent() << "let args = try " << args_type << ".read(from: inProtocol)" << endl << endl << indent() << "try inProtocol.readMessageEnd()" << endl << endl; } else { out << indent() << "let args = try " << args_type << ".readValueFromProtocol(inProtocol)" << endl << endl << indent() << "try inProtocol.readMessageEnd()" << endl << endl; } if (!tfunction->is_oneway() ) { string result_type = function_result_helper_struct_type(tservice, tfunction); indent(out) << "var result = " << result_type << "()" << endl; indent(out) << "do"; block_open(out); indent(out); if (!tfunction->get_returntype()->is_void()) { out << "result.success = "; } out << "try handler." << (gen_cocoa_ ? function_name(tfunction) : tfunction->get_name()) << "("; t_struct* arg_struct = tfunction->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator f_iter; for (f_iter = fields.begin(); f_iter != fields.end();) { string fieldName = (*f_iter)->get_name(); if (!gen_cocoa_ || f_iter != fields.begin()) { out << fieldName << ": "; } out << "args." << fieldName; if (++f_iter != fields.end()) { out << ", "; } } out << ")" << endl; block_close(out); t_struct* xs = tfunction->get_xceptions(); const vector& xfields = xs->get_members(); vector::const_iterator x_iter; if (!gen_cocoa_) { for (x_iter = xfields.begin(); x_iter != xfields.end(); ++x_iter) { indent(out) << "catch let error as "; t_program* program = (*x_iter)->get_type()->get_program(); if ((*x_iter)->get_type()->get_name() == "Error" && namespaced_ && program != program_) { out << get_real_swift_module(program) << "."; } out << (*x_iter)->get_type()->get_name(); out << " { result." << (*x_iter)->get_name() << " = error }" << endl; } indent(out) << "catch let error { throw error }" << endl; out << endl; if (!tfunction->is_oneway()) { out << indent() << "try outProtocol.writeMessageBegin(name: \"" << tfunction->get_name() << "\", type: .reply, sequenceID: sequenceID)" << endl << indent() << "try result.write(to: outProtocol)" << endl << indent() << "try outProtocol.writeMessageEnd()" << endl << indent() << "try outProtocol.transport.flush()" << endl; } } else { for (x_iter = xfields.begin(); x_iter != xfields.end(); ++x_iter) { indent(out) << "catch let error as " << (*x_iter)->get_type()->get_name(); block_open(out); indent(out) << "result." << (*x_iter)->get_name() << " = error" << endl; block_close(out); } indent(out) << "catch let error"; block_open(out); out << indent() << "throw error" << endl; block_close(out); out << endl; if (!tfunction->is_oneway()) { out << indent() << "try outProtocol.writeMessageBeginWithName(\"" << tfunction->get_name() << "\", type: .REPLY, sequenceID: sequenceID)" << endl << indent() << "try " << result_type << ".writeValue(result, toProtocol: outProtocol)" << endl << indent() << "try outProtocol.writeMessageEnd()" << endl; } } } block_close(out); } indent(out) << "return processorHandlers" << endl; block_close(out,false); out << "()" << endl; out << endl; if (!gen_cocoa_) { indent(out) << "public func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws"; } else { indent(out) << "public func processOnInputProtocol(inProtocol: TProtocol, outputProtocol outProtocol: TProtocol) throws"; } block_open(out); out << endl; out << indent() << "let (messageName, _, sequenceID) = try inProtocol.readMessageBegin()" << endl << endl << indent() << "if let processorHandler = " << name << ".processorHandlers[messageName]"; block_open(out); out << indent() << "do"; block_open(out); out << indent() << "try processorHandler(sequenceID, inProtocol, outProtocol, service)" << endl; block_close(out); if (!gen_cocoa_) { out << indent() << "catch let error as TApplicationError"; block_open(out); out << indent() << "try outProtocol.writeException(messageName: messageName, sequenceID: sequenceID, ex: error)" << endl << indent() << "try outProtocol.transport.flush()" << endl; block_close(out); block_close(out); out << indent() << "else"; block_open(out); out << indent() << "try inProtocol.skip(type: .struct)" << endl << indent() << "try inProtocol.readMessageEnd()" << endl << indent() << "let ex = TApplicationError(error: .unknownMethod(methodName: messageName))" << endl << indent() << "try outProtocol.writeException(messageName: messageName, sequenceID: sequenceID, ex: ex)" << endl << indent() << "try outProtocol.transport.flush()" << endl; } else { out << indent() << "catch let error as NSError"; block_open(out); out << indent() << "try outProtocol.writeExceptionForMessageName(messageName, sequenceID: sequenceID, ex: error)" << endl; block_close(out); block_close(out); out << indent() << "else"; block_open(out); out << indent() << "try inProtocol.skipType(.STRUCT)" << endl << indent() << "try inProtocol.readMessageEnd()" << endl << indent() << "try outProtocol.writeExceptionForMessageName(messageName," << endl; indent_up(); out << indent() << "sequenceID: sequenceID," << endl << indent() << "ex: NSError(" << endl; indent_up(); out << indent() << "domain: TApplicationErrorDomain, " << endl << indent() << "code: Int(TApplicationError.UnknownMethod.rawValue), " << endl << indent() << "userInfo: [TApplicationErrorMethodKey: messageName]))" << endl; indent_down(); indent_down(); } block_close(out); block_close(out); block_close(out); out << endl; } /** * Returns an Swift name * * @param ttype The type * @param class_ref Do we want a Class reference istead of a type reference? * @return Swift type name, i.e. Dictionary */ string t_swift_generator::type_name(t_type* ttype, bool is_optional, bool is_forced) { string result = ""; if (ttype->is_base_type()) { result += base_type_name((t_base_type*)ttype); } else if (ttype->is_map()) { t_map *map = (t_map *)ttype; result += "TMap<" + type_name(map->get_key_type()) + ", " + type_name(map->get_val_type()) + ">"; } else if (ttype->is_set()) { t_set *set = (t_set *)ttype; result += "TSet<" + type_name(set->get_elem_type()) + ">"; } else if (ttype->is_list()) { t_list *list = (t_list *)ttype; result += "TList<" + type_name(list->get_elem_type()) + ">"; } else { t_program* program = ttype->get_program(); if (namespaced_ && program != program_) { result += get_real_swift_module(program) + "."; } result += ttype->get_name(); } if (is_optional) { result += "?"; } if (is_forced) { result += "!"; } return result; } /** * Returns the Swift type that corresponds to the thrift type. * * @param tbase The base type */ string t_swift_generator::base_type_name(t_base_type* type) { t_base_type::t_base tbase = type->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: return "Void"; case t_base_type::TYPE_STRING: if (type->is_binary()) { return gen_cocoa_ ? "TBinary" : "Data"; } else { return "String"; } case t_base_type::TYPE_BOOL: return "Bool"; case t_base_type::TYPE_I8: return "Int8"; case t_base_type::TYPE_I16: return "Int16"; case t_base_type::TYPE_I32: return "Int32"; case t_base_type::TYPE_I64: return "Int64"; case t_base_type::TYPE_DOUBLE: return "Double"; default: throw "compiler error: no Swift name for base type " + t_base_type::t_base_name(tbase); } } /** * Renders full constant value (as would be seen after an '=') * */ void t_swift_generator::render_const_value(ostream& out, t_type* type, t_const_value* value) { type = get_true_type(type); if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: out << "\"" << get_escaped_string(value) << "\""; break; case t_base_type::TYPE_BOOL: out << ((value->get_integer() > 0) ? "true" : "false"); break; case t_base_type::TYPE_I8: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: out << type_name(type) << "(" << value->get_integer() << ")"; break; case t_base_type::TYPE_DOUBLE: out << type_name(type) << "("; if (value->get_type() == t_const_value::CV_INTEGER) { out << value->get_integer(); } else { out << value->get_double(); } out << ")"; break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); } } else if (type->is_enum()) { out << (gen_cocoa_ ? value->get_identifier() : enum_const_name(value->get_identifier())); // Swift2/Cocoa compatibility } else if (type->is_struct() || type->is_xception()) { out << type_name(type) << "("; const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (f_iter = fields.begin(); f_iter != fields.end();) { t_field* tfield = *f_iter; t_const_value* value = nullptr; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { if (tfield->get_name() == v_iter->first->get_string()) { value = v_iter->second; } } if (value) { out << tfield->get_name() << ": "; render_const_value(out, tfield->get_type(), value); } else if (!field_is_optional(tfield)) { throw "constant error: required field " + type->get_name() + "." + tfield->get_name() + " has no value"; } if (++f_iter != fields.end()) { out << ", "; } } out << ")"; } else if (type->is_map()) { out << "["; t_type* ktype = ((t_map*)type)->get_key_type(); t_type* vtype = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end();) { render_const_value(out, ktype, v_iter->first); out << ": "; render_const_value(out, vtype, v_iter->second); if (++v_iter != val.end()) { out << ", "; } } out << "]"; } else if (type->is_list()) { out << "["; t_type* etype = ((t_list*)type)->get_elem_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end();) { render_const_value(out, etype, v_iter->first); if (++v_iter != val.end()) { out << ", "; } } out << "]"; } else if (type->is_set()) { out << "["; t_type* etype = ((t_set*)type)->get_elem_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end();) { render_const_value(out, etype, v_iter->first); if (++v_iter != val.end()) { out << ", "; } } out << "]"; } else { throw "compiler error: no const of type " + type->get_name(); } } /** * Declares an Swift property. * * @param tfield The field to declare a property for */ string t_swift_generator::declare_property(t_field* tfield, bool is_private) { string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public"; ostringstream render; render << visibility << " var " << maybe_escape_identifier(tfield->get_name()); if (field_is_optional(tfield)) { render << (gen_cocoa_ ? " " : "") << ": " << type_name(tfield->get_type(), true); } else { if (!gen_cocoa_) { render << ": " << type_name(tfield->get_type(), false); } else { // Swift2/Cocoa backward compat, Bad, default init render << " = " << type_name(tfield->get_type(), false) << "()"; } } return render.str(); } /** * Renders a function signature * * @param tfunction Function definition * @return String of rendered function definition */ string t_swift_generator::function_signature(t_function* tfunction) { string result = "func " + (gen_cocoa_ ? function_name(tfunction) : tfunction->get_name()); result += "(" + argument_list(tfunction->get_arglist(), "", false) + ") throws"; /// argsreview t_type* ttype = tfunction->get_returntype(); if (!ttype->is_void()) { result += " -> " + type_name(ttype); } return result; } /** * Renders a function docstring * * @param tfunction Function definition * @return String of rendered function definition */ void t_swift_generator::function_docstring(ostream& out, t_function* tfunction) { // Generate docstring with following format: // /// // /// // /// - Parameters: // /// - : // /// - Returns: (Thrift has no docstring on return val) // /// - Throws: // Description string doc = tfunction->get_doc(); generate_docstring(out, doc); indent(out) << "///" << endl; // Parameters const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator f_iter; if (!fields.empty()) { indent(out) << "/// - Parameters:" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "/// - " << (*f_iter)->get_name() << ": "; string doc = (*f_iter)->get_doc(); if (!doc.empty() && doc[doc.length()-1] == '\n') { doc.erase(doc.length()-1); } out << doc << endl; } } // Returns t_type* ttype = tfunction->get_returntype(); if (!ttype->is_void()) { indent(out) << "/// - Returns: " << type_name(ttype) << endl; } // Throws indent(out) << "/// - Throws: "; t_struct* xs = tfunction->get_xceptions(); const vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << type_name((*x_iter)->get_type()); if (*x_iter != xceptions.back()) { out << ", "; } } out << endl; } /** * Renders a function docstring * * @param tfunction Function definition * @return String of rendered function definition */ void t_swift_generator::async_function_docstring(ostream& out, t_function* tfunction) { // Generate docstring with following format: // /// // /// // /// - Parameters: // /// - : // /// - callback: // Description string doc = tfunction->get_doc(); generate_docstring(out, doc); indent(out) << "///" << endl; // Parameters const vector& fields = tfunction->get_arglist()->get_members(); vector::const_iterator f_iter; if (!fields.empty()) { indent(out) << "/// - Parameters:" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { indent(out) << "/// - " << (*f_iter)->get_name() << ": "; string doc = (*f_iter)->get_doc(); if (!doc.empty() && doc[doc.length()-1] == '\n') { doc.erase(doc.length()-1); } out << doc << endl; } } // completion indent(out) << "/// - completion: Result<" << type_name(tfunction->get_returntype()) << ", Error> wrapping return and following Exceptions: "; t_struct* xs = tfunction->get_xceptions(); const vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { out << type_name((*x_iter)->get_type()); if (*x_iter != xceptions.back()) { out << ", "; } } out << endl; } /** * Renders a function signature that returns asynchronously via blocks. * * @param tfunction Function definition * @return String of rendered function definition */ string t_swift_generator::async_function_signature(t_function* tfunction) { t_type* ttype = tfunction->get_returntype(); t_struct* targlist = tfunction->get_arglist(); string result = "func " + (gen_cocoa_ ? function_name(tfunction) : tfunction->get_name()); if (!gen_cocoa_) { string response_string = "(Result<"; response_string += (ttype->is_void()) ? "Void" : type_name(ttype); response_string += ", Error>) -> Void"; result += "(" + argument_list(tfunction->get_arglist(), "", false) + (targlist->get_members().size() ? ", " : "") + "completion: @escaping " + response_string + ")"; } else { string response_param = "(" + ((ttype->is_void()) ? "" : type_name(ttype)) + ") -> Void"; result += "(" + argument_list(tfunction->get_arglist(), "", false) + (targlist->get_members().size() ? ", " : "") + "success: " + response_param + ", " + "failure: (NSError) -> Void) throws"; } return result; } /** * Renders a function signature that returns asynchronously via promises. * ONLY FOR Swift2/Cocoa BACKWARDS COMPATIBILITY * * @param tfunction Function definition * @return String of rendered function definition */ string t_swift_generator::promise_function_signature(t_function* tfunction) { return "func " + function_name(tfunction) + "(" + argument_list(tfunction->get_arglist(), "", false) + ") throws " + "-> Promise<" + type_name(tfunction->get_returntype()) + ">"; } /** * Renders a verbose function name suitable for a Swift method. ONLY FOR Swift2/Cocoa BACKWARDS COMPATIBILITY */ string t_swift_generator::function_name(t_function* tfunction) { string name = tfunction->get_name(); if (!tfunction->get_arglist()->get_members().empty()) { string first_arg = tfunction->get_arglist()->get_members().front()->get_name(); if (name.size() < first_arg.size() || lowercase(name.substr(name.size()-first_arg.size())) != lowercase(first_arg)) { name += "With" + capitalize(tfunction->get_arglist()->get_members()[0]->get_name()); } } return name; } /** * Renders a Swift method argument list */ string t_swift_generator::argument_list(t_struct* tstruct, string protocol_name, bool is_internal) { string result = ""; bool include_protocol = !protocol_name.empty(); const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; if (include_protocol) { result += protocol_name + ": TProtocol"; if (!fields.empty()) { result += ", "; } } else if (!fields.empty() && is_internal && gen_cocoa_) { // Force first argument to be named, Swift2/Cocoa backwards compat result += fields.front()->get_name() + " "; } for (f_iter = fields.begin(); f_iter != fields.end();) { t_field* arg = *f_iter; if (!gen_cocoa_) { // optional args not usually permitted for some reason, even though dynamic langs handle it // use annotation "swift.nullable" to achieve result += arg->get_name() + ": " + type_name(arg->get_type(), field_is_optional(arg)); } else { result += arg->get_name() + ": " + type_name(arg->get_type()); } if (++f_iter != fields.end()) { result += ", "; } } return result; } /** * https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html * */ void t_swift_generator::populate_reserved_words() { if (!gen_cocoa_) { swift_reserved_words_.insert("__COLUMN__"); swift_reserved_words_.insert("__FILE__"); swift_reserved_words_.insert("__FUNCTION__"); swift_reserved_words_.insert("__LINE__"); swift_reserved_words_.insert("Any"); swift_reserved_words_.insert("as"); swift_reserved_words_.insert("associatedtype"); swift_reserved_words_.insert("associativity"); swift_reserved_words_.insert("break"); swift_reserved_words_.insert("case"); swift_reserved_words_.insert("catch"); swift_reserved_words_.insert("class"); swift_reserved_words_.insert("continue"); swift_reserved_words_.insert("convenience"); swift_reserved_words_.insert("default"); swift_reserved_words_.insert("defer"); swift_reserved_words_.insert("deinit"); swift_reserved_words_.insert("didSet"); swift_reserved_words_.insert("do"); swift_reserved_words_.insert("dynamic"); swift_reserved_words_.insert("dynamicType"); swift_reserved_words_.insert("else"); swift_reserved_words_.insert("enum"); swift_reserved_words_.insert("extension"); swift_reserved_words_.insert("fallthrough"); swift_reserved_words_.insert("false"); swift_reserved_words_.insert("fileprivate"); swift_reserved_words_.insert("final"); swift_reserved_words_.insert("for"); swift_reserved_words_.insert("func"); swift_reserved_words_.insert("get"); swift_reserved_words_.insert("guard"); swift_reserved_words_.insert("if"); swift_reserved_words_.insert("import"); swift_reserved_words_.insert("in"); swift_reserved_words_.insert("indirect"); swift_reserved_words_.insert("infix"); swift_reserved_words_.insert("init"); swift_reserved_words_.insert("inout"); swift_reserved_words_.insert("internal"); swift_reserved_words_.insert("is"); swift_reserved_words_.insert("lazy"); swift_reserved_words_.insert("left"); swift_reserved_words_.insert("let"); swift_reserved_words_.insert("mutating"); swift_reserved_words_.insert("nil"); swift_reserved_words_.insert("none"); swift_reserved_words_.insert("nonmutating"); swift_reserved_words_.insert("open"); swift_reserved_words_.insert("operator"); swift_reserved_words_.insert("optional"); swift_reserved_words_.insert("override"); swift_reserved_words_.insert("postfix"); swift_reserved_words_.insert("precedence"); swift_reserved_words_.insert("prefix"); swift_reserved_words_.insert("private"); swift_reserved_words_.insert("protocol"); swift_reserved_words_.insert("Protocol"); swift_reserved_words_.insert("public"); swift_reserved_words_.insert("repeat"); swift_reserved_words_.insert("required"); swift_reserved_words_.insert("rethrows"); swift_reserved_words_.insert("return"); swift_reserved_words_.insert("right"); swift_reserved_words_.insert("self"); swift_reserved_words_.insert("Self"); swift_reserved_words_.insert("set"); swift_reserved_words_.insert("static"); swift_reserved_words_.insert("struct"); swift_reserved_words_.insert("subscript"); swift_reserved_words_.insert("super"); swift_reserved_words_.insert("switch"); swift_reserved_words_.insert("throw"); swift_reserved_words_.insert("throws"); swift_reserved_words_.insert("true"); swift_reserved_words_.insert("try"); swift_reserved_words_.insert("Type"); swift_reserved_words_.insert("typealias"); swift_reserved_words_.insert("unowned"); swift_reserved_words_.insert("var"); swift_reserved_words_.insert("weak"); swift_reserved_words_.insert("where"); swift_reserved_words_.insert("while"); swift_reserved_words_.insert("willSet"); } else { swift_reserved_words_.insert("Self"); swift_reserved_words_.insert("associatedtype"); swift_reserved_words_.insert("defer"); swift_reserved_words_.insert("deinit"); swift_reserved_words_.insert("dynamicType"); swift_reserved_words_.insert("enum"); swift_reserved_words_.insert("extension"); swift_reserved_words_.insert("fallthrough"); swift_reserved_words_.insert("false"); swift_reserved_words_.insert("func"); swift_reserved_words_.insert("guard"); swift_reserved_words_.insert("init"); swift_reserved_words_.insert("inout"); swift_reserved_words_.insert("internal"); swift_reserved_words_.insert("let"); swift_reserved_words_.insert("operator"); swift_reserved_words_.insert("protocol"); swift_reserved_words_.insert("repeat"); swift_reserved_words_.insert("rethrows"); swift_reserved_words_.insert("struct"); swift_reserved_words_.insert("subscript"); swift_reserved_words_.insert("throws"); swift_reserved_words_.insert("true"); swift_reserved_words_.insert("typealias"); swift_reserved_words_.insert("where"); } } string t_swift_generator::maybe_escape_identifier(const string& identifier) { if (swift_reserved_words_.find(identifier) != swift_reserved_words_.end()) { return "`" + identifier + "`"; } return identifier; } /** * Converts the parse type to a Swift TType enumeration. */ string t_swift_generator::type_to_enum(t_type* type, bool qualified) { type = get_true_type(type); string result = qualified ? "TType." : "."; if (!gen_cocoa_) { if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return result + "string"; case t_base_type::TYPE_BOOL: return result + "bool"; case t_base_type::TYPE_I8: return result + "i8"; case t_base_type::TYPE_I16: return result + "i16"; case t_base_type::TYPE_I32: return result + "i32"; case t_base_type::TYPE_I64: return result + "i64"; case t_base_type::TYPE_DOUBLE: return result + "double"; } } else if (type->is_enum()) { return result + "i32"; } else if (type->is_struct() || type->is_xception()) { return result + "struct"; } else if (type->is_map()) { return result + "map"; } else if (type->is_set()) { return result + "set"; } else if (type->is_list()) { return result + "list"; } } else { if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_VOID: throw "NO T_VOID CONSTRUCT"; case t_base_type::TYPE_STRING: return result + "STRING"; case t_base_type::TYPE_BOOL: return result + "BOOL"; case t_base_type::TYPE_I8: return result + "BYTE"; case t_base_type::TYPE_I16: return result + "I16"; case t_base_type::TYPE_I32: return result + "I32"; case t_base_type::TYPE_I64: return result + "I64"; case t_base_type::TYPE_DOUBLE: return result + "DOUBLE"; } } else if (type->is_enum()) { return result + "I32"; } else if (type->is_struct() || type->is_xception()) { return result + "STRUCT"; } else if (type->is_map()) { return result + "MAP"; } else if (type->is_set()) { return result + "SET"; } else if (type->is_list()) { return result + "LIST"; } } throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } THRIFT_REGISTER_GENERATOR( swift, "Swift 3.0", " log_unexpected: Log every time an unexpected field ID or type is encountered.\n" " debug_descriptions:\n" " Allow use of debugDescription so the app can add description via a cateogory/extension\n" " async_clients: Generate clients which invoke asynchronously via block syntax.\n" " namespaced: Generate source in Module scoped output directories for Swift Namespacing.\n" " cocoa: Generate Swift 2.x code compatible with the Thrift/Cocoa library\n" " promise_kit: Generate clients which invoke asynchronously via promises (only use with cocoa flag)\n" " safe_enums: Generate enum types with an unknown case to handle unspecified values rather than throw a serialization error\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_xml_generator.cc000066400000000000000000000464701420101504100250520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include "thrift/platform.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; using std::stack; using std::set; static const string endl = "\n"; static const string quot = "\""; static const string default_ns_prefix = "http://thrift.apache.org/xml/ns/"; /** * This generator creates an XML model of the parsed IDL tree, and is designed * to make it easy to use this file as the input for other template engines, * such as XSLT. To this end, the generated XML is slightly more verbose than * you might expect... for example, references to "id" types (such as structs, * unions, etc) always specify the name of the IDL document, even if the type * is defined in the same document as the reference. */ class t_xml_generator : public t_generator { public: t_xml_generator( t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; should_merge_includes_ = false; should_use_default_ns_ = true; should_use_namespaces_ = true; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("merge") == 0) { should_merge_includes_ = true; } else if( iter->first.compare("no_default_ns") == 0) { should_use_default_ns_ = false; } else if( iter->first.compare("no_namespaces") == 0) { should_use_namespaces_ = false; } else { throw "unknown option xml:" + iter->first; } } out_dir_base_ = "gen-xml"; } ~t_xml_generator() override = default; void init_generator() override; void close_generator() override; void generate_program() override; void iterate_program(t_program* program); void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override; void generate_function(t_function* tfunc); void generate_field(t_field* field); void generate_service(t_service* tservice) override; void generate_struct(t_struct* tstruct) override; void generate_annotations(std::map annotations); private: bool should_merge_includes_; bool should_use_default_ns_; bool should_use_namespaces_; ofstream_with_content_based_conditional_update f_xml_; std::set programs_; std::stack elements_; bool top_element_is_empty; bool top_element_is_open; string target_namespace(t_program* program); void write_element_start(const string name); void close_top_element(); void write_element_end(); void write_attribute(string key, string val); void write_int_attribute(string key, int val); string escape_xml_string(const string& input); void write_xml_comment(string msg); void write_type(t_type* ttype); void write_doc(t_doc* tdoc); template string number_to_string(T t) { std::ostringstream out; out.imbue(std::locale::classic()); out.precision(std::numeric_limits::digits10); out << t; return out.str(); } template void write_number(T n) { f_xml_ << number_to_string(n); } template void write_element_number(string name, T n) { write_element_string(name, number_to_string(n)); } string get_type_name(t_type* ttype); void generate_constant(t_const* con); void write_element_string(string name, string value); void write_value(t_type* tvalue); void write_const_value(t_const_value* value); virtual std::string xml_autogen_comment() { return std::string("\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"; } }; void t_xml_generator::init_generator() { MKDIR(get_out_dir().c_str()); string f_xml_name = get_out_dir() + program_->get_name() + ".xml"; f_xml_.open(f_xml_name.c_str()); top_element_is_open = false; } string t_xml_generator::target_namespace(t_program* program) { std::map map; std::map::iterator iter; map = program->get_namespace_annotations("xml"); if ((iter = map.find("targetNamespace")) != map.end()) { return iter->second; } map = program->get_namespaces(); if ((iter = map.find("xml")) != map.end()) { return default_ns_prefix + iter->second; } map = program->get_namespace_annotations("*"); if ((iter = map.find("xml.targetNamespace")) != map.end()) { return iter->second; } map = program->get_namespaces(); if ((iter = map.find("*")) != map.end()) { return default_ns_prefix + iter->second; } return default_ns_prefix + program->get_name(); } void t_xml_generator::write_xml_comment(string msg) { close_top_element(); // TODO: indent any EOLs that may occur with msg // TODO: proper msg escaping needed? f_xml_ << indent() << "" << endl; top_element_is_empty = false; } void t_xml_generator::close_top_element() { if( top_element_is_open) { top_element_is_open = false; if (elements_.size() > 0 && top_element_is_empty) { f_xml_ << ">" << endl; } } } void t_xml_generator::write_element_start(string name) { if (should_use_namespaces_ && !should_use_default_ns_) { name = "idl:" + name; } close_top_element(); f_xml_ << indent() << "<" << name; elements_.push(name); top_element_is_empty = true; top_element_is_open = true; indent_up(); } void t_xml_generator::write_element_end() { indent_down(); if (top_element_is_empty && top_element_is_open) { f_xml_ << " />" << endl; } else { f_xml_ << indent() << "" << endl; } top_element_is_empty = false; elements_.pop(); } void t_xml_generator::write_attribute(string key, string val) { f_xml_ << " " << key << "=\"" << escape_xml_string(val) << "\""; } void t_xml_generator::write_int_attribute(string key, int val) { write_attribute(key, number_to_string(val)); } void t_xml_generator::write_element_string(string name, string val) { if (should_use_namespaces_ && !should_use_default_ns_) { name = "idl:" + name; } close_top_element(); top_element_is_empty = false; f_xml_ << indent() << "<" << name << ">" << escape_xml_string(val) << "" << endl; } string t_xml_generator::escape_xml_string(const string& input) { std::ostringstream ss; for (char iter : input) { switch (iter) { case '&': ss << "&"; break; case '"': ss << """; break; case '\'': ss << "'"; break; case '<': ss << "<"; break; case '>': ss << ">"; break; default: ss << iter; break; } } return ss.str(); } void t_xml_generator::close_generator() { f_xml_.close(); } void t_xml_generator::generate_program() { init_generator(); write_element_start("idl"); if (should_use_namespaces_) { if (should_use_default_ns_) { write_attribute("xmlns", "http://thrift.apache.org/xml/idl"); } write_attribute("xmlns:idl", "http://thrift.apache.org/xml/idl"); } write_xml_comment( xml_autogen_comment()); iterate_program(program_); write_element_end(); close_generator(); } void t_xml_generator::iterate_program(t_program* program) { write_element_start("document"); write_attribute("name", program->get_name()); if (should_use_namespaces_) { const string targetNamespace = target_namespace(program); write_attribute("targetNamespace", targetNamespace); write_attribute("xmlns:" + program->get_name(), targetNamespace); } write_doc(program); const vector includes = program->get_includes(); vector::const_iterator inc_it; for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) { write_element_start("include"); write_attribute("name", (*inc_it)->get_name()); write_element_end(); } const map& namespaces = program->get_namespaces(); map::const_iterator ns_it; for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) { write_element_start("namespace"); write_attribute("name", ns_it->first); write_attribute("value", ns_it->second); generate_annotations(program->get_namespace_annotations(ns_it->first)); write_element_end(); } // TODO: can constants have annotations? vector consts = program->get_consts(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { generate_constant(*c_iter); } vector typedefs = program->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { generate_typedef(*td_iter); } vector enums = program->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } vector objects = program->get_objects(); vector::iterator o_iter; for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { if ((*o_iter)->is_xception()) { generate_xception(*o_iter); } else { generate_struct(*o_iter); } } vector services = program->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { generate_service(*sv_iter); } write_element_end(); if (should_merge_includes_) { programs_.insert(program->get_name()); const vector programs = program->get_includes(); vector::const_iterator prog_it; for (prog_it = programs.begin(); prog_it != programs.end(); ++prog_it) { if (!programs_.count((*prog_it)->get_name())) { iterate_program(*prog_it); } } } } void t_xml_generator::generate_typedef(t_typedef* ttypedef) { write_element_start("typedef"); write_attribute("name", ttypedef->get_name()); write_doc(ttypedef); write_type(ttypedef->get_true_type()); generate_annotations(ttypedef->annotations_); write_element_end(); return; } void t_xml_generator::write_type(t_type* ttype) { const string type = get_type_name(ttype); write_attribute("type", type); if (type == "id") { write_attribute("type-module", ttype->get_program()->get_name()); write_attribute("type-id", ttype->get_name()); } else if (type == "list") { t_type* etype = ((t_list*)ttype)->get_elem_type(); write_element_start("elemType"); write_type(etype); write_element_end(); } else if (type == "set") { t_type* etype = ((t_set*)ttype)->get_elem_type(); write_element_start("elemType"); write_type(etype); write_element_end(); } else if (type == "map") { t_type* ktype = ((t_map*)ttype)->get_key_type(); write_element_start("keyType"); write_type(ktype); write_element_end(); t_type* vtype = ((t_map*)ttype)->get_val_type(); write_element_start("valueType"); write_type(vtype); write_element_end(); } } void t_xml_generator::write_doc(t_doc* tdoc) { if (tdoc->has_doc()) { string doc = tdoc->get_doc(); // for some reason there always seems to be a trailing newline on doc // comments; loop below naively tries to strip off trailing cr/lf int n = 0; for (string::reverse_iterator i = doc.rbegin(); i != doc.rend(); i++,n++) { if (*i != '\n' || *i == '\r') { if (n > 0) { doc.erase(doc.length() - n); } break; } } write_attribute("doc", doc); } } void t_xml_generator::generate_annotations( std::map annotations) { std::map::iterator iter; for (iter = annotations.begin(); iter != annotations.end(); ++iter) { write_element_start("annotation"); write_attribute("key", iter->first); write_attribute("value", iter->second); write_element_end(); } } void t_xml_generator::generate_constant(t_const* con) { write_element_start("const"); write_attribute("name", con->get_name()); write_doc(con); write_type(con->get_type()); write_const_value(con->get_value()); write_element_end(); } void t_xml_generator::write_const_value(t_const_value* value) { switch (value->get_type()) { case t_const_value::CV_IDENTIFIER: case t_const_value::CV_INTEGER: write_element_number("int", value->get_integer()); break; case t_const_value::CV_DOUBLE: write_element_number("double", value->get_double()); break; case t_const_value::CV_STRING: write_element_string("string", value->get_string()); break; case t_const_value::CV_LIST: { write_element_start("list"); std::vector list = value->get_list(); std::vector::iterator lit; for (lit = list.begin(); lit != list.end(); ++lit) { write_element_start("entry"); write_const_value(*lit); write_element_end(); } write_element_end(); break; } case t_const_value::CV_MAP: { write_element_start("map"); std::map map = value->get_map(); std::map::iterator mit; for (mit = map.begin(); mit != map.end(); ++mit) { write_element_start("entry"); write_element_start("key"); write_const_value(mit->first); write_element_end(); write_element_start("value"); write_const_value(mit->second); write_element_end(); write_element_end(); } write_element_end(); break; } default: indent_up(); f_xml_ << indent() << "" << endl; indent_down(); break; } } void t_xml_generator::generate_enum(t_enum* tenum) { write_element_start("enum"); write_attribute("name", tenum->get_name()); write_doc(tenum); vector values = tenum->get_constants(); vector::iterator val_iter; for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) { t_enum_value* val = (*val_iter); write_element_start("member"); write_attribute("name", val->get_name()); write_int_attribute("value", val->get_value()); write_doc(val); generate_annotations(val->annotations_); write_element_end(); } generate_annotations(tenum->annotations_); write_element_end(); } void t_xml_generator::generate_struct(t_struct* tstruct) { string tagname = "struct"; if (tstruct->is_union()) { tagname = "union"; } else if (tstruct->is_xception()) { tagname = "exception"; } write_element_start(tagname); write_attribute("name", tstruct->get_name()); write_doc(tstruct); vector members = tstruct->get_members(); vector::iterator mem_iter; for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) { write_element_start("field"); generate_field(*mem_iter); write_element_end(); } generate_annotations(tstruct->annotations_); write_element_end(); } void t_xml_generator::generate_field(t_field* field) { write_attribute("name", field->get_name()); write_int_attribute("field-id", field->get_key()); write_doc(field); string requiredness; switch (field->get_req()) { case t_field::T_REQUIRED: requiredness = "required"; break; case t_field::T_OPTIONAL: requiredness = "optional"; break; default: requiredness = ""; break; } if (requiredness != "") { write_attribute("required", requiredness); } write_type(field->get_type()); if (field->get_value()) { write_element_start("default"); write_const_value(field->get_value()); write_element_end(); } generate_annotations(field->annotations_); } void t_xml_generator::generate_service(t_service* tservice) { write_element_start("service"); write_attribute("name", tservice->get_name()); if (should_use_namespaces_) { string prog_ns = target_namespace(tservice->get_program()); if (*prog_ns.rbegin() != '/') { prog_ns.push_back('/'); } const string tns = prog_ns + tservice->get_name(); write_attribute("targetNamespace", tns); write_attribute("xmlns:tns", tns); } if (tservice->get_extends()) { const t_service* extends = tservice->get_extends(); write_attribute("parent-module", extends->get_program()->get_name()); write_attribute("parent-id", extends->get_name()); } write_doc(tservice); vector functions = tservice->get_functions(); vector::iterator fn_iter = functions.begin(); for (; fn_iter != functions.end(); fn_iter++) { generate_function(*fn_iter); } generate_annotations(tservice->annotations_); write_element_end(); } void t_xml_generator::generate_function(t_function* tfunc) { write_element_start("method"); write_attribute("name", tfunc->get_name()); if (tfunc->is_oneway()) { write_attribute("oneway", "true"); } write_doc(tfunc); write_element_start("returns"); write_type(tfunc->get_returntype()); write_element_end(); vector members = tfunc->get_arglist()->get_members(); vector::iterator mem_iter = members.begin(); for (; mem_iter != members.end(); mem_iter++) { write_element_start("arg"); generate_field(*mem_iter); write_element_end(); } vector excepts = tfunc->get_xceptions()->get_members(); vector::iterator ex_iter = excepts.begin(); for (; ex_iter != excepts.end(); ex_iter++) { write_element_start("throws"); generate_field(*ex_iter); write_element_end(); } generate_annotations(tfunc->annotations_); write_element_end(); } string t_xml_generator::get_type_name(t_type* ttype) { if (ttype->is_list()) { return "list"; } if (ttype->is_set()) { return "set"; } if (ttype->is_map()) { return "map"; } if ((ttype->is_enum() )|| (ttype->is_struct() )|| (ttype->is_typedef() )|| (ttype->is_xception())){ return "id"; } if (ttype->is_base_type()) { t_base_type* tbasetype = (t_base_type*)ttype; if (tbasetype->is_binary() ) { return "binary"; } return t_base_type::t_base_name(tbasetype->get_base()); } return "(unknown)"; } THRIFT_REGISTER_GENERATOR( xml, "XML", " merge: Generate output with included files merged\n" " no_default_ns: Omit default xmlns and add idl: prefix to all elements\n" " no_namespaces: Do not add namespace definitions to the XML model\n") thrift-0.16.0/compiler/cpp/src/thrift/generate/t_xsd_generator.cc000066400000000000000000000306611420101504100250430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include "thrift/version.h" #include "thrift/platform.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; static const string endl = "\n"; // avoid ostream << std::endl flushes /** * XSD generator, creates an XSD for the base types etc. * */ class t_xsd_generator : public t_generator { public: t_xsd_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option xsd:" + iter->first; } out_dir_base_ = "gen-xsd"; } ~t_xsd_generator() override = default; /** * Init and close methods */ void init_generator() override; void close_generator() override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override { (void)tenum; } void generate_service(t_service* tservice) override; void generate_struct(t_struct* tstruct) override; private: void generate_element(std::ostream& out, std::string name, t_type* ttype, t_struct* attrs = nullptr, bool optional = false, bool nillable = false, bool list_element = false); std::string ns(std::string in, std::string ns) { return ns + ":" + in; } std::string xsd(std::string in) { return ns(in, "xsd"); } std::string type_name(t_type* ttype); std::string base_type_name(t_base_type::t_base tbase); virtual std::string xml_autogen_comment() { return std::string("\n"; } /** * Output xsd/php file */ ofstream_with_content_based_conditional_update f_xsd_; ofstream_with_content_based_conditional_update f_php_; /** * Output string stream */ std::ostringstream s_xsd_types_; }; void t_xsd_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); // Make output file string f_php_name = get_out_dir() + program_->get_name() + "_xsd.php"; f_php_.open(f_php_name.c_str()); f_php_ << "" << endl; f_php_.close(); } void t_xsd_generator::generate_typedef(t_typedef* ttypedef) { indent(s_xsd_types_) << "get_name() << "\">" << endl; indent_up(); if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) { indent(s_xsd_types_) << "get_type()) << "\">" << endl; indent_up(); const vector& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals(); vector::const_iterator v_iter; for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) { indent(s_xsd_types_) << "" << endl; } indent_down(); indent(s_xsd_types_) << "" << endl; } else { indent(s_xsd_types_) << "get_type()) << "\" />" << endl; } indent_down(); indent(s_xsd_types_) << "" << endl << endl; } void t_xsd_generator::generate_struct(t_struct* tstruct) { vector::const_iterator m_iter; const vector& members = tstruct->get_members(); bool xsd_all = tstruct->get_xsd_all(); indent(s_xsd_types_) << "get_name() << "\">" << endl; indent_up(); if (xsd_all) { indent(s_xsd_types_) << "" << endl; } else { indent(s_xsd_types_) << "" << endl; } indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_element(s_xsd_types_, (*m_iter)->get_name(), (*m_iter)->get_type(), (*m_iter)->get_xsd_attrs(), (*m_iter)->get_xsd_optional() || xsd_all, (*m_iter)->get_xsd_nillable()); } indent_down(); if (xsd_all) { indent(s_xsd_types_) << "" << endl; } else { indent(s_xsd_types_) << "" << endl; } indent_down(); indent(s_xsd_types_) << "" << endl << endl; } void t_xsd_generator::generate_element(ostream& out, string name, t_type* ttype, t_struct* attrs, bool optional, bool nillable, bool list_element) { string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : ""; string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : ""; string soptional = sminOccurs + smaxOccurs; string snillable = nillable ? " nillable=\"true\"" : ""; if (ttype->is_void() || ttype->is_list()) { indent(out) << "" << endl; indent_up(); if (attrs == nullptr && ttype->is_void()) { indent(out) << "" << endl; } else { indent(out) << "" << endl; indent_up(); if (ttype->is_list()) { indent(out) << "" << endl; indent_up(); string subname; t_type* subtype = ((t_list*)ttype)->get_elem_type(); if (subtype->is_base_type() || subtype->is_container()) { subname = name + "_elt"; } else { subname = type_name(subtype); } f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << endl; generate_element(out, subname, subtype, nullptr, false, false, true); indent_down(); indent(out) << "" << endl; indent(out) << "" << endl; } if (attrs != nullptr) { const vector& members = attrs->get_members(); vector::const_iterator a_iter; for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) { indent(out) << "get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl; } } indent_down(); indent(out) << "" << endl; } indent_down(); indent(out) << "" << endl; } else { if (attrs == nullptr) { indent(out) << "" << endl; } else { // Wow, all this work for a SIMPLE TYPE with attributes?!?!?! indent(out) << "" << endl; indent_up(); indent(out) << "" << endl; indent_up(); indent(out) << "" << endl; indent_up(); indent(out) << "" << endl; indent_up(); const vector& members = attrs->get_members(); vector::const_iterator a_iter; for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) { indent(out) << "get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl; } indent_down(); indent(out) << "" << endl; indent_down(); indent(out) << "" << endl; indent_down(); indent(out) << "" << endl; indent_down(); indent(out) << "" << endl; } } } void t_xsd_generator::generate_service(t_service* tservice) { // Make output file string f_xsd_name = get_out_dir() + tservice->get_name() + ".xsd"; f_xsd_.open(f_xsd_name.c_str()); string ns = program_->get_namespace("xsd"); const std::map annot = program_->get_namespace_annotations("xsd"); const std::map::const_iterator uri = annot.find("uri"); if (uri != annot.end()) { ns = uri->second; } if (ns.size() > 0) { ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " + "elementFormDefault=\"qualified\""; } // Print the XSD header f_xsd_ << "" << endl << "" << endl << xml_autogen_comment() << endl; // Print out the type definitions indent(f_xsd_) << s_xsd_types_.str(); // Keep a list of all the possible exceptions that might get thrown map all_xceptions; // List the elements that you might actually get vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string elemname = (*f_iter)->get_name() + "_response"; t_type* returntype = (*f_iter)->get_returntype(); generate_element(f_xsd_, elemname, returntype); f_xsd_ << endl; t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type()); } } map::iterator ax_iter; for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) { generate_element(f_xsd_, ax_iter->first, ax_iter->second); } // Close the XSD document f_xsd_ << endl << "" << endl; f_xsd_.close(); } string t_xsd_generator::type_name(t_type* ttype) { if (ttype->is_typedef()) { return ttype->get_name(); } if (ttype->is_base_type()) { return xsd(base_type_name(((t_base_type*)ttype)->get_base())); } if (ttype->is_enum()) { return xsd("int"); } if (ttype->is_struct() || ttype->is_xception()) { return ttype->get_name(); } return "container"; } /** * Returns the XSD type that corresponds to the thrift type. * * @param tbase The base type * @return Explicit XSD type, i.e. xsd:string */ string t_xsd_generator::base_type_name(t_base_type::t_base tbase) { switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: return "string"; case t_base_type::TYPE_BOOL: return "boolean"; case t_base_type::TYPE_I8: return "byte"; case t_base_type::TYPE_I16: return "short"; case t_base_type::TYPE_I32: return "int"; case t_base_type::TYPE_I64: return "long"; case t_base_type::TYPE_DOUBLE: return "decimal"; default: throw "compiler error: no XSD base type name for base type " + t_base_type::t_base_name(tbase); } } THRIFT_REGISTER_GENERATOR(xsd, "XSD", "") thrift-0.16.0/compiler/cpp/src/thrift/globals.h000066400000000000000000000074501420101504100213470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_GLOBALS_H #define T_GLOBALS_H #include #include #include #include #include /** * This module contains all the global variables (slap on the wrist) that are * shared throughout the program. The reason for this is to facilitate simple * interaction between the parser and the rest of the program. Before calling * yyparse(), the main.cc program will make necessary adjustments to these * global variables such that the parser does the right thing and puts entries * into the right containers, etc. * */ /** * Hooray for forward declaration of types! */ class t_program; class t_scope; class t_type; /** * Parsing mode, two passes up in this gin rummy! */ enum PARSE_MODE { INCLUDES = 1, PROGRAM = 2 }; /** * Strictness level */ extern int g_strict; /** * The master program parse tree. This is accessed from within the parser code * to build up the program elements. */ extern t_program* g_program; /** * The scope that we are currently parsing into */ extern t_scope* g_scope; /** * The parent scope to also load symbols into */ extern t_scope* g_parent_scope; /** * The prefix for the parent scope entries */ extern std::string g_parent_prefix; /** * The parsing pass that we are on. We do different things on each pass. */ extern PARSE_MODE g_parse_mode; /** * Global time string, used in formatting error messages etc. */ extern char* g_time_str; /** * The last parsed doctext comment. */ extern char* g_doctext; /** * The location of the last parsed doctext comment. */ extern int g_doctext_lineno; /** * Status of program level doctext candidate */ enum PROGDOCTEXT_STATUS { INVALID = 0, STILL_CANDIDATE = 1, // the text may or may not be the program doctext ALREADY_PROCESSED = 2, // doctext has been used and is no longer available ABSOLUTELY_SURE = 3, // this is the program doctext NO_PROGRAM_DOCTEXT = 4 // there is no program doctext }; /** * The program level doctext. Stored separately to make parsing easier. */ extern char* g_program_doctext_candidate; extern int g_program_doctext_lineno; extern PROGDOCTEXT_STATUS g_program_doctext_status; /** * Whether or not negative field keys are accepted. * * When a field does not have a user-specified key, thrift automatically * assigns a negative value. However, this is fragile since changes to the * file may unintentionally change the key numbering, resulting in a new * protocol that is not backwards compatible. * * When g_allow_neg_field_keys is enabled, users can explicitly specify * negative keys. This way they can write a .thrift file with explicitly * specified keys that is still backwards compatible with older .thrift files * that did not specify key values. */ extern int g_allow_neg_field_keys; /** * Whether or not 64-bit constants will generate a warning. * * Some languages don't support 64-bit constants, but many do, so we can * suppress this warning for projects that don't use any non-64-bit-safe * languages. */ extern int g_allow_64bit_consts; #endif thrift-0.16.0/compiler/cpp/src/thrift/logging.cc000066400000000000000000000034171420101504100215070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "thrift/logging.h" #include "thrift/globals.h" #include #include #include int g_debug = 0; int g_warn = 1; int g_verbose = 0; void pdebug(const char* fmt, ...) { if (g_debug == 0) { return; } va_list args; // printf("[PARSE:%d] ", yylineno); va_start(args, fmt); vprintf(fmt, args); va_end(args); printf("\n"); } void pverbose(const char* fmt, ...) { if (g_verbose == 0) { return; } va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); } void pwarning(int level, const char* fmt, ...) { if (g_warn < level) { return; } va_list args; // printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno); va_start(args, fmt); vprintf(fmt, args); va_end(args); printf("\n"); } void failure(const char* fmt, ...) { va_list args; // fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); printf("\n"); exit(1); } thrift-0.16.0/compiler/cpp/src/thrift/logging.h000066400000000000000000000023071420101504100213460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_LOGGING_H #define T_LOGGING_H extern int g_debug; extern int g_warn; extern int g_verbose; /** * Parse debugging output, used to print helpful info */ void pdebug(const char* fmt, ...); /** * Parser warning */ void pwarning(int level, const char* fmt, ...); /** * Print verbose output message */ void pverbose(const char* fmt, ...); /** * Failure! */ void failure(const char* fmt, ...); #endif thrift-0.16.0/compiler/cpp/src/thrift/main.cc000066400000000000000000001135131420101504100210040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * thrift - a lightweight cross-language rpc/serialization tool * * This file contains the main compiler engine for Thrift, which invokes the * scanner/parser to build the thrift object tree. The interface generation * code for each language lives in a file by the language name under the * generate/ folder, and all parse structures live in parse/ * */ #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include /* for GetFullPathName */ #endif // Careful: must include globals first for extern definitions #include "thrift/common.h" #include "thrift/globals.h" #include "thrift/platform.h" #include "thrift/main.h" #include "thrift/parse/t_program.h" #include "thrift/parse/t_scope.h" #include "thrift/generate/t_generator.h" #include "thrift/audit/t_audit.h" #include "thrift/version.h" using namespace std; /** * Global program tree */ t_program* g_program; /** * Global scope */ t_scope* g_scope; /** * Parent scope to also parse types */ t_scope* g_parent_scope; /** * Prefix for putting types in parent scope */ string g_parent_prefix; /** * Parsing pass */ PARSE_MODE g_parse_mode; /** * Current directory of file being parsed */ string g_curdir; /** * Current file being parsed */ string g_curpath; /** * Search path for inclusions */ vector g_incl_searchpath; /** * Global debug state */ int g_debug = 0; /** * Strictness level */ int g_strict = 127; /** * Warning level */ int g_warn = 1; /** * Verbose output */ int g_verbose = 0; /** * Global time string */ char* g_time_str; /** * The last parsed doctext comment. */ char* g_doctext; /** * The First doctext comment */ char* g_program_doctext_candidate; /** * Whether or not negative field keys are accepted. */ int g_allow_neg_field_keys; /** * Whether or not 64-bit constants will generate a warning. */ int g_allow_64bit_consts = 0; /** * Flags to control code generation */ bool gen_recurse = false; /** * Flags to control thrift audit */ bool g_audit = false; /** * Flag to control return status */ bool g_return_failure = false; bool g_audit_fatal = true; bool g_generator_failure = false; /** * Win32 doesn't have realpath, so use fallback implementation in that case, * otherwise this just calls through to realpath */ char* saferealpath(const char* path, char* resolved_path) { #ifdef _WIN32 char buf[MAX_PATH]; char* basename; DWORD len = GetFullPathNameA(path, MAX_PATH, buf, &basename); if (len == 0 || len > MAX_PATH - 1) { strcpy(resolved_path, path); } else { strcpy(resolved_path, buf); } // Replace backslashes with forward slashes so the // rest of the code behaves correctly. size_t resolved_len = strlen(resolved_path); for (size_t i = 0; i < resolved_len; i++) { if (resolved_path[i] == '\\') { resolved_path[i] = '/'; } } return resolved_path; #else return realpath(path, resolved_path); #endif } bool check_is_directory(const char* dir_name) { #ifdef _WIN32 DWORD attributes = ::GetFileAttributesA(dir_name); if (attributes == INVALID_FILE_ATTRIBUTES) { fprintf(stderr, "Output directory %s is unusable: GetLastError() = %ld\n", dir_name, GetLastError()); return false; } if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) { fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name); return false; } return true; #else struct stat sb; if (stat(dir_name, &sb) < 0) { fprintf(stderr, "Output directory %s is unusable: %s\n", dir_name, strerror(errno)); return false; } if (!S_ISDIR(sb.st_mode)) { fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name); return false; } return true; #endif } /** * Report an error to the user. This is called yyerror for historical * reasons (lex and yacc expect the error reporting routine to be called * this). Call this function to report any errors to the user. * yyerror takes printf style arguments. * * @param fmt C format string followed by additional arguments */ void yyerror(const char* fmt, ...) { va_list args; fprintf(stderr, "[ERROR:%s:%d] (last token was '%s')\n", g_curpath.c_str(), yylineno, yytext); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); } /** * Prints a debug message from the parser. * * @param fmt C format string followed by additional arguments */ void pdebug(const char* fmt, ...) { if (g_debug == 0) { return; } va_list args; printf("[PARSE:%d] ", yylineno); va_start(args, fmt); vprintf(fmt, args); va_end(args); printf("\n"); } /** * Prints a verbose output mode message * * @param fmt C format string followed by additional arguments */ void pverbose(const char* fmt, ...) { if (g_verbose == 0) { return; } va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); } /** * Prints a warning message * * @param fmt C format string followed by additional arguments */ void pwarning(int level, const char* fmt, ...) { if (g_warn < level) { return; } va_list args; printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno); va_start(args, fmt); vprintf(fmt, args); va_end(args); printf("\n"); } /** * Prints a failure message and exits * * @param fmt C format string followed by additional arguments */ void failure(const char* fmt, ...) { va_list args; fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); printf("\n"); exit(1); } /** * Converts a string filename into a thrift program name */ string program_name(string filename) { string::size_type slash = filename.rfind("/"); if (slash != string::npos) { filename = filename.substr(slash + 1); } string::size_type dot = filename.rfind("."); if (dot != string::npos) { filename = filename.substr(0, dot); } return filename; } /** * Gets the directory path of a filename */ string directory_name(string filename) { string::size_type slash = filename.rfind("/"); // No slash, just use the current directory if (slash == string::npos) { return "."; } return filename.substr(0, slash); } /** * Finds the appropriate file path for the given filename */ string include_file(string filename) { // Absolute path? Just try that if (filename[0] == '/') { // Realpath! char rp[THRIFT_PATH_MAX]; // cppcheck-suppress uninitvar if (saferealpath(filename.c_str(), rp) == nullptr) { pwarning(0, "Cannot open include file %s\n", filename.c_str()); return std::string(); } // Stat this file struct stat finfo; if (stat(rp, &finfo) == 0) { return rp; } } else { // relative path, start searching // new search path with current dir global vector sp = g_incl_searchpath; sp.insert(sp.begin(), g_curdir); // iterate through paths vector::iterator it; for (it = sp.begin(); it != sp.end(); it++) { string sfilename = *(it) + "/" + filename; // Realpath! char rp[THRIFT_PATH_MAX]; // cppcheck-suppress uninitvar if (saferealpath(sfilename.c_str(), rp) == nullptr) { continue; } // Stat this files struct stat finfo; if (stat(rp, &finfo) == 0) { return rp; } } } // Uh oh pwarning(0, "Could not find include file %s\n", filename.c_str()); return std::string(); } /** * Clears any previously stored doctext string. * Also prints a warning if we are discarding information. */ void clear_doctext() { if (g_doctext != nullptr) { pwarning(2, "Uncaptured doctext at on line %d.", g_doctext_lineno); } free(g_doctext); g_doctext = nullptr; } /** * Reset program doctext information after processing a file */ void reset_program_doctext_info() { if (g_program_doctext_candidate != nullptr) { free(g_program_doctext_candidate); g_program_doctext_candidate = nullptr; } g_program_doctext_lineno = 0; g_program_doctext_status = INVALID; pdebug("%s", "program doctext set to INVALID"); } /** * We are sure the program doctext candidate is really the program doctext. */ void declare_valid_program_doctext() { if ((g_program_doctext_candidate != nullptr) && (g_program_doctext_status == STILL_CANDIDATE)) { g_program_doctext_status = ABSOLUTELY_SURE; pdebug("%s", "program doctext set to ABSOLUTELY_SURE"); } else { g_program_doctext_status = NO_PROGRAM_DOCTEXT; pdebug("%s", "program doctext set to NO_PROGRAM_DOCTEXT"); } } /** * Cleans up text commonly found in doxygen-like comments * * Warning: if you mix tabs and spaces in a non-uniform way, * you will get what you deserve. */ char* clean_up_doctext(char* doctext) { // Convert to C++ string, and remove Windows's carriage returns. string docstring = doctext; docstring.erase(remove(docstring.begin(), docstring.end(), '\r'), docstring.end()); // Separate into lines. vector lines; string::size_type pos = string::npos; string::size_type last; while (true) { last = (pos == string::npos) ? 0 : pos + 1; pos = docstring.find('\n', last); if (pos == string::npos) { // First bit of cleaning. If the last line is only whitespace, drop it. string::size_type nonwhite = docstring.find_first_not_of(" \t", last); if (nonwhite != string::npos) { lines.push_back(docstring.substr(last)); } break; } lines.push_back(docstring.substr(last, pos - last)); } // A very profound docstring. if (lines.empty()) { return nullptr; } // Clear leading whitespace from the first line. pos = lines.front().find_first_not_of(" \t"); lines.front().erase(0, pos); // If every nonblank line after the first has the same number of spaces/tabs, // then a star, remove them. bool have_prefix = true; bool found_prefix = false; string::size_type prefix_len = 0; vector::iterator l_iter; for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { if (l_iter->empty()) { continue; } pos = l_iter->find_first_not_of(" \t"); if (!found_prefix) { if (pos != string::npos) { if (l_iter->at(pos) == '*') { found_prefix = true; prefix_len = pos; } else { have_prefix = false; break; } } else { // Whitespace-only line. Truncate it. l_iter->clear(); } } else if (l_iter->size() > pos && l_iter->at(pos) == '*' && pos == prefix_len) { // Business as usual. } else if (pos == string::npos) { // Whitespace-only line. Let's truncate it for them. l_iter->clear(); } else { // The pattern has been broken. have_prefix = false; break; } } // If our prefix survived, delete it from every line. if (have_prefix) { // Get the star too. prefix_len++; for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { l_iter->erase(0, prefix_len); } } // Now delete the minimum amount of leading whitespace from each line. prefix_len = string::npos; for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { if (l_iter->empty()) { continue; } pos = l_iter->find_first_not_of(" \t"); if (pos != string::npos && (prefix_len == string::npos || pos < prefix_len)) { prefix_len = pos; } } // If our prefix survived, delete it from every line. if (prefix_len != string::npos) { for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) { l_iter->erase(0, prefix_len); } } // Remove trailing whitespace from every line. for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) { pos = l_iter->find_last_not_of(" \t"); if (pos != string::npos && pos != l_iter->length() - 1) { l_iter->erase(pos + 1); } } // If the first line is empty, remove it. // Don't do this earlier because a lot of steps skip the first line. if (lines.front().empty()) { lines.erase(lines.begin()); } // Now rejoin the lines and copy them back into doctext. docstring.clear(); for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) { docstring += *l_iter; docstring += '\n'; } // assert(docstring.length() <= strlen(doctext)); may happen, see THRIFT-1755 if (docstring.length() <= strlen(doctext)) { strcpy(doctext, docstring.c_str()); } else { free(doctext); // too short doctext = strdup(docstring.c_str()); } return doctext; } /** Set to true to debug docstring parsing */ static bool dump_docs = false; /** * Dumps docstrings to stdout * Only works for top-level definitions and the whole program doc * (i.e., not enum constants, struct fields, or functions. */ void dump_docstrings(t_program* program) { string progdoc = program->get_doc(); if (!progdoc.empty()) { printf("Whole program doc:\n%s\n", progdoc.c_str()); } const vector& typedefs = program->get_typedefs(); vector::const_iterator t_iter; for (t_iter = typedefs.begin(); t_iter != typedefs.end(); ++t_iter) { t_typedef* td = *t_iter; if (td->has_doc()) { printf("typedef %s:\n%s\n", td->get_name().c_str(), td->get_doc().c_str()); } } const vector& enums = program->get_enums(); vector::const_iterator e_iter; for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) { t_enum* en = *e_iter; if (en->has_doc()) { printf("enum %s:\n%s\n", en->get_name().c_str(), en->get_doc().c_str()); } } const vector& consts = program->get_consts(); vector::const_iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { t_const* co = *c_iter; if (co->has_doc()) { printf("const %s:\n%s\n", co->get_name().c_str(), co->get_doc().c_str()); } } const vector& structs = program->get_structs(); vector::const_iterator s_iter; for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) { t_struct* st = *s_iter; if (st->has_doc()) { printf("struct %s:\n%s\n", st->get_name().c_str(), st->get_doc().c_str()); } } const vector& xceptions = program->get_xceptions(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { t_struct* xn = *x_iter; if (xn->has_doc()) { printf("xception %s:\n%s\n", xn->get_name().c_str(), xn->get_doc().c_str()); } } const vector& services = program->get_services(); vector::const_iterator v_iter; for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) { t_service* sv = *v_iter; if (sv->has_doc()) { printf("service %s:\n%s\n", sv->get_name().c_str(), sv->get_doc().c_str()); } } } /** * Emits a warning on list, binary type is typically a much better choice. */ void check_for_list_of_bytes(t_type* list_elem_type) { if ((g_parse_mode == PROGRAM) && (list_elem_type != nullptr) && list_elem_type->is_base_type()) { t_base_type* tbase = (t_base_type*)list_elem_type; if (tbase->get_base() == t_base_type::TYPE_I8) { pwarning(1, "Consider using the more efficient \"binary\" type instead of \"list\"."); } } } static bool g_byte_warning_emitted = false; /** * Emits a one-time warning on byte type, promoting the new i8 type instead */ void emit_byte_type_warning() { if (!g_byte_warning_emitted) { pwarning(1, "The \"byte\" type is a compatibility alias for \"i8\". Use \"i8\" to emphasize the " "signedness of this type.\n"); g_byte_warning_emitted = true; } } /** * Prints deprecation notice for old NS declarations that are no longer supported * If new_form is nullptr, old_form is assumed to be a language identifier, such as "cpp" * If new_form is not nullptr, both arguments are used exactly as given */ void error_unsupported_namespace_decl(const char* old_form, const char* new_form) { const char* remainder = ""; if( new_form == nullptr) { new_form = old_form; remainder = "_namespace"; } failure("Unsupported declaration '%s%s'. Use 'namespace %s' instead.", old_form, remainder, new_form); } /** * Prints the version number */ void version() { printf("Thrift version %s\n", THRIFT_VERSION); } /** * Display the usage message and then exit with an error code. */ void usage() { fprintf(stderr, "Usage: thrift [options] file\n\n"); fprintf(stderr, "Use thrift -help for a list of options\n"); exit(1); } /** * Diplays the help message and then exits with an error code. */ void help() { fprintf(stderr, "Usage: thrift [options] file\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -version Print the compiler version\n"); fprintf(stderr, " -o dir Set the output directory for gen-* packages\n"); fprintf(stderr, " (default: current directory)\n"); fprintf(stderr, " -out dir Set the ouput location for generated files.\n"); fprintf(stderr, " (no gen-* folder will be created)\n"); fprintf(stderr, " -I dir Add a directory to the list of directories\n"); fprintf(stderr, " searched for include directives\n"); fprintf(stderr, " -nowarn Suppress all compiler warnings (BAD!)\n"); fprintf(stderr, " -strict Strict compiler warnings on\n"); fprintf(stderr, " -v[erbose] Verbose mode\n"); fprintf(stderr, " -r[ecurse] Also generate included files\n"); fprintf(stderr, " -debug Parse debug trace to stdout\n"); fprintf(stderr, " --allow-neg-keys Allow negative field keys (Used to " "preserve protocol\n"); fprintf(stderr, " compatibility with older .thrift files)\n"); fprintf(stderr, " --allow-64bit-consts Do not print warnings about using 64-bit constants\n"); fprintf(stderr, " --gen STR Generate code with a dynamically-registered generator.\n"); fprintf(stderr, " STR has the form language[:key1=val1[,key2[,key3=val3]]].\n"); fprintf(stderr, " Keys and values are options passed to the generator.\n"); fprintf(stderr, " Many options will not require values.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Options related to audit operation\n"); fprintf(stderr, " --audit OldFile Old Thrift file to be audited with 'file'\n"); fprintf(stderr, " -Iold dir Add a directory to the list of directories\n"); fprintf(stderr, " searched for include directives for old thrift file\n"); fprintf(stderr, " -Inew dir Add a directory to the list of directories\n"); fprintf(stderr, " searched for include directives for new thrift file\n"); fprintf(stderr, "\n"); fprintf(stderr, "Available generators (and options):\n"); t_generator_registry::gen_map_t gen_map = t_generator_registry::get_generator_map(); t_generator_registry::gen_map_t::iterator iter; for (iter = gen_map.begin(); iter != gen_map.end(); ++iter) { fprintf(stderr, " %s (%s):\n", iter->second->get_short_name().c_str(), iter->second->get_long_name().c_str()); fprintf(stderr, "%s", iter->second->get_documentation().c_str()); } exit(1); } /** * You know, when I started working on Thrift I really thought it wasn't going * to become a programming language because it was just a generator and it * wouldn't need runtime type information and all that jazz. But then we * decided to add constants, and all of a sudden that means runtime type * validation and inference, except the "runtime" is the code generator * runtime. */ void validate_const_rec(std::string name, t_type* type, t_const_value* value) { if (type->is_void()) { throw "type error: cannot declare a void const: " + name; } if (type->is_base_type()) { t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); switch (tbase) { case t_base_type::TYPE_STRING: if (value->get_type() != t_const_value::CV_STRING) { throw "type error: const \"" + name + "\" was declared as string"; } break; case t_base_type::TYPE_BOOL: if (value->get_type() != t_const_value::CV_INTEGER) { throw "type error: const \"" + name + "\" was declared as bool"; } break; case t_base_type::TYPE_I8: if (value->get_type() != t_const_value::CV_INTEGER) { throw "type error: const \"" + name + "\" was declared as byte"; } break; case t_base_type::TYPE_I16: if (value->get_type() != t_const_value::CV_INTEGER) { throw "type error: const \"" + name + "\" was declared as i16"; } break; case t_base_type::TYPE_I32: if (value->get_type() != t_const_value::CV_INTEGER) { throw "type error: const \"" + name + "\" was declared as i32"; } break; case t_base_type::TYPE_I64: if (value->get_type() != t_const_value::CV_INTEGER) { throw "type error: const \"" + name + "\" was declared as i64"; } break; case t_base_type::TYPE_DOUBLE: if (value->get_type() != t_const_value::CV_INTEGER && value->get_type() != t_const_value::CV_DOUBLE) { throw "type error: const \"" + name + "\" was declared as double"; } break; default: throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase) + name; } } else if (type->is_enum()) { if (value->get_type() != t_const_value::CV_IDENTIFIER) { throw "type error: const \"" + name + "\" was declared as enum"; } // see if there's a dot in the identifier std::string name_portion = value->get_identifier_name(); const vector& enum_values = ((t_enum*)type)->get_constants(); vector::const_iterator c_iter; bool found = false; for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { if ((*c_iter)->get_name() == name_portion) { found = true; break; } } if (!found) { throw "type error: const " + name + " was declared as type " + type->get_name() + " which is an enum, but " + value->get_identifier() + " is not a valid value for that enum"; } } else if (type->is_struct() || type->is_xception()) { if (value->get_type() != t_const_value::CV_MAP) { throw "type error: const \"" + name + "\" was declared as struct/xception"; } const vector& fields = ((t_struct*)type)->get_members(); vector::const_iterator f_iter; const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { if (v_iter->first->get_type() != t_const_value::CV_STRING) { throw "type error: " + name + " struct key must be string"; } t_type* field_type = nullptr; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if ((*f_iter)->get_name() == v_iter->first->get_string()) { field_type = (*f_iter)->get_type(); } } if (field_type == nullptr) { throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); } validate_const_rec(name + "." + v_iter->first->get_string(), field_type, v_iter->second); } } else if (type->is_map()) { t_type* k_type = ((t_map*)type)->get_key_type(); t_type* v_type = ((t_map*)type)->get_val_type(); const map& val = value->get_map(); map::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { validate_const_rec(name + "", k_type, v_iter->first); validate_const_rec(name + "", v_type, v_iter->second); } } else if (type->is_list() || type->is_set()) { t_type* e_type; if (type->is_list()) { e_type = ((t_list*)type)->get_elem_type(); } else { e_type = ((t_set*)type)->get_elem_type(); } const vector& val = value->get_list(); vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { validate_const_rec(name + "", e_type, *v_iter); } } } /** * Check simple identifier names * It's easier to do it this way instead of rewriting the whole grammar etc. */ void validate_simple_identifier(const char* identifier) { string name(identifier); if (name.find(".") != string::npos) { yyerror("Identifier %s can't have a dot.", identifier); exit(1); } } /** * Check the type of the parsed const information against its declared type */ void validate_const_type(t_const* c) { validate_const_rec(c->get_name(), c->get_type(), c->get_value()); } /** * Check the type of a default value assigned to a field. */ void validate_field_value(t_field* field, t_const_value* cv) { validate_const_rec(field->get_name(), field->get_type(), cv); } /** * Check that all the elements of a throws block are actually exceptions. */ bool validate_throws(t_struct* throws) { const vector& members = throws->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { if (!t_generator::get_true_type((*m_iter)->get_type())->is_xception()) { return false; } } return true; } /** * Skips UTF-8 BOM if there is one */ bool skip_utf8_bom(FILE* f) { // pretty straightforward, but works if (fgetc(f) == 0xEF) { if (fgetc(f) == 0xBB) { if (fgetc(f) == 0xBF) { return true; } } } rewind(f); return false; } /** * Parses a program */ void parse(t_program* program, t_program* parent_program) { // Get scope file path string path = program->get_path(); // Set current dir global, which is used in the include_file function g_curdir = directory_name(path); g_curpath = path; // Open the file // skip UTF-8 BOM if there is one yyin = fopen(path.c_str(), "r"); if (yyin == 0) { failure("Could not open input file: \"%s\"", path.c_str()); } if (skip_utf8_bom(yyin)) pverbose("Skipped UTF-8 BOM at %s\n", path.c_str()); // Create new scope and scan for includes pverbose("Scanning %s for includes\n", path.c_str()); g_parse_mode = INCLUDES; g_program = program; g_scope = program->scope(); try { yylineno = 1; if (yyparse() != 0) { failure("Parser error during include pass."); } } catch (string &x) { failure(x.c_str()); } fclose(yyin); // Recursively parse all the include programs vector& includes = program->get_includes(); vector::iterator iter; for (iter = includes.begin(); iter != includes.end(); ++iter) { parse(*iter, program); } // reset program doctext status before parsing a new file reset_program_doctext_info(); // Parse the program file g_parse_mode = PROGRAM; g_program = program; g_scope = program->scope(); g_parent_scope = (parent_program != nullptr) ? parent_program->scope() : nullptr; g_parent_prefix = program->get_name() + "."; g_curpath = path; // Open the file // skip UTF-8 BOM if there is one yyin = fopen(path.c_str(), "r"); if (yyin == 0) { failure("Could not open input file: \"%s\"", path.c_str()); } if (skip_utf8_bom(yyin)) pverbose("Skipped UTF-8 BOM at %s\n", path.c_str()); pverbose("Parsing %s for types\n", path.c_str()); yylineno = 1; try { if (yyparse() != 0) { failure("Parser error during types pass."); } } catch (string &x) { failure(x.c_str()); } fclose(yyin); } /** * Generate code */ void generate(t_program* program, const vector& generator_strings) { // Oooohh, recursive code generation, hot!! if (gen_recurse) { program->set_recursive(true); const vector& includes = program->get_includes(); for (auto include : includes) { // Propagate output path from parent to child programs include->set_out_path(program->get_out_path(), program->is_out_path_absolute()); generate(include, generator_strings); } } // Generate code! try { pverbose("Program: %s\n", program->get_path().c_str()); if (dump_docs) { dump_docstrings(program); } vector::const_iterator iter; for (iter = generator_strings.begin(); iter != generator_strings.end(); ++iter) { t_generator* generator = t_generator_registry::get_generator(program, *iter); if (generator == nullptr) { pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str()); g_generator_failure = true; } else if (generator) { generator->validate_input(); pverbose("Generating \"%s\"\n", iter->c_str()); generator->generate_program(); delete generator; } } } catch (string &s) { failure("Error: %s\n", s.c_str()); } catch (const char* exc) { failure("Error: %s\n", exc); } catch (const std::invalid_argument& invalid_argument_exception) { failure("Error: %s\n", invalid_argument_exception.what()); } } void audit(t_program* new_program, t_program* old_program, string new_thrift_include_path, string old_thrift_include_path) { vector temp_incl_searchpath = g_incl_searchpath; if (!old_thrift_include_path.empty()) { g_incl_searchpath.push_back(old_thrift_include_path); } parse(old_program, nullptr); g_incl_searchpath = temp_incl_searchpath; if (!new_thrift_include_path.empty()) { g_incl_searchpath.push_back(new_thrift_include_path); } parse(new_program, nullptr); compare_namespace(new_program, old_program); compare_services(new_program->get_services(), old_program->get_services()); compare_enums(new_program->get_enums(), old_program->get_enums()); compare_structs(new_program->get_structs(), old_program->get_structs()); compare_structs(new_program->get_xceptions(), old_program->get_xceptions()); compare_consts(new_program->get_consts(), old_program->get_consts()); } /** * Parse it up.. then spit it back out, in pretty much every language. Alright * not that many languages, but the cool ones that we care about. */ int main(int argc, char** argv) { int i; std::string out_path; bool out_path_is_absolute = false; // Setup time string time_t now = time(nullptr); g_time_str = ctime(&now); // Check for necessary arguments, you gotta have at least a filename and // an output language flag if (argc < 2) { usage(); } vector generator_strings; string old_thrift_include_path; string new_thrift_include_path; string old_input_file; // Set the current path to a dummy value to make warning messages clearer. g_curpath = "arguments"; // Hacky parameter handling... I didn't feel like using a library sorry! for (i = 1; i < argc - 1; i++) { char* arg; arg = strtok(argv[i], " "); while (arg != nullptr) { // Treat double dashes as single dashes if (arg[0] == '-' && arg[1] == '-') { ++arg; } if (strcmp(arg, "-help") == 0) { help(); } else if (strcmp(arg, "-version") == 0) { version(); exit(0); } else if (strcmp(arg, "-debug") == 0) { g_debug = 1; } else if (strcmp(arg, "-nowarn") == 0) { g_warn = 0; } else if (strcmp(arg, "-strict") == 0) { g_strict = 255; g_warn = 2; } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "-verbose") == 0) { g_verbose = 1; } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-recurse") == 0) { gen_recurse = true; } else if (strcmp(arg, "-allow-neg-keys") == 0) { g_allow_neg_field_keys = true; } else if (strcmp(arg, "-allow-64bit-consts") == 0) { g_allow_64bit_consts = true; } else if (strcmp(arg, "-gen") == 0) { arg = argv[++i]; if (arg == nullptr) { fprintf(stderr, "Missing generator specification\n"); usage(); } generator_strings.emplace_back(arg); } else if (strcmp(arg, "-I") == 0) { // An argument of "-I\ asdf" is invalid and has unknown results arg = argv[++i]; if (arg == nullptr) { fprintf(stderr, "Missing Include directory\n"); usage(); } g_incl_searchpath.emplace_back(arg); } else if ((strcmp(arg, "-o") == 0) || (strcmp(arg, "-out") == 0)) { out_path_is_absolute = (strcmp(arg, "-out") == 0) ? true : false; arg = argv[++i]; if (arg == nullptr) { fprintf(stderr, "-o: missing output directory\n"); usage(); } out_path = arg; #ifdef _WIN32 // strip out trailing \ on Windows std::string::size_type last = out_path.length() - 1; if (out_path[last] == '\\') { out_path.erase(last); } #endif if (!check_is_directory(out_path.c_str())) return -1; } else if (strcmp(arg, "-audit") == 0) { g_audit = true; arg = argv[++i]; if (arg == nullptr) { fprintf(stderr, "Missing old thrift file name for audit operation\n"); usage(); } char old_thrift_file_rp[THRIFT_PATH_MAX]; // cppcheck-suppress uninitvar if (saferealpath(arg, old_thrift_file_rp) == nullptr) { failure("Could not open input file with realpath: %s", arg); } old_input_file = string(old_thrift_file_rp); } else if (strcmp(arg, "-audit-nofatal") == 0) { g_audit_fatal = false; } else if (strcmp(arg, "-Iold") == 0) { arg = argv[++i]; if (arg == nullptr) { fprintf(stderr, "Missing Include directory for old thrift file\n"); usage(); } old_thrift_include_path = string(arg); } else if (strcmp(arg, "-Inew") == 0) { arg = argv[++i]; if (arg == nullptr) { fprintf(stderr, "Missing Include directory for new thrift file\n"); usage(); } new_thrift_include_path = string(arg); } else { fprintf(stderr, "Unrecognized option: %s\n", arg); usage(); } // Tokenize more arg = strtok(nullptr, " "); } } // display help if ((strcmp(argv[argc - 1], "-help") == 0) || (strcmp(argv[argc - 1], "--help") == 0)) { help(); } // if you're asking for version, you have a right not to pass a file if ((strcmp(argv[argc - 1], "-version") == 0) || (strcmp(argv[argc - 1], "--version") == 0)) { version(); exit(0); } // Initialize global types initGlobals(); if (g_audit) { // Audit operation if (old_input_file.empty()) { fprintf(stderr, "Missing file name of old thrift file for audit\n"); usage(); } char new_thrift_file_rp[THRIFT_PATH_MAX]; if (argv[i] == nullptr) { fprintf(stderr, "Missing file name of new thrift file for audit\n"); usage(); } // cppcheck-suppress uninitvar if (saferealpath(argv[i], new_thrift_file_rp) == nullptr) { failure("Could not open input file with realpath: %s", argv[i]); } string new_input_file(new_thrift_file_rp); t_program new_program(new_input_file); t_program old_program(old_input_file); audit(&new_program, &old_program, new_thrift_include_path, old_thrift_include_path); } else { // Generate options // You gotta generate something! if (generator_strings.empty()) { fprintf(stderr, "No output language(s) specified\n"); usage(); } // Real-pathify it char rp[THRIFT_PATH_MAX]; if (argv[i] == nullptr) { fprintf(stderr, "Missing file name\n"); usage(); } // cppcheck-suppress uninitvar if (saferealpath(argv[i], rp) == nullptr) { failure("Could not open input file with realpath: %s", argv[i]); } string input_file(rp); // Instance of the global parse tree t_program* program = new t_program(input_file); if (out_path.size()) { program->set_out_path(out_path, out_path_is_absolute); } // Compute the cpp include prefix. // infer this from the filename passed in string input_filename = argv[i]; string include_prefix; string::size_type last_slash = string::npos; if ((last_slash = input_filename.rfind("/")) != string::npos) { include_prefix = input_filename.substr(0, last_slash); } program->set_include_prefix(include_prefix); // Parse it! parse(program, nullptr); // The current path is not really relevant when we are doing generation. // Reset the variable to make warning messages clearer. g_curpath = "generation"; // Reset yylineno for the heck of it. Use 1 instead of 0 because // That is what shows up during argument parsing. yylineno = 1; // Generate it! generate(program, generator_strings); delete program; } // Clean up. Who am I kidding... this program probably orphans heap memory // all over the place, but who cares because it is about to exit and it is // all referenced and used by this wacky parse tree up until now anyways. clearGlobals(); // Finished if (g_return_failure && g_audit_fatal) { exit(2); } if (g_generator_failure) { exit(3); } // Finished return 0; } thrift-0.16.0/compiler/cpp/src/thrift/main.h000066400000000000000000000054221420101504100206450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_MAIN_H #define T_MAIN_H #include #include #include "thrift/logging.h" #include "thrift/parse/t_const.h" #include "thrift/parse/t_field.h" /** * Defined in the flex library */ extern "C" { int yylex(void); } int yyparse(void); /** * Expected to be defined by Flex/Bison */ void yyerror(const char* fmt, ...); /** * Check simple identifier names */ void validate_simple_identifier(const char* identifier); /** * Check constant types */ void validate_const_type(t_const* c); /** * Check constant types */ void validate_field_value(t_field* field, t_const_value* cv); /** * Check members of a throws block */ bool validate_throws(t_struct* throws); /** * Converts a string filename into a thrift program name */ std::string program_name(std::string filename); /** * Gets the directory path of a filename */ std::string directory_name(std::string filename); /** * Get the absolute path for an include file */ std::string include_file(std::string filename); /** * Clears any previously stored doctext string. */ void clear_doctext(); /** * Cleans up text commonly found in doxygen-like comments */ char* clean_up_doctext(char* doctext); /** * We are sure the program doctext candidate is really the program doctext. */ void declare_valid_program_doctext(); /** * Emits a warning on list, binary type is typically a much better choice. */ void check_for_list_of_bytes(t_type* list_elem_type); /** * Emits a one-time warning on byte type, promoting the new i8 type instead */ void emit_byte_type_warning(); /** * Prints deprecation notice for old NS declarations that are no longer supported * If new_form is nullptr, old_form is assumed to be a language identifier, such as "cpp" * If new_form is not nullptr, both arguments are used exactly as given */ void error_unsupported_namespace_decl(const char* old_form, const char* new_form = nullptr); /** * Flex utilities */ extern int yylineno; extern char yytext[]; extern std::FILE* yyin; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/000077500000000000000000000000001420101504100206575ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/src/thrift/parse/parse.cc000066400000000000000000000022441420101504100223020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "thrift/parse/t_type.h" #include "thrift/parse/t_typedef.h" #include "thrift/main.h" t_type* t_type::get_true_type() { return const_cast(const_cast(this)->get_true_type()); } const t_type* t_type::get_true_type() const { const t_type* type = this; while (type->is_typedef()) { type = ((t_typedef*)type)->get_type(); } return type; } thrift-0.16.0/compiler/cpp/src/thrift/parse/t_base_type.h000066400000000000000000000056331420101504100233350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_BASE_TYPE_H #define T_BASE_TYPE_H #include #include "thrift/parse/t_type.h" /** * A thrift base type, which must be one of the defined enumerated types inside * this definition. * */ class t_base_type : public t_type { public: /** * Enumeration of thrift base types */ enum t_base { TYPE_VOID, TYPE_STRING, TYPE_BOOL, TYPE_I8, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_DOUBLE }; t_base_type(std::string name, t_base base) : t_type(name), base_(base), string_list_(false), binary_(false), string_enum_(false) {} t_base get_base() const { return base_; } bool is_void() const override { return base_ == TYPE_VOID; } bool is_string() const override { return base_ == TYPE_STRING; } bool is_bool() const override { return base_ == TYPE_BOOL; } void set_string_list(bool val) { string_list_ = val; } bool is_string_list() const { return string_list_ && (base_ == TYPE_STRING); } void set_binary(bool val) { binary_ = val; } bool is_binary() const override { return binary_ && (base_ == TYPE_STRING); } void set_string_enum(bool val) { string_enum_ = val; } bool is_string_enum() const { return string_enum_ && base_ == TYPE_STRING; } void add_string_enum_val(std::string val) { string_enum_vals_.push_back(val); } const std::vector& get_string_enum_vals() const { return string_enum_vals_; } bool is_base_type() const override { return true; } static std::string t_base_name(t_base tbase) { switch (tbase) { case TYPE_VOID: return "void"; break; case TYPE_STRING: return "string"; break; case TYPE_BOOL: return "bool"; break; case TYPE_I8: return "i8"; break; case TYPE_I16: return "i16"; break; case TYPE_I32: return "i32"; break; case TYPE_I64: return "i64"; break; case TYPE_DOUBLE: return "double"; break; default: return "(unknown)"; break; } } private: t_base base_; bool string_list_; bool binary_; bool string_enum_; std::vector string_enum_vals_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_const.h000066400000000000000000000030351420101504100225020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_CONST_H #define T_CONST_H #include "thrift/parse/t_type.h" #include "thrift/parse/t_const_value.h" /** * A const is a constant value defined across languages that has a type and * a value. The trick here is that the declared type might not match the type * of the value object, since that is not determined until after parsing the * whole thing out. * */ class t_const : public t_doc { public: t_const(t_type* type, std::string name, t_const_value* value) : type_(type), name_(name), value_(value) {} t_type* get_type() const { return type_; } std::string get_name() const { return name_; } t_const_value* get_value() const { return value_; } private: t_type* type_; std::string name_; t_const_value* value_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_const_value.h000066400000000000000000000142121420101504100236750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_CONST_VALUE_H #define T_CONST_VALUE_H #include "thrift/parse/t_enum.h" #include #include #include #include /** * A const value is something parsed that could be a map, set, list, struct * or whatever. * */ class t_const_value { public: /** * Comparator to sort fields in ascending order by key. * Make this a functor instead of a function to help GCC inline it. */ struct value_compare { public: bool operator()(t_const_value const* const& left, t_const_value const* const& right) const { return *left < *right; } }; enum t_const_value_type { CV_INTEGER, CV_DOUBLE, CV_STRING, CV_MAP, CV_LIST, CV_IDENTIFIER, CV_UNKNOWN }; t_const_value() : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)nullptr), valType_(CV_UNKNOWN) {} t_const_value(int64_t val) : doubleVal_(0.0f), enum_((t_enum*)nullptr), valType_(CV_UNKNOWN) { set_integer(val); } t_const_value(std::string val) : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)nullptr), valType_(CV_UNKNOWN) { set_string(val); } void set_string(std::string val) { valType_ = CV_STRING; stringVal_ = val; } std::string get_string() const { return stringVal_; } void set_integer(int64_t val) { valType_ = CV_INTEGER; intVal_ = val; } int64_t get_integer() const { if (valType_ == CV_IDENTIFIER) { if (enum_ == nullptr) { throw "have identifier \"" + get_identifier() + "\", but unset enum on line!"; } std::string identifier = get_identifier(); std::string::size_type dot = identifier.rfind('.'); if (dot != std::string::npos) { identifier = identifier.substr(dot + 1); } t_enum_value* val = enum_->get_constant_by_name(identifier); if (val == nullptr) { throw "Unable to find enum value \"" + identifier + "\" in enum \"" + enum_->get_name() + "\""; } return val->get_value(); } else { return intVal_; } } void set_double(double val) { valType_ = CV_DOUBLE; doubleVal_ = val; } double get_double() const { return doubleVal_; } void set_map() { valType_ = CV_MAP; } void add_map(t_const_value* key, t_const_value* val) { mapVal_[key] = val; } const std::map& get_map() const { return mapVal_; } void set_list() { valType_ = CV_LIST; } void add_list(t_const_value* val) { listVal_.push_back(val); } const std::vector& get_list() const { return listVal_; } void set_identifier(std::string val) { valType_ = CV_IDENTIFIER; identifierVal_ = val; } std::string get_identifier() const { return identifierVal_; } std::string get_identifier_name() const { std::string ret = get_identifier(); size_t s = ret.find('.'); if (s == std::string::npos) { throw "error: identifier " + ret + " is unqualified!"; } ret = ret.substr(s + 1); s = ret.find('.'); if (s != std::string::npos) { ret = ret.substr(s + 1); } return ret; } std::string get_identifier_with_parent() const { std::string ret = get_identifier(); size_t s = ret.find('.'); if (s == std::string::npos) { throw "error: identifier " + ret + " is unqualified!"; } size_t s2 = ret.find('.', s + 1); if (s2 != std::string::npos) { ret = ret.substr(s + 1); } return ret; } void set_enum(t_enum* tenum) { enum_ = tenum; } t_const_value_type get_type() const { if (valType_ == CV_UNKNOWN) { throw std::string("unknown t_const_value"); } return valType_; } /** * Comparator to sort map fields in ascending order by key and then value. * This is used for map comparison in lexicographic order. */ struct map_entry_compare { private: typedef std::pair ConstPair; public: bool operator()(ConstPair left, ConstPair right) const { if (*(left.first) < *(right.first)) { return true; } else { if (*(right.first) < *(left.first)) { return false; } else { return *(left.second) < *(right.second); } } } }; bool operator < (const t_const_value& that) const { ::t_const_value::t_const_value_type t1 = get_type(); ::t_const_value::t_const_value_type t2 = that.get_type(); if (t1 != t2) return t1 < t2; switch (t1) { case ::t_const_value::CV_INTEGER: return intVal_ < that.intVal_; case ::t_const_value::CV_DOUBLE: return doubleVal_ < that.doubleVal_; case ::t_const_value::CV_STRING: return stringVal_ < that.stringVal_; case ::t_const_value::CV_IDENTIFIER: return identifierVal_ < that.identifierVal_; case ::t_const_value::CV_MAP: return std::lexicographical_compare( mapVal_.begin(), mapVal_.end(), that.mapVal_.begin(), that.mapVal_.end(), map_entry_compare()); case ::t_const_value::CV_LIST: return std::lexicographical_compare( listVal_.begin(), listVal_.end(), that.listVal_.begin(), that.listVal_.end(), value_compare()); case ::t_const_value::CV_UNKNOWN: default: throw "unknown value type"; } } private: std::map mapVal_; std::vector listVal_; std::string stringVal_; int64_t intVal_; double doubleVal_; std::string identifierVal_; t_enum* enum_; t_const_value_type valType_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_container.h000066400000000000000000000025161420101504100233410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_CONTAINER_H #define T_CONTAINER_H #include "thrift/parse/t_type.h" class t_container : public t_type { public: t_container() : cpp_name_(), has_cpp_name_(false) {} ~t_container() override = default; void set_cpp_name(std::string cpp_name) { cpp_name_ = cpp_name; has_cpp_name_ = true; } bool has_cpp_name() const { return has_cpp_name_; } std::string get_cpp_name() const { return cpp_name_; } bool is_container() const override { return true; } private: std::string cpp_name_; bool has_cpp_name_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_doc.h000066400000000000000000000027151420101504100221250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_DOC_H #define T_DOC_H #include "thrift/globals.h" #include "thrift/logging.h" /** * Documentation stubs * */ class t_doc { public: t_doc() : has_doc_(false) {} virtual ~t_doc() = default; void set_doc(const std::string& doc) { doc_ = doc; has_doc_ = true; if ((g_program_doctext_lineno == g_doctext_lineno) && (g_program_doctext_status == STILL_CANDIDATE)) { g_program_doctext_status = ALREADY_PROCESSED; pdebug("%s", "program doctext set to ALREADY_PROCESSED"); } } const std::string& get_doc() const { return doc_; } bool has_doc() { return has_doc_; } private: std::string doc_; bool has_doc_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_enum.h000066400000000000000000000066661420101504100223350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_ENUM_H #define T_ENUM_H #include #include "thrift/parse/t_enum_value.h" #include "thrift/parse/t_type.h" /** * An enumerated type. A list of constant objects with a name for the type. * */ class t_enum : public t_type { public: t_enum(t_program* program) : t_type(program) {} void set_name(const std::string& name) override { name_ = name; } void append(t_enum_value* constant) { constants_.push_back(constant); } const std::vector& get_constants() const { return constants_; } t_enum_value* get_constant_by_name(const std::string& name) const { const std::vector& enum_values = get_constants(); std::vector::const_iterator c_iter; for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { if ((*c_iter)->get_name() == name) { return *c_iter; } } return nullptr; } t_enum_value* get_constant_by_value(int64_t value) const { const std::vector& enum_values = get_constants(); std::vector::const_iterator c_iter; for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { if ((*c_iter)->get_value() == value) { return *c_iter; } } return nullptr; } t_enum_value* get_min_value() const { const std::vector& enum_values = get_constants(); std::vector::const_iterator c_iter; t_enum_value* min_value; if (enum_values.size() == 0) { min_value = nullptr; } else { int min_value_value; min_value = enum_values.front(); min_value_value = min_value->get_value(); for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { if ((*c_iter)->get_value() < min_value_value) { min_value = (*c_iter); min_value_value = min_value->get_value(); } } } return min_value; } t_enum_value* get_max_value() const { const std::vector& enum_values = get_constants(); std::vector::const_iterator c_iter; t_enum_value* max_value; if (enum_values.size() == 0) { max_value = nullptr; } else { int max_value_value; max_value = enum_values.back(); max_value_value = max_value->get_value(); for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { if ((*c_iter)->get_value() > max_value_value) { max_value = (*c_iter); max_value_value = max_value->get_value(); } } } return max_value; } bool is_enum() const override { return true; } private: std::vector constants_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_enum_value.h000066400000000000000000000026701420101504100235200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_ENUM_VALUE_H #define T_ENUM_VALUE_H #include #include #include "thrift/parse/t_doc.h" /** * A constant. These are used inside of enum definitions. Constants are just * symbol identifiers that may or may not have an explicit value associated * with them. * */ class t_enum_value : public t_doc { public: t_enum_value(std::string name, int value) : name_(name), value_(value) {} ~t_enum_value() override = default; const std::string& get_name() const { return name_; } int get_value() const { return value_; } std::map annotations_; private: std::string name_; int value_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_field.h000066400000000000000000000070701420101504100224420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_FIELD_H #define T_FIELD_H #include #include #include #include "thrift/parse/t_doc.h" #include "thrift/parse/t_type.h" // Forward declare for xsd_attrs class t_struct; /** * Class to represent a field in a thrift structure. A field has a data type, * a symbolic name, and a numeric identifier. * */ class t_field : public t_doc { public: t_field(t_type* type, std::string name) : type_(type), name_(name), key_(0), value_(nullptr), xsd_optional_(false), xsd_nillable_(false), xsd_attrs_(nullptr), reference_(false) {} t_field(t_type* type, std::string name, int32_t key) : type_(type), name_(name), key_(key), req_(T_OPT_IN_REQ_OUT), value_(nullptr), xsd_optional_(false), xsd_nillable_(false), xsd_attrs_(nullptr), reference_(false) {} ~t_field() override = default; t_type* get_type() { return type_; } const t_type* get_type() const { return type_; } const std::string& get_name() const { return name_; } int32_t get_key() const { return key_; } enum e_req { T_REQUIRED, T_OPTIONAL, T_OPT_IN_REQ_OUT }; void set_req(e_req req) { req_ = req; } e_req get_req() const { return req_; } void set_value(t_const_value* value) { value_ = value; } t_const_value* get_value() { return value_; } const t_const_value* get_value() const { return value_; } void set_xsd_optional(bool xsd_optional) { xsd_optional_ = xsd_optional; } bool get_xsd_optional() const { return xsd_optional_; } void set_xsd_nillable(bool xsd_nillable) { xsd_nillable_ = xsd_nillable; } bool get_xsd_nillable() const { return xsd_nillable_; } void set_xsd_attrs(t_struct* xsd_attrs) { xsd_attrs_ = xsd_attrs; } t_struct* get_xsd_attrs() { return xsd_attrs_; } const t_struct* get_xsd_attrs() const { return xsd_attrs_; } /** * Comparator to sort fields in ascending order by key. * Make this a functor instead of a function to help GCC inline it. * The arguments are (const) references to const pointers to const t_fields. */ struct key_compare { bool operator()(t_field const* const& a, t_field const* const& b) { return a->get_key() < b->get_key(); } }; std::map annotations_; bool get_reference() const { return reference_; } void set_reference(bool reference) { reference_ = reference; } private: t_type* type_; std::string name_; int32_t key_; e_req req_; t_const_value* value_; bool xsd_optional_; bool xsd_nillable_; t_struct* xsd_attrs_; bool reference_; }; /** * A simple struct for the parser to use to store a field ID, and whether or * not it was specified by the user or automatically chosen. */ struct t_field_id { int32_t value; bool auto_assigned; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_function.h000066400000000000000000000051751420101504100232100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_FUNCTION_H #define T_FUNCTION_H #include #include "thrift/parse/t_type.h" #include "thrift/parse/t_struct.h" #include "thrift/parse/t_doc.h" /** * Representation of a function. Key parts are return type, function name, * optional modifiers, and an argument list, which is implemented as a thrift * struct. * */ class t_function : public t_doc { public: t_function(t_type* returntype, std::string name, t_struct* arglist, bool oneway = false) : returntype_(returntype), name_(name), arglist_(arglist), xceptions_(new t_struct(nullptr)), own_xceptions_(true), oneway_(oneway) { if (oneway_ && (!returntype_->is_void())) { pwarning(1, "Oneway methods should return void.\n"); } } t_function(t_type* returntype, std::string name, t_struct* arglist, t_struct* xceptions, bool oneway = false) : returntype_(returntype), name_(name), arglist_(arglist), xceptions_(xceptions), own_xceptions_(false), oneway_(oneway) { if (oneway_ && !xceptions_->get_members().empty()) { throw std::string("Oneway methods can't throw exceptions."); } if (oneway_ && (!returntype_->is_void())) { pwarning(1, "Oneway methods should return void.\n"); } } ~t_function() override { if (own_xceptions_) delete xceptions_; } t_type* get_returntype() const { return returntype_; } const std::string& get_name() const { return name_; } t_struct* get_arglist() const { return arglist_; } t_struct* get_xceptions() const { return xceptions_; } bool is_oneway() const { return oneway_; } std::map annotations_; private: t_type* returntype_; std::string name_; t_struct* arglist_; t_struct* xceptions_; bool own_xceptions_; bool oneway_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_list.h000066400000000000000000000022771420101504100223360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_LIST_H #define T_LIST_H #include "thrift/parse/t_container.h" /** * A list is a lightweight container type that just wraps another data type. * */ class t_list : public t_container { public: t_list(t_type* elem_type) : elem_type_(elem_type) {} t_type* get_elem_type() const { return elem_type_; } bool is_list() const override { return true; } private: t_type* elem_type_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_map.h000066400000000000000000000024551420101504100221360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_MAP_H #define T_MAP_H #include "thrift/parse/t_container.h" /** * A map is a lightweight container type that just wraps another two data * types. * */ class t_map : public t_container { public: t_map(t_type* key_type, t_type* val_type) : key_type_(key_type), val_type_(val_type) {} t_type* get_key_type() const { return key_type_; } t_type* get_val_type() const { return val_type_; } bool is_map() const override { return true; } private: t_type* key_type_; t_type* val_type_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_program.h000066400000000000000000000332201420101504100230220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_PROGRAM_H #define T_PROGRAM_H #include #include #include // For program_name() #include "thrift/main.h" #include "thrift/parse/t_doc.h" #include "thrift/parse/t_scope.h" #include "thrift/parse/t_base_type.h" #include "thrift/parse/t_typedef.h" #include "thrift/parse/t_enum.h" #include "thrift/parse/t_const.h" #include "thrift/parse/t_struct.h" #include "thrift/parse/t_service.h" #include "thrift/parse/t_list.h" #include "thrift/parse/t_map.h" #include "thrift/parse/t_set.h" #include "thrift/generate/t_generator_registry.h" //#include "thrift/parse/t_doc.h" /** * Top level class representing an entire thrift program. A program consists * fundamentally of the following: * * Typedefs * Enumerations * Constants * Structs * Exceptions * Services * * The program module also contains the definitions of the base types. * */ class t_program : public t_doc { public: t_program(std::string path, std::string name) : path_(path), name_(name), out_path_("./"), out_path_is_absolute_(false), scope_(new t_scope), recursive_(false) {} t_program(std::string path) : path_(path), out_path_("./"), out_path_is_absolute_(false), recursive_(false) { name_ = program_name(path); scope_ = new t_scope(); } ~t_program() override { if (scope_) { delete scope_; scope_ = nullptr; } } // Path accessor const std::string& get_path() const { return path_; } // Output path accessor const std::string& get_out_path() const { return out_path_; } // Create gen-* dir accessor bool is_out_path_absolute() const { return out_path_is_absolute_; } // Name accessor const std::string& get_name() const { return name_; } // Namespace const std::string& get_namespace() const { return namespace_; } // Include prefix accessor const std::string& get_include_prefix() const { return include_prefix_; } // Accessors for program elements const std::vector& get_typedefs() const { return typedefs_; } const std::vector& get_enums() const { return enums_; } const std::vector& get_consts() const { return consts_; } const std::vector& get_structs() const { return structs_; } const std::vector& get_xceptions() const { return xceptions_; } const std::vector& get_objects() const { return objects_; } const std::vector& get_services() const { return services_; } const std::map& get_namespaces() const { return namespaces_; } // Program elements void add_typedef(t_typedef* td) { typedefs_.push_back(td); } void add_enum(t_enum* te) { enums_.push_back(te); } void add_const(t_const* tc) { consts_.push_back(tc); } void add_struct(t_struct* ts) { objects_.push_back(ts); structs_.push_back(ts); } void add_xception(t_struct* tx) { objects_.push_back(tx); xceptions_.push_back(tx); } void add_service(t_service* ts) { ts->validate_unique_members(); services_.push_back(ts); } // Programs to include std::vector& get_includes() { return includes_; } const std::vector& get_includes() const { return includes_; } void set_out_path(std::string out_path, bool out_path_is_absolute) { out_path_ = out_path; out_path_is_absolute_ = out_path_is_absolute; // Ensure that it ends with a trailing '/' (or '\' for windows machines) char c = out_path_.at(out_path_.size() - 1); if (!(c == '/' || c == '\\')) { out_path_.push_back('/'); } } // Typename collision detection /** * Search for typename collisions * @param t the type to test for collisions * @return true if a certain collision was found, otherwise false */ bool is_unique_typename(const t_type* t) const { int occurrences = program_typename_count(this, t); for (auto it = includes_.cbegin(); it != includes_.cend(); ++it) { occurrences += program_typename_count(*it, t); } return 0 == occurrences; } /** * Search all type collections for duplicate typenames * @param prog the program to search * @param t the type to test for collisions * @return the number of certain typename collisions */ int program_typename_count(const t_program* prog, const t_type* t) const { int occurrences = 0; occurrences += collection_typename_count(prog, prog->typedefs_, t); occurrences += collection_typename_count(prog, prog->enums_, t); occurrences += collection_typename_count(prog, prog->objects_, t); occurrences += collection_typename_count(prog, prog->services_, t); return occurrences; } /** * Search a type collection for duplicate typenames * @param prog the program to search * @param type_collection the type collection to search * @param t the type to test for collisions * @return the number of certain typename collisions */ template int collection_typename_count(const t_program* prog, const T type_collection, const t_type* t) const { int occurrences = 0; for (auto it = type_collection.cbegin(); it != type_collection.cend(); ++it) if (t != *it && 0 == t->get_name().compare((*it)->get_name()) && is_common_namespace(prog, t)) ++occurrences; return occurrences; } /** * Determine whether identical typenames will collide based on namespaces. * * Because we do not know which languages the user will generate code for, * collisions within programs (IDL files) having namespace declarations can be * difficult to determine. Only guaranteed collisions return true (cause an error). * Possible collisions involving explicit namespace declarations produce a warning. * Other possible collisions go unreported. * @param prog the program containing the preexisting typename * @param t the type containing the typename match * @return true if a collision within namespaces is found, otherwise false */ bool is_common_namespace(const t_program* prog, const t_type* t) const { // Case 1: Typenames are in the same program [collision] if (prog == t->get_program()) { pwarning(1, "Duplicate typename %s found in %s", t->get_name().c_str(), t->get_program()->get_name().c_str()); return true; } // Case 2: Both programs have identical namespace scope/name declarations [collision] bool match = true; for (auto it = prog->namespaces_.cbegin(); it != prog->namespaces_.cend(); ++it) { if (0 == it->second.compare(t->get_program()->get_namespace(it->first))) { pwarning(1, "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]", t->get_name().c_str(), t->get_program()->get_name().c_str(), it->first.c_str(), it->second.c_str(), prog->get_name().c_str(), it->first.c_str(), it->second.c_str()); } else { match = false; } } for (auto it = t->get_program()->namespaces_.cbegin(); it != t->get_program()->namespaces_.cend(); ++it) { if (0 == it->second.compare(prog->get_namespace(it->first))) { pwarning(1, "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]", t->get_name().c_str(), t->get_program()->get_name().c_str(), it->first.c_str(), it->second.c_str(), prog->get_name().c_str(), it->first.c_str(), it->second.c_str()); } else { match = false; } } if (0 == prog->namespaces_.size() && 0 == t->get_program()->namespaces_.size()) { pwarning(1, "Duplicate typename %s found in %s and %s", t->get_name().c_str(), t->get_program()->get_name().c_str(), prog->get_name().c_str()); } return match; } // Scoping and namespacing void set_namespace(std::string name) { namespace_ = name; } // Scope accessor t_scope* scope() { return scope_; } const t_scope* scope() const { return scope_; } // Includes void add_include(t_program* program) { includes_.push_back(program); } void add_include(std::string path, std::string include_site) { t_program* program = new t_program(path); // include prefix for this program is the site at which it was included // (minus the filename) std::string include_prefix; std::string::size_type last_slash = std::string::npos; if ((last_slash = include_site.rfind("/")) != std::string::npos) { include_prefix = include_site.substr(0, last_slash); } program->set_include_prefix(include_prefix); includes_.push_back(program); } void set_include_prefix(std::string include_prefix) { include_prefix_ = include_prefix; // this is intended to be a directory; add a trailing slash if necessary std::string::size_type len = include_prefix_.size(); if (len > 0 && include_prefix_[len - 1] != '/') { include_prefix_ += '/'; } } // Language neutral namespace / packaging void set_namespace(std::string language, std::string name_space) { if (language != "*") { size_t sub_index = language.find('.'); std::string base_language = language.substr(0, sub_index); if (base_language == "smalltalk") { pwarning(1, "Namespace 'smalltalk' is deprecated. Use 'st' instead"); base_language = "st"; } t_generator_registry::gen_map_t my_copy = t_generator_registry::get_generator_map(); t_generator_registry::gen_map_t::iterator it; it = my_copy.find(base_language); if (it == my_copy.end()) { std::string warning = "No generator named '" + base_language + "' could be found!"; pwarning(1, warning.c_str()); } else { if (sub_index != std::string::npos) { std::string sub_namespace = language.substr(sub_index + 1); if (!it->second->is_valid_namespace(sub_namespace)) { std::string warning = base_language + " generator does not accept '" + sub_namespace + "' as sub-namespace!"; pwarning(1, warning.c_str()); } } } } namespaces_[language] = name_space; } std::string get_namespace(std::string language) const { std::map::const_iterator iter; if ((iter = namespaces_.find(language)) != namespaces_.end() || (iter = namespaces_.find("*")) != namespaces_.end()) { return iter->second; } return std::string(); } const std::map& get_all_namespaces() const { return namespaces_; } void set_namespace_annotations(std::string language, std::map annotations) { namespace_annotations_[language] = annotations; } const std::map& get_namespace_annotations(const std::string& language) const { auto it = namespace_annotations_.find(language); if (namespace_annotations_.end() != it) { return it->second; } static const std::map emptyMap; return emptyMap; } std::map& get_namespace_annotations(const std::string& language) { return namespace_annotations_[language]; } // Language specific namespace / packaging void add_cpp_include(std::string path) { cpp_includes_.push_back(path); } const std::vector& get_cpp_includes() const { return cpp_includes_; } void add_c_include(std::string path) { c_includes_.push_back(path); } const std::vector& get_c_includes() const { return c_includes_; } void set_recursive(const bool recursive) { recursive_ = recursive; } bool get_recursive() const { return recursive_; } private: // File path std::string path_; // Name std::string name_; // Output directory std::string out_path_; // Output directory is absolute location for generated source (no gen-*) bool out_path_is_absolute_; // Namespace std::string namespace_; // Included programs std::vector includes_; // Include prefix for this program, if any std::string include_prefix_; // Identifier lookup scope t_scope* scope_; // Components to generate code for std::vector typedefs_; std::vector enums_; std::vector consts_; std::vector objects_; std::vector structs_; std::vector xceptions_; std::vector services_; // Dynamic namespaces std::map namespaces_; // Annotations for dynamic namespaces std::map > namespace_annotations_; // C++ extra includes std::vector cpp_includes_; // C extra includes std::vector c_includes_; // Recursive code generation bool recursive_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_scope.h000066400000000000000000000167711420101504100225000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_SCOPE_H #define T_SCOPE_H #include #include #include #include "thrift/parse/t_type.h" #include "thrift/parse/t_service.h" #include "thrift/parse/t_const.h" #include "thrift/parse/t_const_value.h" #include "thrift/parse/t_base_type.h" #include "thrift/parse/t_map.h" #include "thrift/parse/t_list.h" #include "thrift/parse/t_set.h" /** * This represents a variable scope used for looking up predefined types and * services. Typically, a scope is associated with a t_program. Scopes are not * used to determine code generation, but rather to resolve identifiers at * parse time. * */ class t_scope { public: t_scope() = default; void add_type(std::string name, t_type* type) { types_[name] = type; } t_type* get_type(std::string name) { return types_[name]; } const t_type* get_type(std::string name) const { const auto it = types_.find(name); if (types_.end() != it) { return it->second; } return nullptr; } void add_service(std::string name, t_service* service) { services_[name] = service; } t_service* get_service(std::string name) { return services_[name]; } const t_service* get_service(std::string name) const { const auto it = services_.find(name); if (services_.end() != it) { return it->second; } return nullptr; } void add_constant(std::string name, t_const* constant) { if (constants_.find(name) != constants_.end()) { throw "Enum " + name + " is already defined!"; } else { constants_[name] = constant; } } t_const* get_constant(std::string name) { return constants_[name]; } const t_const* get_constant(std::string name) const { const auto it = constants_.find(name); if (constants_.end() != it) { return it->second; } return nullptr; } void print() { std::map::iterator iter; for (iter = types_.begin(); iter != types_.end(); ++iter) { printf("%s => %s\n", iter->first.c_str(), iter->second->get_name().c_str()); } } void resolve_const_value(t_const_value* const_val, t_type* ttype) { if (ttype->is_map()) { const std::map& map = const_val->get_map(); std::map::const_iterator v_iter; for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) { resolve_const_value(v_iter->first, ((t_map*)ttype)->get_key_type()); resolve_const_value(v_iter->second, ((t_map*)ttype)->get_val_type()); } } else if (ttype->is_list()) { const std::vector& val = const_val->get_list(); std::vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { resolve_const_value((*v_iter), ((t_list*)ttype)->get_elem_type()); } } else if (ttype->is_set()) { const std::vector& val = const_val->get_list(); std::vector::const_iterator v_iter; for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { resolve_const_value((*v_iter), ((t_set*)ttype)->get_elem_type()); } } else if (ttype->is_struct()) { auto* tstruct = (t_struct*)ttype; const std::map& map = const_val->get_map(); std::map::const_iterator v_iter; for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) { t_field* field = tstruct->get_field_by_name(v_iter->first->get_string()); if (field == nullptr) { throw "No field named \"" + v_iter->first->get_string() + "\" was found in struct of type \"" + tstruct->get_name() + "\""; } resolve_const_value(v_iter->second, field->get_type()); } } else if (const_val->get_type() == t_const_value::CV_IDENTIFIER) { if (ttype->is_enum()) { const_val->set_enum((t_enum*)ttype); } else { t_const* constant = get_constant(const_val->get_identifier()); if (constant == nullptr) { throw "No enum value or constant found named \"" + const_val->get_identifier() + "\"!"; } // Resolve typedefs to the underlying type t_type* const_type = constant->get_type()->get_true_type(); if (const_type->is_base_type()) { switch (((t_base_type*)const_type)->get_base()) { case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: case t_base_type::TYPE_I64: case t_base_type::TYPE_BOOL: case t_base_type::TYPE_I8: const_val->set_integer(constant->get_value()->get_integer()); break; case t_base_type::TYPE_STRING: const_val->set_string(constant->get_value()->get_string()); break; case t_base_type::TYPE_DOUBLE: const_val->set_double(constant->get_value()->get_double()); break; case t_base_type::TYPE_VOID: throw "Constants cannot be of type VOID"; } } else if (const_type->is_map()) { const std::map& map = constant->get_value()->get_map(); std::map::const_iterator v_iter; const_val->set_map(); for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) { const_val->add_map(v_iter->first, v_iter->second); } } else if (const_type->is_list()) { const std::vector& val = constant->get_value()->get_list(); std::vector::const_iterator v_iter; const_val->set_list(); for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { const_val->add_list(*v_iter); } } } } else if (ttype->is_enum()) { // enum constant with non-identifier value. set the enum and find the // value's name. auto* tenum = (t_enum*)ttype; t_enum_value* enum_value = tenum->get_constant_by_value(const_val->get_integer()); if (enum_value == nullptr) { std::ostringstream valstm; valstm << const_val->get_integer(); throw "Couldn't find a named value in enum " + tenum->get_name() + " for value " + valstm.str(); } const_val->set_identifier(tenum->get_name() + "." + enum_value->get_name()); const_val->set_enum(tenum); } } private: // Map of names to types std::map types_; // Map of names to constants std::map constants_; // Map of names to services std::map services_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_service.h000066400000000000000000000060001420101504100230070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_SERVICE_H #define T_SERVICE_H #include "thrift/parse/t_function.h" #include class t_program; /** * A service consists of a set of functions. * */ class t_service : public t_type { public: t_service(t_program* program) : t_type(program), extends_(nullptr) {} bool is_service() const override { return true; } void set_extends(t_service* extends) { extends_ = extends; } void add_function(t_function* func) { if (get_function_by_name(func->get_name()) != NULL) { throw "Function " + func->get_name() + " is already defined"; } functions_.push_back(func); } void validate_unique_members() { std::vector::const_iterator iter; for (iter = functions_.begin(); iter != functions_.end(); ++iter) { // throw exception when there is a conflict of names with super class if (extends_ != NULL) { if (extends_->get_function_by_name((*iter)->get_name()) != NULL) { throw "Function " + (*iter)->get_name() + " is already defined in service " + name_; } } } } t_function* get_function_by_name(std::string func_name) { if (extends_ != NULL) { t_function* func = NULL; if ((func = extends_->get_function_by_name(func_name)) != NULL) { return func; } } std::vector::const_iterator iter; for (iter = functions_.begin(); iter != functions_.end(); ++iter) { if ((*iter)->get_name() == func_name) { return *iter; } } return NULL; } const t_function* get_function_by_name(std::string func_name) const { if (extends_ != NULL) { t_function* func = NULL; if ((func = extends_->get_function_by_name(func_name)) != NULL) { return func; } } std::vector::const_iterator iter; for (iter = functions_.begin(); iter != functions_.end(); ++iter) { if ((*iter)->get_name() == func_name) { return *iter; } } return NULL; } const std::vector& get_functions() const { return functions_; } t_service* get_extends() { return extends_; } const t_service* get_extends() const { return extends_; } private: std::vector functions_; t_service* extends_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_set.h000066400000000000000000000023611420101504100221500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_SET_H #define T_SET_H #include "thrift/parse/t_container.h" /** * A set is a lightweight container type that just wraps another data type. * */ class t_set : public t_container { public: t_set(t_type* elem_type) : elem_type_(elem_type) {} const t_type* get_elem_type() const { return elem_type_; } t_type* get_elem_type() { return elem_type_; } bool is_set() const override { return true; } private: t_type* elem_type_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_struct.h000066400000000000000000000120541420101504100227010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_STRUCT_H #define T_STRUCT_H #include #include #include #include #include "thrift/parse/t_type.h" #include "thrift/parse/t_field.h" // Forward declare that puppy class t_program; /** * A struct is a container for a set of member fields that has a name. Structs * are also used to implement exception types. * */ class t_struct : public t_type { public: typedef std::vector members_type; t_struct(t_program* program) : t_type(program), is_xception_(false), is_union_(false), members_validated(false), members_with_value(0), xsd_all_(false) {} t_struct(t_program* program, const std::string& name) : t_type(program, name), is_xception_(false), is_union_(false), members_validated(false), members_with_value(0), xsd_all_(false) {} void set_name(const std::string& name) override { name_ = name; validate_union_members(); } void set_xception(bool is_xception) { is_xception_ = is_xception; } void validate_union_member(t_field* field) { if (is_union_ && (!name_.empty())) { // 1) unions can't have required fields // 2) union members are implicitly optional, otherwise bugs like THRIFT-3650 wait to happen if (field->get_req() != t_field::T_OPTIONAL) { // no warning on default requiredness, but do warn on anything else that is explicitly asked for if(field->get_req() != t_field::T_OPT_IN_REQ_OUT) { pwarning(1, "Union %s field %s: union members must be optional, ignoring specified requiredness.\n", name_.c_str(), field->get_name().c_str()); } field->set_req(t_field::T_OPTIONAL); } // unions may have up to one member defaulted, but not more if (field->get_value() != nullptr) { if (1 < ++members_with_value) { throw "Error: Field " + field->get_name() + " provides another default value for union " + name_; } } } } void validate_union_members() { if (is_union_ && (!name_.empty()) && (!members_validated)) { members_type::const_iterator m_iter; for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { validate_union_member(*m_iter); } members_validated = true; } } void set_union(bool is_union) { is_union_ = is_union; validate_union_members(); } void set_xsd_all(bool xsd_all) { xsd_all_ = xsd_all; } bool get_xsd_all() const { return xsd_all_; } bool append(t_field* elem) { typedef members_type::iterator iter_type; std::pair bounds = std::equal_range(members_in_id_order_.begin(), members_in_id_order_.end(), elem, t_field::key_compare()); if (bounds.first != bounds.second) { return false; } // returns false when there is a conflict of field names if (get_field_by_name(elem->get_name()) != nullptr) { return false; } members_.push_back(elem); members_in_id_order_.insert(bounds.second, elem); validate_union_member(elem); return true; } const members_type& get_members() const { return members_; } const members_type& get_sorted_members() const { return members_in_id_order_; } bool is_struct() const override { return !is_xception_; } bool is_xception() const override { return is_xception_; } bool is_union() const { return is_union_; } t_field* get_field_by_name(std::string field_name) { return const_cast(const_cast(*this).get_field_by_name(field_name)); } const t_field* get_field_by_name(std::string field_name) const { members_type::const_iterator m_iter; for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { if ((*m_iter)->get_name() == field_name) { return *m_iter; } } return nullptr; } private: members_type members_; members_type members_in_id_order_; bool is_xception_; bool is_union_; bool members_validated; int members_with_value; bool xsd_all_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_type.h000066400000000000000000000063311420101504100223370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_TYPE_H #define T_TYPE_H #include #include #include #include #include "thrift/parse/t_doc.h" class t_program; /** * Generic representation of a thrift type. These objects are used by the * parser module to build up a tree of object that are all explicitly typed. * The generic t_type class exports a variety of useful methods that are * used by the code generator to branch based upon different handling for the * various types. * */ class t_type : public t_doc { public: ~t_type() override = default; virtual void set_name(const std::string& name) { name_ = name; } virtual const std::string& get_name() const { return name_; } virtual bool is_void() const { return false; } virtual bool is_base_type() const { return false; } virtual bool is_string() const { return false; } virtual bool is_binary() const { return false; } virtual bool is_bool() const { return false; } virtual bool is_typedef() const { return false; } virtual bool is_enum() const { return false; } virtual bool is_struct() const { return false; } virtual bool is_xception() const { return false; } virtual bool is_container() const { return false; } virtual bool is_list() const { return false; } virtual bool is_set() const { return false; } virtual bool is_map() const { return false; } virtual bool is_service() const { return false; } t_program* get_program() { return program_; } const t_program* get_program() const { return program_; } t_type* get_true_type(); const t_type* get_true_type() const; // This function will break (maybe badly) unless 0 <= num <= 16. static char nybble_to_xdigit(int num) { if (num < 10) { return '0' + num; } else { return 'A' + num - 10; } } static std::string byte_to_hex(uint8_t byte) { std::string rv; rv += nybble_to_xdigit(byte >> 4); rv += nybble_to_xdigit(byte & 0x0f); return rv; } std::map annotations_; protected: t_type() : program_(nullptr) { ; } t_type(t_program* program) : program_(program) { ; } t_type(t_program* program, std::string name) : program_(program), name_(name) { ; } t_type(std::string name) : program_(nullptr), name_(name) { ; } t_program* program_; std::string name_; }; /** * Placeholder struct for returning the key and value of an annotation * during parsing. */ struct t_annotation { std::string key; std::string val; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/parse/t_typedef.cc000066400000000000000000000024221420101504100231510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include "thrift/parse/t_typedef.h" #include "thrift/parse/t_program.h" t_type* t_typedef::get_type() { return const_cast(const_cast(this)->get_type()); } const t_type* t_typedef::get_type() const { if (type_ == nullptr) { const t_type* type = get_program()->scope()->get_type(symbolic_); if (type == nullptr) { printf("Type \"%s\" not defined\n", symbolic_.c_str()); exit(1); } return type; } return type_; } thrift-0.16.0/compiler/cpp/src/thrift/parse/t_typedef.h000066400000000000000000000040661420101504100230210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef T_TYPEDEF_H #define T_TYPEDEF_H #include #include "thrift/parse/t_type.h" /** * A typedef is a mapping from a symbolic name to another type. In dymanically * typed languages (i.e. php/python) the code generator can actually usually * ignore typedefs and just use the underlying type directly, though in C++ * the symbolic naming can be quite useful for code clarity. * */ class t_typedef : public t_type { public: t_typedef(t_program* program, t_type* type, const std::string& symbolic) : t_type(program, symbolic), type_(type), symbolic_(symbolic), forward_(false) {} /** * This constructor is used to refer to a type that is lazily * resolved at a later time, like for forward declarations or * recursive types. */ t_typedef(t_program* program, const std::string& symbolic, bool forward) : t_type(program, symbolic), type_(nullptr), symbolic_(symbolic), forward_(forward) {} ~t_typedef() override = default; t_type* get_type(); const t_type* get_type() const; const std::string& get_symbolic() const { return symbolic_; } bool is_forward_typedef() const { return forward_; } bool is_typedef() const override { return true; } private: t_type* type_; std::string symbolic_; bool forward_; }; #endif thrift-0.16.0/compiler/cpp/src/thrift/platform.h000066400000000000000000000027741420101504100215540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * define for mkdir,since the method signature * is different for the non-POSIX MinGW */ #ifdef _MSC_VER #include "thrift/windows/config.h" #endif #ifdef _WIN32 #include #include #else #include #include #endif #include // ignore EEXIST, throw on any other error #ifdef _WIN32 #define MKDIR(x) { int r = _mkdir(x); if (r == -1 && errno != EEXIST) { throw (std::string(x) + ": ") + strerror(errno); } } #else #define MKDIR(x) { int r = mkdir(x, S_IRWXU | S_IRWXG | S_IRWXO); if (r == -1 && errno != EEXIST) { throw (std::string(x) + ": ") + strerror(errno); } } #endif #ifdef PATH_MAX #define THRIFT_PATH_MAX PATH_MAX #else #define THRIFT_PATH_MAX MAX_PATH #endif thrift-0.16.0/compiler/cpp/src/thrift/thriftl.ll000066400000000000000000000250641420101504100215610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * Thrift scanner. * * Tokenizes a thrift definition file. */ %{ /* This is redundant with some of the flags in Makefile.am, but it works * when people override CXXFLAGS without being careful. The pragmas are * the 'right' way to do it, but don't work on old-enough GCC (in particular * the GCC that ship on Mac OS X 10.6.5, *counter* to what the GNU docs say) * * We should revert the Makefile.am changes once Apple ships a reasonable * GCC. */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-label" #endif #ifdef _MSC_VER #pragma warning( push ) // warning C4102: 'find_rule' : unreferenced label #pragma warning( disable : 4102 ) // warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data #pragma warning( disable : 4267 ) // avoid isatty redefinition #define YY_NEVER_INTERACTIVE 1 #define YY_NO_UNISTD_H 1 #endif #include #include #include #include #ifdef _MSC_VER #include "thrift/windows/config.h" #endif #include "thrift/main.h" #include "thrift/common.h" #include "thrift/globals.h" #include "thrift/parse/t_program.h" /** * Must be included AFTER parse/t_program.h, but I can't remember why anymore * because I wrote this a while ago. */ #if defined(BISON_USE_PARSER_H_EXTENSION) #include "thrift/thrifty.h" #else #include "thrift/thrifty.hh" #endif void integer_overflow(char* text) { yyerror("This integer is too big: \"%s\"\n", text); exit(1); } void unexpected_token(char* text) { yyerror("Unexpected token in input: \"%s\"\n", text); exit(1); } %} /** * Provides the yylineno global, useful for debugging output */ %option lex-compat /** * Our inputs are all single files, so no need for yywrap */ %option noyywrap /** * We don't use it, and it fires up warnings at -Wall */ %option nounput /** * Helper definitions, comments, constants, and whatnot */ intconstant ([+-]?[0-9]+) hexconstant ([+-]?"0x"[0-9A-Fa-f]+) dubconstant ([+-]?[0-9]*(\.[0-9]+)?([eE][+-]?[0-9]+)?) identifier ([a-zA-Z_](\.[a-zA-Z_0-9]|[a-zA-Z_0-9])*) whitespace ([ \t\r\n]*) sillycomm ("/*""*"*"*/") multicm_begin ("/*") doctext_begin ("/**") comment ("//"[^\n]*) unixcomment ("#"[^\n]*) symbol ([:;\,\{\}\(\)\=<>\[\]]) literal_begin (['\"]) %% {whitespace} { /* do nothing */ } {sillycomm} { /* do nothing */ } {doctext_begin} { std::string parsed("/**"); int state = 0; // 0 = normal, 1 = "*" seen, "*/" seen while(state < 2) { int ch = yyinput(); parsed.push_back(ch); switch (ch) { case EOF: yyerror("Unexpected end of file in doc-comment at %d\n", yylineno); exit(1); case '*': state = 1; break; case '/': state = (state == 1) ? 2 : 0; break; default: state = 0; break; } } pdebug("doctext = \"%s\"\n",parsed.c_str()); /* This does not show up in the parse tree. */ /* Rather, the parser will grab it out of the global. */ if (g_parse_mode == PROGRAM) { clear_doctext(); g_doctext = strdup(parsed.c_str() + 3); assert(strlen(g_doctext) >= 2); g_doctext[strlen(g_doctext) - 2] = ' '; g_doctext[strlen(g_doctext) - 1] = '\0'; g_doctext = clean_up_doctext(g_doctext); g_doctext_lineno = yylineno; if( (g_program_doctext_candidate == nullptr) && (g_program_doctext_status == INVALID)){ g_program_doctext_candidate = strdup(g_doctext); g_program_doctext_lineno = g_doctext_lineno; g_program_doctext_status = STILL_CANDIDATE; pdebug("%s","program doctext set to STILL_CANDIDATE"); } } } {multicm_begin} { /* parsed, but thrown away */ std::string parsed("/*"); int state = 0; // 0 = normal, 1 = "*" seen, "*/" seen while(state < 2) { int ch = yyinput(); parsed.push_back(ch); switch (ch) { case EOF: yyerror("Unexpected end of file in multiline comment at %d\n", yylineno); exit(1); case '*': state = 1; break; case '/': state = (state == 1) ? 2 : 0; break; default: state = 0; break; } } pdebug("multi_comm = \"%s\"\n",parsed.c_str()); } {comment} { /* do nothing */ } {unixcomment} { /* do nothing */ } {symbol} { return yytext[0]; } "*" { return yytext[0]; } "false" { yylval.iconst=0; return tok_int_constant; } "true" { yylval.iconst=1; return tok_int_constant; } "namespace" { return tok_namespace; } "cpp_namespace" { error_unsupported_namespace_decl("cpp"); /* do nothing */ } "cpp_include" { return tok_cpp_include; } "cpp_type" { return tok_cpp_type; } "java_package" { error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ } "delphi_namespace" { error_unsupported_namespace_decl("delphi"); /* do nothing */ } "php_namespace" { error_unsupported_namespace_decl("php"); /* do nothing */ } "py_module" { error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ } "perl_package" { error_unsupported_namespace_decl("perl_package", "perl"); /* do nothing */ } "ruby_namespace" { error_unsupported_namespace_decl("ruby"); /* do nothing */ } "smalltalk_category" { error_unsupported_namespace_decl("smalltalk_category", "st"); /* do nothing */ } "smalltalk_prefix" { error_unsupported_namespace_decl("smalltalk_prefix", "st"); /* do nothing */ } "xsd_all" { return tok_xsd_all; } "xsd_optional" { return tok_xsd_optional; } "xsd_nillable" { return tok_xsd_nillable; } "xsd_namespace" { error_unsupported_namespace_decl("xsd"); /* do nothing */ } "xsd_attrs" { return tok_xsd_attrs; } "include" { return tok_include; } "void" { return tok_void; } "bool" { return tok_bool; } "byte" { emit_byte_type_warning(); return tok_i8; } "i8" { return tok_i8; } "i16" { return tok_i16; } "i32" { return tok_i32; } "i64" { return tok_i64; } "double" { return tok_double; } "string" { return tok_string; } "binary" { return tok_binary; } "slist" { pwarning(0, "\"slist\" is deprecated and will be removed in a future compiler version. This type should be replaced with \"string\".\n"); return tok_slist; } "senum" { pwarning(0, "\"senum\" is deprecated and will be removed in a future compiler version. This type should be replaced with \"string\".\n"); return tok_senum; } "map" { return tok_map; } "list" { return tok_list; } "set" { return tok_set; } "oneway" { return tok_oneway; } "typedef" { return tok_typedef; } "struct" { return tok_struct; } "union" { return tok_union; } "exception" { return tok_xception; } "extends" { return tok_extends; } "throws" { return tok_throws; } "service" { return tok_service; } "enum" { return tok_enum; } "const" { return tok_const; } "required" { return tok_required; } "optional" { return tok_optional; } "async" { pwarning(0, "\"async\" is deprecated. It is called \"oneway\" now.\n"); return tok_oneway; } "&" { return tok_reference; } {intconstant} { errno = 0; yylval.iconst = strtoll(yytext, nullptr, 10); if (errno == ERANGE) { integer_overflow(yytext); } return tok_int_constant; } {hexconstant} { errno = 0; char sign = yytext[0]; int shift = sign == '0' ? 2 : 3; yylval.iconst = strtoll(yytext+shift, nullptr, 16); if (sign == '-') { yylval.iconst = -yylval.iconst; } if (errno == ERANGE) { integer_overflow(yytext); } return tok_int_constant; } {identifier} { yylval.id = strdup(yytext); return tok_identifier; } {dubconstant} { /* Deliberately placed after identifier, since "e10" is NOT a double literal (THRIFT-3477) */ yylval.dconst = atof(yytext); return tok_dub_constant; } {literal_begin} { char mark = yytext[0]; std::string result; for(;;) { int ch = yyinput(); switch (ch) { case EOF: yyerror("End of file while read string at %d\n", yylineno); exit(1); case '\n': yyerror("End of line while read string at %d\n", yylineno - 1); exit(1); case '\\': ch = yyinput(); switch (ch) { case 'r': result.push_back('\r'); continue; case 'n': result.push_back('\n'); continue; case 't': result.push_back('\t'); continue; case '"': result.push_back('"'); continue; case '\'': result.push_back('\''); continue; case '\\': result.push_back('\\'); continue; default: yyerror("Bad escape character\n"); return -1; } break; default: if (ch == mark) { yylval.id = strdup(result.c_str()); return tok_literal; } else { result.push_back(ch); } } } } . { unexpected_token(yytext); } %% #ifdef _MSC_VER #pragma warning( pop ) #endif /* vim: filetype=lex */ thrift-0.16.0/compiler/cpp/src/thrift/thrifty.yy000066400000000000000000000655671420101504100216440ustar00rootroot00000000000000%code requires { #include "thrift/parse/t_program.h" } %{ /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * Thrift parser. * * This parser is used on a thrift definition file. * */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include #include #ifndef _MSC_VER #include #else #include #endif #include #ifdef _MSC_VER #include "thrift/windows/config.h" #endif #include "thrift/main.h" #include "thrift/common.h" #include "thrift/globals.h" #include "thrift/parse/t_program.h" #include "thrift/parse/t_scope.h" #ifdef _MSC_VER //warning C4065: switch statement contains 'default' but no 'case' labels #pragma warning(disable:4065) #endif /** * This global variable is used for automatic numbering of field indices etc. * when parsing the members of a struct. Field values are automatically * assigned starting from -1 and working their way down. */ int y_field_val = -1; /** * This global variable is used for automatic numbering of enum values. * y_enum_val is the last value assigned; the next auto-assigned value will be * y_enum_val+1, and then it continues working upwards. Explicitly specified * enum values reset y_enum_val to that value. */ int32_t y_enum_val = -1; int g_arglist = 0; const int struct_is_struct = 0; const int struct_is_union = 1; %} /** * This structure is used by the parser to hold the data types associated with * various parse nodes. */ %union { char* id; int64_t iconst; double dconst; bool tbool; t_doc* tdoc; t_type* ttype; t_base_type* tbase; t_typedef* ttypedef; t_enum* tenum; t_enum_value* tenumv; t_const* tconst; t_const_value* tconstv; t_struct* tstruct; t_service* tservice; t_function* tfunction; t_field* tfield; char* dtext; t_field::e_req ereq; t_annotation* tannot; t_field_id tfieldid; } /** * Strings identifier */ %token tok_identifier %token tok_literal %token tok_doctext /** * Constant values */ %token tok_int_constant %token tok_dub_constant /** * Header keywords */ %token tok_include %token tok_namespace %token tok_cpp_include %token tok_cpp_type %token tok_xsd_all %token tok_xsd_optional %token tok_xsd_nillable %token tok_xsd_attrs /** * Base datatype keywords */ %token tok_void %token tok_bool %token tok_string %token tok_binary %token tok_slist %token tok_senum %token tok_i8 %token tok_i16 %token tok_i32 %token tok_i64 %token tok_double /** * Complex type keywords */ %token tok_map %token tok_list %token tok_set /** * Function modifiers */ %token tok_oneway /** * Thrift language keywords */ %token tok_typedef %token tok_struct %token tok_xception %token tok_throws %token tok_extends %token tok_service %token tok_enum %token tok_const %token tok_required %token tok_optional %token tok_union %token tok_reference /** * Grammar nodes */ %type BaseType %type SimpleBaseType %type ContainerType %type SimpleContainerType %type MapType %type SetType %type ListType %type Definition %type TypeDefinition %type Typedef %type TypeAnnotations %type TypeAnnotationList %type TypeAnnotation %type TypeAnnotationValue %type Field %type FieldIdentifier %type FieldRequiredness %type FieldType %type FieldValue %type FieldList %type FieldReference %type Enum %type EnumDefList %type EnumDef %type EnumValue %type Senum %type SenumDefList %type SenumDef %type Const %type ConstValue %type ConstList %type ConstListContents %type ConstMap %type ConstMapContents %type StructHead %type Struct %type Xception %type Service %type Function %type FunctionType %type FunctionList %type Throws %type Extends %type Oneway %type XsdAll %type XsdOptional %type XsdNillable %type XsdAttributes %type CppType %type CaptureDocText %% /** * Thrift Grammar Implementation. * * For the most part this source file works its way top down from what you * might expect to find in a typical .thrift file, i.e. type definitions and * namespaces up top followed by service definitions using those types. */ Program: HeaderList DefinitionList { pdebug("Program -> Headers DefinitionList"); if((g_program_doctext_candidate != nullptr) && (g_program_doctext_status != ALREADY_PROCESSED)) { g_program->set_doc(g_program_doctext_candidate); g_program_doctext_status = ALREADY_PROCESSED; } clear_doctext(); } CaptureDocText: { if (g_parse_mode == PROGRAM) { $$ = g_doctext; g_doctext = nullptr; } else { $$ = nullptr; } } /* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */ DestroyDocText: { if (g_parse_mode == PROGRAM) { clear_doctext(); } } /* We have to DestroyDocText here, otherwise it catches the doctext on the first real element. */ HeaderList: HeaderList DestroyDocText Header { pdebug("HeaderList -> HeaderList Header"); } | { pdebug("HeaderList -> "); } Header: Include { pdebug("Header -> Include"); } | tok_namespace tok_identifier tok_identifier TypeAnnotations { pdebug("Header -> tok_namespace tok_identifier tok_identifier"); declare_valid_program_doctext(); if (g_parse_mode == PROGRAM) { g_program->set_namespace($2, $3); } if ($4 != nullptr) { g_program->set_namespace_annotations($2, $4->annotations_); delete $4; } } | tok_namespace '*' tok_identifier { pdebug("Header -> tok_namespace * tok_identifier"); declare_valid_program_doctext(); if (g_parse_mode == PROGRAM) { g_program->set_namespace("*", $3); } } | tok_cpp_include tok_literal { pdebug("Header -> tok_cpp_include tok_literal"); declare_valid_program_doctext(); if (g_parse_mode == PROGRAM) { g_program->add_cpp_include($2); } } Include: tok_include tok_literal { pdebug("Include -> tok_include tok_literal"); declare_valid_program_doctext(); if (g_parse_mode == INCLUDES) { std::string path = include_file(std::string($2)); if (!path.empty()) { g_program->add_include(path, std::string($2)); } } } DefinitionList: DefinitionList CaptureDocText Definition { pdebug("DefinitionList -> DefinitionList Definition"); if ($2 != nullptr && $3 != nullptr) { $3->set_doc($2); } } | { pdebug("DefinitionList -> "); } Definition: Const { pdebug("Definition -> Const"); if (g_parse_mode == PROGRAM) { g_program->add_const($1); } $$ = $1; } | TypeDefinition { pdebug("Definition -> TypeDefinition"); if (g_parse_mode == PROGRAM) { g_scope->add_type($1->get_name(), $1); if (g_parent_scope != nullptr) { g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1); } if (! g_program->is_unique_typename($1)) { yyerror("Type \"%s\" is already defined.", $1->get_name().c_str()); exit(1); } } $$ = $1; } | Service { pdebug("Definition -> Service"); if (g_parse_mode == PROGRAM) { g_scope->add_service($1->get_name(), $1); if (g_parent_scope != nullptr) { g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1); } g_program->add_service($1); if (! g_program->is_unique_typename($1)) { yyerror("Type \"%s\" is already defined.", $1->get_name().c_str()); exit(1); } } $$ = $1; } TypeDefinition: Typedef { pdebug("TypeDefinition -> Typedef"); if (g_parse_mode == PROGRAM) { g_program->add_typedef($1); } } | Enum { pdebug("TypeDefinition -> Enum"); if (g_parse_mode == PROGRAM) { g_program->add_enum($1); } } | Senum { pdebug("TypeDefinition -> Senum"); if (g_parse_mode == PROGRAM) { g_program->add_typedef($1); } } | Struct { pdebug("TypeDefinition -> Struct"); if (g_parse_mode == PROGRAM) { g_program->add_struct($1); } } | Xception { pdebug("TypeDefinition -> Xception"); if (g_parse_mode == PROGRAM) { g_program->add_xception($1); } } CommaOrSemicolonOptional: ',' {} | ';' {} | {} Typedef: tok_typedef FieldType tok_identifier TypeAnnotations CommaOrSemicolonOptional { pdebug("TypeDef -> tok_typedef FieldType tok_identifier"); validate_simple_identifier( $3); t_typedef *td = new t_typedef(g_program, $2, $3); $$ = td; if ($4 != nullptr) { $$->annotations_ = $4->annotations_; delete $4; } } Enum: tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations { pdebug("Enum -> tok_enum tok_identifier { EnumDefList }"); $$ = $4; validate_simple_identifier( $2); $$->set_name($2); if ($6 != nullptr) { $$->annotations_ = $6->annotations_; delete $6; } // make constants for all the enum values if (g_parse_mode == PROGRAM) { const std::vector& enum_values = $$->get_constants(); std::vector::const_iterator c_iter; for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { std::string const_name = $$->get_name() + "." + (*c_iter)->get_name(); t_const_value* const_val = new t_const_value((*c_iter)->get_value()); const_val->set_enum($$); g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); if (g_parent_scope != nullptr) { g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); } } } } EnumDefList: EnumDefList EnumDef { pdebug("EnumDefList -> EnumDefList EnumDef"); $$ = $1; $$->append($2); } | { pdebug("EnumDefList -> "); $$ = new t_enum(g_program); y_enum_val = -1; } EnumDef: CaptureDocText EnumValue TypeAnnotations CommaOrSemicolonOptional { pdebug("EnumDef -> EnumValue"); $$ = $2; if ($1 != nullptr) { $$->set_doc($1); } if ($3 != nullptr) { $$->annotations_ = $3->annotations_; delete $3; } } EnumValue: tok_identifier '=' tok_int_constant { pdebug("EnumValue -> tok_identifier = tok_int_constant"); if ($3 < INT32_MIN || $3 > INT32_MAX) { // Note: this used to be just a warning. However, since thrift always // treats enums as i32 values, I'm changing it to a fatal error. // I doubt this will affect many people, but users who run into this // will have to update their thrift files to manually specify the // truncated i32 value that thrift has always been using anyway. failure("64-bit value supplied for enum %s will be truncated.", $1); } y_enum_val = static_cast($3); $$ = new t_enum_value($1, y_enum_val); } | tok_identifier { pdebug("EnumValue -> tok_identifier"); validate_simple_identifier( $1); if (y_enum_val == INT32_MAX) { failure("enum value overflow at enum %s", $1); } ++y_enum_val; $$ = new t_enum_value($1, y_enum_val); } Senum: tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations { pdebug("Senum -> tok_senum tok_identifier { SenumDefList }"); validate_simple_identifier( $2); $$ = new t_typedef(g_program, $4, $2); if ($6 != nullptr) { $$->annotations_ = $6->annotations_; delete $6; } } SenumDefList: SenumDefList SenumDef { pdebug("SenumDefList -> SenumDefList SenumDef"); $$ = $1; $$->add_string_enum_val($2); } | { pdebug("SenumDefList -> "); $$ = new t_base_type("string", t_base_type::TYPE_STRING); $$->set_string_enum(true); } SenumDef: tok_literal CommaOrSemicolonOptional { pdebug("SenumDef -> tok_literal"); $$ = $1; } Const: tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional { pdebug("Const -> tok_const FieldType tok_identifier = ConstValue"); if (g_parse_mode == PROGRAM) { validate_simple_identifier( $3); g_scope->resolve_const_value($5, $2); $$ = new t_const($2, $3, $5); validate_const_type($$); g_scope->add_constant($3, $$); if (g_parent_scope != nullptr) { g_parent_scope->add_constant(g_parent_prefix + $3, $$); } } else { $$ = nullptr; } } ConstValue: tok_int_constant { pdebug("ConstValue => tok_int_constant"); $$ = new t_const_value(); $$->set_integer($1); if (!g_allow_64bit_consts && ($1 < INT32_MIN || $1 > INT32_MAX)) { pwarning(1, "64-bit constant \"%" PRIi64"\" may not work in all languages.\n", $1); } } | tok_dub_constant { pdebug("ConstValue => tok_dub_constant"); $$ = new t_const_value(); $$->set_double($1); } | tok_literal { pdebug("ConstValue => tok_literal"); $$ = new t_const_value($1); } | tok_identifier { pdebug("ConstValue => tok_identifier"); $$ = new t_const_value(); $$->set_identifier($1); } | ConstList { pdebug("ConstValue => ConstList"); $$ = $1; } | ConstMap { pdebug("ConstValue => ConstMap"); $$ = $1; } ConstList: '[' ConstListContents ']' { pdebug("ConstList => [ ConstListContents ]"); $$ = $2; } ConstListContents: ConstListContents ConstValue CommaOrSemicolonOptional { pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional"); $$ = $1; $$->add_list($2); } | { pdebug("ConstListContents =>"); $$ = new t_const_value(); $$->set_list(); } ConstMap: '{' ConstMapContents '}' { pdebug("ConstMap => { ConstMapContents }"); $$ = $2; } ConstMapContents: ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional { pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional"); $$ = $1; $$->add_map($2, $4); } | { pdebug("ConstMapContents =>"); $$ = new t_const_value(); $$->set_map(); } StructHead: tok_struct { $$ = struct_is_struct; } | tok_union { $$ = struct_is_union; } Struct: StructHead tok_identifier XsdAll '{' FieldList '}' TypeAnnotations { pdebug("Struct -> tok_struct tok_identifier { FieldList }"); validate_simple_identifier( $2); $5->set_xsd_all($3); $5->set_union($1 == struct_is_union); $$ = $5; $$->set_name($2); if ($7 != nullptr) { $$->annotations_ = $7->annotations_; delete $7; } } XsdAll: tok_xsd_all { $$ = true; } | { $$ = false; } XsdOptional: tok_xsd_optional { $$ = true; } | { $$ = false; } XsdNillable: tok_xsd_nillable { $$ = true; } | { $$ = false; } XsdAttributes: tok_xsd_attrs '{' FieldList '}' { $$ = $3; } | { $$ = nullptr; } Xception: tok_xception tok_identifier '{' FieldList '}' TypeAnnotations { pdebug("Xception -> tok_xception tok_identifier { FieldList }"); validate_simple_identifier( $2); $4->set_name($2); $4->set_xception(true); $$ = $4; if ($6 != nullptr) { $$->annotations_ = $6->annotations_; delete $6; } } Service: tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations { pdebug("Service -> tok_service tok_identifier { FunctionList }"); validate_simple_identifier( $2); $$ = $6; $$->set_name($2); $$->set_extends($3); if ($9 != nullptr) { $$->annotations_ = $9->annotations_; delete $9; } } FlagArgs: { g_arglist = 1; } UnflagArgs: { g_arglist = 0; } Extends: tok_extends tok_identifier { pdebug("Extends -> tok_extends tok_identifier"); $$ = nullptr; if (g_parse_mode == PROGRAM) { $$ = g_scope->get_service($2); if ($$ == nullptr) { yyerror("Service \"%s\" has not been defined.", $2); exit(1); } } } | { $$ = nullptr; } FunctionList: FunctionList Function { pdebug("FunctionList -> FunctionList Function"); $$ = $1; $1->add_function($2); } | { pdebug("FunctionList -> "); $$ = new t_service(g_program); } Function: CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional { validate_simple_identifier( $4); $6->set_name(std::string($4) + "_args"); $$ = new t_function($3, $4, $6, $8, $2); if ($1 != nullptr) { $$->set_doc($1); } if ($9 != nullptr) { $$->annotations_ = $9->annotations_; delete $9; } } Oneway: tok_oneway { $$ = true; } | { $$ = false; } Throws: tok_throws '(' FieldList ')' { pdebug("Throws -> tok_throws ( FieldList )"); $$ = $3; if (g_parse_mode == PROGRAM && !validate_throws($$)) { yyerror("Throws clause may not contain non-exception types"); exit(1); } } | { $$ = new t_struct(g_program); } FieldList: FieldList Field { pdebug("FieldList -> FieldList , Field"); $$ = $1; if (!($$->append($2))) { yyerror("\"%d: %s\" - field identifier/name has already been used", $2->get_key(), $2->get_name().c_str()); exit(1); } } | { pdebug("FieldList -> "); y_field_val = -1; $$ = new t_struct(g_program); } Field: CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional { pdebug("tok_int_constant : Field -> FieldType tok_identifier"); if ($2.auto_assigned) { pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6); if (g_strict >= 192) { yyerror("Implicit field keys are deprecated and not allowed with -strict"); exit(1); } } validate_simple_identifier($6); $$ = new t_field($4, $6, $2.value); $$->set_reference($5); $$->set_req($3); if ($7 != nullptr) { g_scope->resolve_const_value($7, $4); validate_field_value($$, $7); $$->set_value($7); } $$->set_xsd_optional($8); $$->set_xsd_nillable($9); if ($1 != nullptr) { $$->set_doc($1); } if ($10 != nullptr) { $$->set_xsd_attrs($10); } if ($11 != nullptr) { $$->annotations_ = $11->annotations_; delete $11; } } FieldIdentifier: tok_int_constant ':' { if ($1 <= 0) { if (g_allow_neg_field_keys) { /* * g_allow_neg_field_keys exists to allow users to add explicitly * specified key values to old .thrift files without breaking * protocol compatibility. */ if ($1 != y_field_val) { /* * warn if the user-specified negative value isn't what * thrift would have auto-assigned. */ pwarning(1, "Nonpositive field key (%" PRIi64") differs from what would be " "auto-assigned by thrift (%d).\n", $1, y_field_val); } /* * Leave $1 as-is, and update y_field_val to be one less than $1. * The FieldList parsing will catch any duplicate key values. */ y_field_val = static_cast($1 - 1); $$.value = static_cast($1); $$.auto_assigned = false; } else { pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", $1); $$.value = y_field_val--; $$.auto_assigned = true; } } else { $$.value = static_cast($1); $$.auto_assigned = false; } if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) { pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", $$.value, SHRT_MIN, SHRT_MAX); } } | { $$.value = y_field_val--; $$.auto_assigned = true; if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) { pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", $$.value, SHRT_MIN, SHRT_MAX); } } FieldReference: tok_reference { $$ = true; } | { $$ = false; } FieldRequiredness: tok_required { $$ = t_field::T_REQUIRED; } | tok_optional { if (g_arglist) { if (g_parse_mode == PROGRAM) { pwarning(1, "optional keyword is ignored in argument lists.\n"); } $$ = t_field::T_OPT_IN_REQ_OUT; } else { $$ = t_field::T_OPTIONAL; } } | { $$ = t_field::T_OPT_IN_REQ_OUT; } FieldValue: '=' ConstValue { if (g_parse_mode == PROGRAM) { $$ = $2; } else { $$ = nullptr; } } | { $$ = nullptr; } FunctionType: FieldType { pdebug("FunctionType -> FieldType"); $$ = $1; } | tok_void { pdebug("FunctionType -> tok_void"); $$ = g_type_void; } FieldType: tok_identifier { pdebug("FieldType -> tok_identifier"); if (g_parse_mode == INCLUDES) { // Ignore identifiers in include mode $$ = nullptr; } else { // Lookup the identifier in the current scope $$ = g_scope->get_type($1); if ($$ == nullptr) { /* * Either this type isn't yet declared, or it's never declared. Either way allow it and we'll figure it out during generation. */ $$ = new t_typedef(g_program, $1, true); } } } | BaseType { pdebug("FieldType -> BaseType"); $$ = $1; } | ContainerType { pdebug("FieldType -> ContainerType"); $$ = $1; } BaseType: SimpleBaseType TypeAnnotations { pdebug("BaseType -> SimpleBaseType TypeAnnotations"); if ($2 != nullptr) { $$ = new t_base_type(*static_cast($1)); $$->annotations_ = $2->annotations_; delete $2; } else { $$ = $1; } } SimpleBaseType: tok_string { pdebug("BaseType -> tok_string"); $$ = g_type_string; } | tok_binary { pdebug("BaseType -> tok_binary"); $$ = g_type_binary; } | tok_slist { pdebug("BaseType -> tok_slist"); $$ = g_type_slist; } | tok_bool { pdebug("BaseType -> tok_bool"); $$ = g_type_bool; } | tok_i8 { pdebug("BaseType -> tok_i8"); $$ = g_type_i8; } | tok_i16 { pdebug("BaseType -> tok_i16"); $$ = g_type_i16; } | tok_i32 { pdebug("BaseType -> tok_i32"); $$ = g_type_i32; } | tok_i64 { pdebug("BaseType -> tok_i64"); $$ = g_type_i64; } | tok_double { pdebug("BaseType -> tok_double"); $$ = g_type_double; } ContainerType: SimpleContainerType TypeAnnotations { pdebug("ContainerType -> SimpleContainerType TypeAnnotations"); $$ = $1; if ($2 != nullptr) { $$->annotations_ = $2->annotations_; delete $2; } } SimpleContainerType: MapType { pdebug("SimpleContainerType -> MapType"); $$ = $1; } | SetType { pdebug("SimpleContainerType -> SetType"); $$ = $1; } | ListType { pdebug("SimpleContainerType -> ListType"); $$ = $1; } MapType: tok_map CppType '<' FieldType ',' FieldType '>' { pdebug("MapType -> tok_map "); $$ = new t_map($4, $6); if ($2 != nullptr) { ((t_container*)$$)->set_cpp_name(std::string($2)); } } SetType: tok_set CppType '<' FieldType '>' { pdebug("SetType -> tok_set"); $$ = new t_set($4); if ($2 != nullptr) { ((t_container*)$$)->set_cpp_name(std::string($2)); } } ListType: tok_list '<' FieldType '>' CppType { pdebug("ListType -> tok_list"); check_for_list_of_bytes($3); $$ = new t_list($3); if ($5 != nullptr) { ((t_container*)$$)->set_cpp_name(std::string($5)); } } CppType: tok_cpp_type tok_literal { $$ = $2; } | { $$ = nullptr; } TypeAnnotations: '(' TypeAnnotationList ')' { pdebug("TypeAnnotations -> ( TypeAnnotationList )"); $$ = $2; } | { $$ = nullptr; } TypeAnnotationList: TypeAnnotationList TypeAnnotation { pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation"); $$ = $1; $$->annotations_[$2->key] = $2->val; delete $2; } | { /* Just use a dummy structure to hold the annotations. */ $$ = new t_struct(g_program); } TypeAnnotation: tok_identifier TypeAnnotationValue CommaOrSemicolonOptional { pdebug("TypeAnnotation -> TypeAnnotationValue"); $$ = new t_annotation; $$->key = $1; $$->val = $2; } TypeAnnotationValue: '=' tok_literal { pdebug("TypeAnnotationValue -> = tok_literal"); $$ = $2; } | { pdebug("TypeAnnotationValue ->"); $$ = strdup("1"); } %% thrift-0.16.0/compiler/cpp/src/thrift/version.h000066400000000000000000000017501420101504100214060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _THRIFT_VERSION_H_ #define _THRIFT_VERSION_H_ 1 #if defined(_MSC_VER) && (_MSC_VER > 1200) #pragma once #endif // _MSC_VER #define THRIFT_VERSION "0.16.0" #endif // _THRIFT_VERSION_H_ thrift-0.16.0/compiler/cpp/src/thrift/windows/000077500000000000000000000000001420101504100212375ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/src/thrift/windows/config.h000066400000000000000000000026431420101504100226620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _THRIFT_WINDOWS_CONFIG_H_ #define _THRIFT_WINDOWS_CONFIG_H_ 1 #if defined(_MSC_VER) && (_MSC_VER > 1200) #pragma once #endif // _MSC_VER #ifndef _WIN32 #error "This is a Windows header only" #endif #include #include #include #define strtoll(begin_ptr, end_ptr, length) _strtoi64(begin_ptr, end_ptr, length) #ifndef PRIu64 #define PRIu64 "I64u" #endif #ifndef PRIi64 #define PRIi64 "I64i" #endif // squelch deprecation warnings #pragma warning(disable : 4996) // squelch bool conversion performance warning #pragma warning(disable : 4800) #include #endif // _THRIFT_WINDOWS_CONFIG_H_ thrift-0.16.0/compiler/cpp/test/000077500000000000000000000000001420101504100164355ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/test/CMakeLists.txt000066400000000000000000000032431420101504100211770ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # file(GLOB KEYWORD_SAMPLES "${CMAKE_CURRENT_SOURCE_DIR}/keyword-samples/*.thrift") set(KEYWORD_LANGS ${thrift_compiler_LANGS}) LIST(REMOVE_ITEM KEYWORD_LANGS swift) # in Swift you can escape reserved words foreach(LANG ${KEYWORD_LANGS}) foreach(SAMPLE ${KEYWORD_SAMPLES}) get_filename_component(FILENAME ${SAMPLE} NAME_WE) add_test(NAME "${LANG}_${FILENAME}" COMMAND thrift-compiler --gen ${LANG} ${SAMPLE}) set_tests_properties("${LANG}_${FILENAME}" PROPERTIES PASS_REGULAR_EXPRESSION "Cannot use reserved language keyword") endforeach() endforeach() find_package(PythonInterp QUIET) if(PYTHONINTERP_FOUND) add_test(NAME StalenessCheckTest COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/compiler/staleness_check.py ${THRIFT_COMPILER}) else() message(WARNING "Skipping StalenessCheckTest as there is no python interpreter available.") endif() thrift-0.16.0/compiler/cpp/test/Makefile.am000066400000000000000000000020651420101504100204740ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # Contains some contributions under the Thrift Software License. # Please see doc/old-thrift-license.txt in the Thrift distribution for # details. AUTOMAKE_OPTIONS = subdir-objects serial-tests nostdinc AM_CPPFLAGS = -I$(top_srcdir)/compiler/cpp/src AM_CXXFLAGS = -Wall -Wextra -pedantic thrift-0.16.0/compiler/cpp/test/compiler/000077500000000000000000000000001420101504100202475ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/test/compiler/Included.thrift000066400000000000000000000004771420101504100232300ustar00rootroot00000000000000const string foo = "bar" struct a_struct { 1: bool im_true, 2: bool im_false, 3: i8 a_bite, 4: i16 integer16, 5: i32 integer32, 6: i64 integer64, 7: double double_precision, 8: string some_characters, 9: string zomg_unicode, 10: bool what_who, } service AService { i32 a_procedure(1: i32 arg) } thrift-0.16.0/compiler/cpp/test/compiler/Including.thrift000066400000000000000000000001541420101504100234050ustar00rootroot00000000000000include "Included.thrift" const string s = "string" struct BStruct { 1: Included.a_struct one_of_each } thrift-0.16.0/compiler/cpp/test/compiler/Single.thrift000066400000000000000000000000311420101504100227040ustar00rootroot00000000000000const string foo = "bar" thrift-0.16.0/compiler/cpp/test/compiler/staleness_check.py000077500000000000000000000130411420101504100237610ustar00rootroot00000000000000#!/usr/bin/env python3 # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from __future__ import print_function import os import shutil import subprocess import sys import tempfile import time import unittest class TestStalenessCheck(unittest.TestCase): CURRENT_DIR_PATH = os.path.dirname(os.path.realpath(__file__)) THRIFT_EXECUTABLE_PATH = None SINGLE_THRIFT_FILE_PATH = os.path.join(CURRENT_DIR_PATH, "Single.thrift") INCLUDING_THRIFT_FILE_PATH = os.path.join(CURRENT_DIR_PATH, "Including.thrift") INCLUDED_THRIFT_FILE_PATH = os.path.join(CURRENT_DIR_PATH, "Included.thrift") def test_staleness_check_of_single_thrift_file_without_changed_output(self): temp_dir = tempfile.mkdtemp(dir=TestStalenessCheck.CURRENT_DIR_PATH) command = [TestStalenessCheck.THRIFT_EXECUTABLE_PATH, "-gen", "cpp", "-o", temp_dir] command += [TestStalenessCheck.SINGLE_THRIFT_FILE_PATH] subprocess.call(command) used_file_path = os.path.join(temp_dir, "gen-cpp", "Single_constants.cpp") first_modification_time = os.path.getmtime(os.path.join(used_file_path)) time.sleep(1.0) subprocess.call(command) second_modification_time = os.path.getmtime(used_file_path) self.assertEqual(second_modification_time, first_modification_time) shutil.rmtree(temp_dir, ignore_errors=True) def test_staleness_check_of_single_thrift_file_with_changed_output(self): temp_dir = tempfile.mkdtemp(dir=TestStalenessCheck.CURRENT_DIR_PATH) command = [TestStalenessCheck.THRIFT_EXECUTABLE_PATH, "-gen", "cpp", "-o", temp_dir] command += [TestStalenessCheck.SINGLE_THRIFT_FILE_PATH] subprocess.call(command) used_file_path = os.path.join(temp_dir, "gen-cpp", "Single_constants.cpp") first_modification_time = os.path.getmtime(os.path.join(used_file_path)) used_file = open(used_file_path, "r") first_contents = used_file.read() used_file.close() used_file = open(used_file_path, "a") used_file.write("\n/* This is a comment */\n") used_file.close() time.sleep(1.0) subprocess.call(command) second_modification_time = os.path.getmtime(used_file_path) used_file = open(used_file_path, "r") second_contents = used_file.read() used_file.close() self.assertGreater(second_modification_time, first_modification_time) self.assertEqual(first_contents, second_contents) shutil.rmtree(temp_dir, ignore_errors=True) def test_staleness_check_of_included_file(self): temp_dir = tempfile.mkdtemp(dir=TestStalenessCheck.CURRENT_DIR_PATH) temp_included_file_path = os.path.join(temp_dir, "Included.thrift") temp_including_file_path = os.path.join(temp_dir, "Including.thrift") shutil.copy2(TestStalenessCheck.INCLUDED_THRIFT_FILE_PATH, temp_included_file_path) shutil.copy2(TestStalenessCheck.INCLUDING_THRIFT_FILE_PATH, temp_including_file_path) command = [TestStalenessCheck.THRIFT_EXECUTABLE_PATH, "-gen", "cpp", "-recurse", "-o", temp_dir] command += [temp_including_file_path] subprocess.call(command) included_constants_cpp_file_path = os.path.join(temp_dir, "gen-cpp", "Included_constants.cpp") including_constants_cpp_file_path = os.path.join(temp_dir, "gen-cpp", "Including_constants.cpp") included_constants_cpp_first_modification_time = os.path.getmtime(included_constants_cpp_file_path) including_constants_cpp_first_modification_time = os.path.getmtime(including_constants_cpp_file_path) temp_included_file = open(temp_included_file_path, "a") temp_included_file.write("\nconst i32 an_integer = 42\n") temp_included_file.close() time.sleep(1.0) subprocess.call(command) included_constants_cpp_second_modification_time = os.path.getmtime(included_constants_cpp_file_path) including_constants_cpp_second_modification_time = os.path.getmtime(including_constants_cpp_file_path) self.assertGreater( included_constants_cpp_second_modification_time, included_constants_cpp_first_modification_time) self.assertEqual( including_constants_cpp_first_modification_time, including_constants_cpp_second_modification_time) shutil.rmtree(temp_dir, ignore_errors=True) def suite(): suite = unittest.TestSuite() loader = unittest.TestLoader() suite.addTest(loader.loadTestsFromTestCase(TestStalenessCheck)) return suite if __name__ == "__main__": # The path of Thrift compiler is passed as an argument to the test script. # Remove it to not confuse the unit testing framework TestStalenessCheck.THRIFT_EXECUTABLE_PATH = sys.argv[-1] del sys.argv[-1] unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2)) thrift-0.16.0/compiler/cpp/test/keyword-samples/000077500000000000000000000000001420101504100215635ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/test/keyword-samples/const1_return.thrift000066400000000000000000000000261420101504100256110ustar00rootroot00000000000000const bool return = 0 thrift-0.16.0/compiler/cpp/test/keyword-samples/enum1_return.thrift000066400000000000000000000000201420101504100254210ustar00rootroot00000000000000enum return { } thrift-0.16.0/compiler/cpp/test/keyword-samples/enum2_return.thrift000066400000000000000000000000341420101504100254270ustar00rootroot00000000000000enum enum_name { return } thrift-0.16.0/compiler/cpp/test/keyword-samples/exception1_return.thrift000066400000000000000000000000241420101504100264570ustar00rootroot00000000000000exception return {} thrift-0.16.0/compiler/cpp/test/keyword-samples/exception2_return.thrift000066400000000000000000000000651420101504100264650ustar00rootroot00000000000000exception exception_name { 1: required i8 return } thrift-0.16.0/compiler/cpp/test/keyword-samples/service1_return.thrift000066400000000000000000000000221420101504100261170ustar00rootroot00000000000000service return {} thrift-0.16.0/compiler/cpp/test/keyword-samples/service2_return.thrift000066400000000000000000000000751420101504100261300ustar00rootroot00000000000000service service_name { bool function_name(1: i32 return) } thrift-0.16.0/compiler/cpp/test/keyword-samples/service3_return.thrift000066400000000000000000000000511420101504100261230ustar00rootroot00000000000000service service_name { void return() } thrift-0.16.0/compiler/cpp/test/keyword-samples/service4_return.thrift000066400000000000000000000001601420101504100261250ustar00rootroot00000000000000exception exception_name {} service service_name { void function_name() throws ( 1: exception_name return) } thrift-0.16.0/compiler/cpp/test/keyword-samples/struct1_return.thrift000066400000000000000000000000211420101504100260020ustar00rootroot00000000000000struct return {} thrift-0.16.0/compiler/cpp/test/keyword-samples/struct2_return.thrift000066400000000000000000000000651420101504100260130ustar00rootroot00000000000000struct struct_name { 1: required bool return = 1 } thrift-0.16.0/compiler/cpp/test/keyword-samples/typedef1_return.thrift000066400000000000000000000000241420101504100261210ustar00rootroot00000000000000typedef bool return thrift-0.16.0/compiler/cpp/test/keyword-samples/union1_return.thrift000066400000000000000000000000201420101504100256050ustar00rootroot00000000000000union return {} thrift-0.16.0/compiler/cpp/test/keyword-samples/union2_return.thrift000066400000000000000000000000611420101504100256130ustar00rootroot00000000000000union union_name { 1: optional bool return=1 } thrift-0.16.0/compiler/cpp/tests/000077500000000000000000000000001420101504100166205ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/tests/CMakeLists.txt000066400000000000000000000145271420101504100213710ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # cmake_minimum_required(VERSION 2.8.12) project(thrift_compiler_tests) set(THRIFT_COMPILER_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.. ) # don't generate ZERO_CHECK set(CMAKE_SUPPRESS_REGENERATION true) # version.h now handled via veralign.sh #configure_file(${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h) if(MSVC) # The winflexbison generator outputs some macros that conflict with the Visual Studio 2010 copy of stdint.h # This might be fixed in later versions of Visual Studio, but an easy solution is to include stdint.h first if(HAVE_STDINT_H) add_definitions(-D__STDC_LIMIT_MACROS) add_definitions(/FI"stdint.h") endif(HAVE_STDINT_H) endif() find_package(FLEX REQUIRED) find_package(BISON REQUIRED) # create directory for thrifty and thriftl file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/) # Create flex and bison files and build the lib parse static library BISON_TARGET(thrifty ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/thrifty.yy ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc) FLEX_TARGET(thriftl ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/thriftl.ll ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc) ADD_FLEX_BISON_DEPENDENCY(thriftl thrifty) set(parse_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.hh ) add_library(parse STATIC ${parse_SOURCES}) # Thrift compiler tests set(thrift_compiler_tests ) # you can add some files manually there set(thrift_compiler_tests_manual_SOURCES # tests file to avoid main in every test file ${CMAKE_CURRENT_SOURCE_DIR}/tests_main.cc ) # set variable for tests sources - will be filled later set(thrift_compiler_tests_SOURCES ) set(thrift_compiler_SOURCES ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/logging.cc # we use logging instead of main to avoid breaking compillation (2 main v) ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/audit/t_audit.cpp ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/common.cc ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/t_generator.cc ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/parse/t_typedef.cc ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/parse/parse.cc ${THRIFT_COMPILER_SOURCE_DIR}/thrift/version.h ) # This macro adds an option THRIFT_COMPILER_${NAME} # that allows enabling or disabling certain languages macro(THRIFT_ADD_COMPILER name description initial) string(TOUPPER "THRIFT_COMPILER_${name}" enabler) set(src "${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/t_${name}_generator.cc") option(${enabler} ${description} ${initial}) if(${enabler}) list(APPEND thrift_compiler_SOURCES ${src}) file(GLOB thrift_compiler_tests_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.c*" "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.thrift" ) endif() endmacro() # The following compiler with unit tests can be enabled or disabled THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" OFF) THRIFT_ADD_COMPILER(cl "Enable compiler for Common LISP" OFF) THRIFT_ADD_COMPILER(cpp "Enable compiler for C++" OFF) THRIFT_ADD_COMPILER(d "Enable compiler for D" OFF) THRIFT_ADD_COMPILER(dart "Enable compiler for Dart" OFF) THRIFT_ADD_COMPILER(delphi "Enable compiler for Delphi" OFF) THRIFT_ADD_COMPILER(erl "Enable compiler for Erlang" OFF) THRIFT_ADD_COMPILER(go "Enable compiler for Go" OFF) THRIFT_ADD_COMPILER(gv "Enable compiler for GraphViz" OFF) THRIFT_ADD_COMPILER(haxe "Enable compiler for Haxe" OFF) THRIFT_ADD_COMPILER(html "Enable compiler for HTML Documentation" OFF) THRIFT_ADD_COMPILER(java "Enable compiler for Java" OFF) THRIFT_ADD_COMPILER(javame "Enable compiler for Java ME" OFF) THRIFT_ADD_COMPILER(js "Enable compiler for JavaScript" OFF) THRIFT_ADD_COMPILER(json "Enable compiler for JSON" OFF) THRIFT_ADD_COMPILER(lua "Enable compiler for Lua" OFF) THRIFT_ADD_COMPILER(netstd "Enable compiler for .NET Standard" ON) THRIFT_ADD_COMPILER(ocaml "Enable compiler for OCaml" OFF) THRIFT_ADD_COMPILER(perl "Enable compiler for Perl" OFF) THRIFT_ADD_COMPILER(php "Enable compiler for PHP" OFF) THRIFT_ADD_COMPILER(py "Enable compiler for Python 2.0" OFF) THRIFT_ADD_COMPILER(rb "Enable compiler for Ruby" OFF) THRIFT_ADD_COMPILER(rs "Enable compiler for Rust" OFF) THRIFT_ADD_COMPILER(st "Enable compiler for Smalltalk" OFF) THRIFT_ADD_COMPILER(swift "Enable compiler for Swift" OFF) THRIFT_ADD_COMPILER(xml "Enable compiler for XML" OFF) THRIFT_ADD_COMPILER(xsd "Enable compiler for XSD" OFF) # Thrift is looking for include files in the src directory # we also add the current binary directory for generated files include_directories(${CMAKE_CURRENT_BINARY_DIR} ${THRIFT_COMPILER_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/catch) add_library(thrift_compiler ${thrift_compiler_SOURCES}) #link parse lib to thrift_compiler lib target_link_libraries(thrift_compiler parse) # add tests executable add_executable(thrift_compiler_tests ${thrift_compiler_tests_manual_SOURCES} ${thrift_compiler_tests_SOURCES}) # if generates for Visual Studio set thrift_compiler_tests as default project if(MSVC) set_property(TARGET thrift_compiler_tests PROPERTY VS_STARTUP_PROJECT thrift_compiler_tests) endif() set_target_properties(thrift_compiler_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY bin/) set_target_properties(thrift_compiler_tests PROPERTIES OUTPUT_NAME thrift_compiler_tests) target_link_libraries(thrift_compiler_tests thrift_compiler) enable_testing() add_test(NAME ThriftTests COMMAND thrift_compiler_tests) thrift-0.16.0/compiler/cpp/tests/README.md000066400000000000000000000061641420101504100201060ustar00rootroot00000000000000# Build and run compiler tests using CMake - [Build and run compiler tests using CMake](#build-and-run-compiler-tests-using-cmake) - [General information](#general-information) - [How to add your tests](#how-to-add-your-tests) - [Build and run tests on Unix-like systems](#build-and-run-tests-on-unix-like-systems) - [Prerequisites:](#prerequisites) - [Build and run test with CMake](#build-and-run-test-with-cmake) - [Build and run tests on Windows](#build-and-run-tests-on-windows) - [Prerequisites:](#prerequisites-1) - [Generation of VS project with CMake, build and run on Windows](#generation-of-vs-project-with-cmake-build-and-run-on-windows) ## General information Added generic way to cover code by tests for many languages (you just need to make a correct header file for generator for your language - example in **netstd** implementation) At current moment these tests use free Catch library (https://github.com/catchorg/Catch2/tree/Catch1.x) for easy test creation and usage. Decision to use it was because of simplicity, easy usage, one header file to use, stable community and growing interest (https://cpp.libhunt.com/project/googletest-google/vs/catch?rel=cmp-cmp) Also, maybe, later it will be migrated to Catch2 (https://github.com/philsquared/Catch) - depends on need to support legacy compilers (c++98) ## How to add your tests - Open **CMakeLists.txt** - Set **On** to call of **THRIFT_ADD_COMPILER** for your language ``` cmake THRIFT_ADD_COMPILER(netstd "Enable compiler for .NET Standard" ON) ``` - Create folder with name specified in list of languages in **CMakeLists.txt** - Create tests in folder for your language (with extensions like *.c* - cc, cpp, etc) - Don't forget to add include of catch.hpp in your test file ``` C #include "../catch/catch.hpp" ``` - If you need - add files manually to **thrift_compiler_tests_manual_SOURCES** in **CMakeLists.txt** similar to ``` cmake # you can add some files manually there set(thrift_compiler_tests_manual_SOURCES # tests file to avoid main in every test file ${CMAKE_CURRENT_SOURCE_DIR}/tests_main.cc ) ``` - Run **cmake** with arguments for your environment and compiler - Enjoy ## Build and run tests on Unix-like systems ### Prerequisites: - Install CMake - - Install winflexbison - ### Build and run test with CMake - Run commands in command line in current directory: ``` mkdir cmake-vs && cd cmake-vs cmake .. cmake --build . ctest -C Debug -V ``` ## Build and run tests on Windows ### Prerequisites: - Install CMake - - Install winflexbison - - Install VS2017 Community Edition - (ensure that you installed workload "Desktop Development with C++" for VS2017) ### Generation of VS project with CMake, build and run on Windows - Run commands in command line in current directory (ensure that VS installed): ``` mkdir cmake-vs cd cmake-vs cmake .. cmake --build . ctest -C Debug -V ```thrift-0.16.0/compiler/cpp/tests/catch/000077500000000000000000000000001420101504100177025ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/tests/catch/catch.hpp000066400000000000000000014617741420101504100215210ustar00rootroot00000000000000/* * Catch v1.9.4 * Generated: 2017-05-16 13:51:55.506519 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // #included from: internal/catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC # pragma clang diagnostic ignored "-Wglobal-constructors" # pragma clang diagnostic ignored "-Wvariadic-macros" # pragma clang diagnostic ignored "-Wc99-extensions" # pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wparentheses" # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // #included from: internal/catch_notimplemented_exception.h #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED // #included from: catch_common.h #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED // #included from: catch_compiler_capabilities.h #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED // Detect a number of compiler features - mostly C++11/14 conformance - by compiler // The following features are defined: // // CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? // CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported // CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? // CATCH_CONFIG_CPP11_OVERRIDE : is override supported? // CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? // CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 #ifdef __cplusplus # if __cplusplus >= 201103L # define CATCH_CPP11_OR_GREATER # endif # if __cplusplus >= 201402L # define CATCH_CPP14_OR_GREATER # endif #endif #ifdef __clang__ # if __has_feature(cxx_nullptr) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # if __has_feature(cxx_noexcept) # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif # if defined(CATCH_CPP11_OR_GREATER) # define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) # define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ _Pragma( "clang diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) # endif #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined(__CYGWIN__) || defined(__QNX__) # if !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS # endif #endif //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Borland #ifdef __BORLANDC__ #endif // __BORLANDC__ //////////////////////////////////////////////////////////////////////////////// // EDG #ifdef __EDG_VERSION__ #endif // __EDG_VERSION__ //////////////////////////////////////////////////////////////////////////////// // Digital Mars #ifdef __DMC__ #endif // __DMC__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ # if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif // - otherwise more recent versions define __cplusplus >= 201103L // and will get picked up below #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER #define CATCH_INTERNAL_CONFIG_WINDOWS_SEH #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE #define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS #endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ ( defined __GNUC__ && __GNUC__ >= 3 ) || \ ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) #define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS #endif // Use __COUNTER__ if the compiler supports it #if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \ ( defined __clang__ && __clang_major__ >= 3 ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif //////////////////////////////////////////////////////////////////////////////// // C++ language feature support // catch all support for C++11 #if defined(CATCH_CPP11_OR_GREATER) # if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE # define CATCH_INTERNAL_CONFIG_CPP11_TUPLE # endif # ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) # define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) # define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) # define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) # define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS # endif #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured #if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NULLPTR #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NOEXCEPT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_GENERATED_METHODS #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_IS_ENUM #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_TUPLE #endif #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) # define CATCH_CONFIG_VARIADIC_MACROS #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_LONG_LONG #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_OVERRIDE #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif // Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for // analytics) because, at time of writing, __COUNTER__ is not properly handled by it. // This does not affect compilation #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__) # define CATCH_CONFIG_COUNTER #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_SHUFFLE #endif # if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_TYPE_TRAITS # endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. #if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #endif // noexcept support: #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) # define CATCH_NOEXCEPT noexcept # define CATCH_NOEXCEPT_IS(x) noexcept(x) #else # define CATCH_NOEXCEPT throw() # define CATCH_NOEXCEPT_IS(x) #endif // nullptr support #ifdef CATCH_CONFIG_CPP11_NULLPTR # define CATCH_NULL nullptr #else # define CATCH_NULL NULL #endif // override support #ifdef CATCH_CONFIG_CPP11_OVERRIDE # define CATCH_OVERRIDE override #else # define CATCH_OVERRIDE #endif // unique_ptr support #ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR # define CATCH_AUTO_PTR( T ) std::unique_ptr #else # define CATCH_AUTO_PTR( T ) std::auto_ptr #endif #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) #else # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) #include #include namespace Catch { struct IConfig; struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; #else NonCopyable( NonCopyable const& info ); NonCopyable& operator = ( NonCopyable const& ); #endif protected: NonCopyable() {} virtual ~NonCopyable(); }; class SafeBool { public: typedef void (SafeBool::*type)() const; static type makeSafe( bool value ) { return value ? &SafeBool::trueValue : 0; } private: void trueValue() const {} }; template inline void deleteAll( ContainerT& container ) { typename ContainerT::const_iterator it = container.begin(); typename ContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete *it; } template inline void deleteAllValues( AssociativeContainerT& container ) { typename AssociativeContainerT::const_iterator it = container.begin(); typename AssociativeContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete it->second; } bool startsWith( std::string const& s, std::string const& prefix ); bool startsWith( std::string const& s, char prefix ); bool endsWith( std::string const& s, std::string const& suffix ); bool endsWith( std::string const& s, char suffix ); bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); std::string trim( std::string const& str ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); struct pluralise { pluralise( std::size_t count, std::string const& label ); friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); std::size_t m_count; std::string m_label; }; struct SourceLineInfo { SourceLineInfo(); SourceLineInfo( char const* _file, std::size_t _line ); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SourceLineInfo(SourceLineInfo const& other) = default; SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; # endif bool empty() const; bool operator == ( SourceLineInfo const& other ) const; bool operator < ( SourceLineInfo const& other ) const; char const* file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // This is just here to avoid compiler warnings with macro constants and boolean literals inline bool isTrue( bool value ){ return value; } inline bool alwaysTrue() { return true; } inline bool alwaysFalse() { return false; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); void seedRng( IConfig const& config ); unsigned int rngSeed(); // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() { return std::string(); } }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); namespace Catch { class NotImplementedException : public std::exception { public: NotImplementedException( SourceLineInfo const& lineInfo ); NotImplementedException( NotImplementedException const& ) {} virtual ~NotImplementedException() CATCH_NOEXCEPT {} virtual const char* what() const CATCH_NOEXCEPT; private: std::string m_what; SourceLineInfo m_lineInfo; }; } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) // #included from: internal/catch_context.h #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED // #included from: catch_interfaces_generators.h #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED #include namespace Catch { struct IGeneratorInfo { virtual ~IGeneratorInfo(); virtual bool moveNext() = 0; virtual std::size_t getCurrentIndex() const = 0; }; struct IGeneratorsForTest { virtual ~IGeneratorsForTest(); virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; virtual bool moveNext() = 0; }; IGeneratorsForTest* createGeneratorsForTest(); } // end namespace Catch // #included from: catch_ptr.hpp #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { // An intrusive reference counting smart pointer. // T must implement addRef() and release() methods // typically implementing the IShared interface template class Ptr { public: Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); } Ptr( Ptr const& other ) : m_p( other.m_p ){ if( m_p ) m_p->addRef(); } ~Ptr(){ if( m_p ) m_p->release(); } void reset() { if( m_p ) m_p->release(); m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); swap( temp ); return *this; } Ptr& operator = ( Ptr const& other ){ Ptr temp( other ); swap( temp ); return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } bool operator !() const { return m_p == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; }; struct IShared : NonCopyable { virtual ~IShared(); virtual void addRef() const = 0; virtual void release() const = 0; }; template struct SharedImpl : T { SharedImpl() : m_rc( 0 ){} virtual void addRef() const { ++m_rc; } virtual void release() const { if( --m_rc == 0 ) delete this; } mutable unsigned int m_rc; }; } // end namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif namespace Catch { class TestCase; class Stream; struct IResultCapture; struct IRunner; struct IGeneratorsForTest; struct IConfig; struct IContext { virtual ~IContext(); virtual IResultCapture* getResultCapture() = 0; virtual IRunner* getRunner() = 0; virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; virtual bool advanceGeneratorsForCurrentTest() = 0; virtual Ptr getConfig() const = 0; }; struct IMutableContext : IContext { virtual ~IMutableContext(); virtual void setResultCapture( IResultCapture* resultCapture ) = 0; virtual void setRunner( IRunner* runner ) = 0; virtual void setConfig( Ptr const& config ) = 0; }; IContext& getCurrentContext(); IMutableContext& getCurrentMutableContext(); void cleanUpContext(); Stream createStream( std::string const& streamName ); } // #included from: internal/catch_test_registry.hpp #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED // #included from: catch_interfaces_testcase.h #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED #include namespace Catch { class TestSpec; struct ITestCase : IShared { virtual void invoke () const = 0; protected: virtual ~ITestCase(); }; class TestCase; struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } namespace Catch { template class MethodTestCase : public SharedImpl { public: MethodTestCase( void (C::*method)() ) : m_method( method ) {} virtual void invoke() const { C obj; (obj.*m_method)(); } private: virtual ~MethodTestCase() {} void (C::*m_method)(); }; typedef void(*TestFunction)(); struct NameAndDesc { NameAndDesc( const char* _name = "", const char* _description= "" ) : name( _name ), description( _description ) {} const char* name; const char* description; }; void registerTestCase ( ITestCase* testCase, char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ); struct AutoReg { AutoReg ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ); template AutoReg ( void (C::*method)(), char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { registerTestCase ( new MethodTestCase( method ), className, nameAndDesc, lineInfo ); } ~AutoReg(); private: AutoReg( AutoReg const& ); void operator= ( AutoReg const& ); }; void registerTestCaseFunction ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ); } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ \ struct TestName : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ \ struct TestCaseName : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestCaseName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #endif // #included from: internal/catch_capture.hpp #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED // #included from: catch_result_builder.h #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED // #included from: catch_result_type.h #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED namespace Catch { // ResultWas::OfType enum struct ResultWas { enum OfType { Unknown = -1, Ok = 0, Info = 1, Warning = 2, FailureBit = 0x10, ExpressionFailed = FailureBit | 1, ExplicitFailure = FailureBit | 2, Exception = 0x100 | FailureBit, ThrewException = Exception | 1, DidntThrowException = Exception | 2, FatalErrorCondition = 0x200 | FailureBit }; }; inline bool isOk( ResultWas::OfType resultType ) { return ( resultType & ResultWas::FailureBit ) == 0; } inline bool isJustInfo( int flags ) { return flags == ResultWas::Info; } // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { Normal = 0x01, ContinueOnFailure = 0x02, // Failures fail test, but execution continues FalseTest = 0x04, // Prefix expression with ! SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { return static_cast( static_cast( lhs ) | static_cast( rhs ) ); } inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch // #included from: catch_assertionresult.h #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED #include namespace Catch { struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; struct DecomposedExpression { virtual ~DecomposedExpression() {} virtual bool isBinaryExpression() const { return false; } virtual void reconstructExpression( std::string& dest ) const = 0; // Only simple binary comparisons can be decomposed. // If more complex check is required then wrap sub-expressions in parentheses. template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); private: DecomposedExpression& operator = (DecomposedExpression const&); }; struct AssertionInfo { AssertionInfo() {} AssertionInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, std::string const& _capturedExpression, ResultDisposition::Flags _resultDisposition ); std::string macroName; SourceLineInfo lineInfo; std::string capturedExpression; ResultDisposition::Flags resultDisposition; }; struct AssertionResultData { AssertionResultData() : decomposedExpression( CATCH_NULL ) , resultType( ResultWas::Unknown ) , negated( false ) , parenthesized( false ) {} void negate( bool parenthesize ) { negated = !negated; parenthesized = parenthesize; if( resultType == ResultWas::Ok ) resultType = ResultWas::ExpressionFailed; else if( resultType == ResultWas::ExpressionFailed ) resultType = ResultWas::Ok; } std::string const& reconstructExpression() const { if( decomposedExpression != CATCH_NULL ) { decomposedExpression->reconstructExpression( reconstructedExpression ); if( parenthesized ) { reconstructedExpression.insert( 0, 1, '(' ); reconstructedExpression.append( 1, ')' ); } if( negated ) { reconstructedExpression.insert( 0, 1, '!' ); } decomposedExpression = CATCH_NULL; } return reconstructedExpression; } mutable DecomposedExpression const* decomposedExpression; mutable std::string reconstructedExpression; std::string message; ResultWas::OfType resultType; bool negated; bool parenthesized; }; class AssertionResult { public: AssertionResult(); AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); ~AssertionResult(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionResult( AssertionResult const& ) = default; AssertionResult( AssertionResult && ) = default; AssertionResult& operator = ( AssertionResult const& ) = default; AssertionResult& operator = ( AssertionResult && ) = default; # endif bool isOk() const; bool succeeded() const; ResultWas::OfType getResultType() const; bool hasExpression() const; bool hasMessage() const; std::string getExpression() const; std::string getExpressionInMacro() const; bool hasExpandedExpression() const; std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; std::string getTestMacroName() const; void discardDecomposedExpression() const; void expandDecomposedExpression() const; protected: AssertionInfo m_info; AssertionResultData m_resultData; }; } // end namespace Catch // #included from: catch_matchers.hpp #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED namespace Catch { namespace Matchers { namespace Impl { template struct MatchAllOf; template struct MatchAnyOf; template struct MatchNotOf; class MatcherUntypedBase { public: std::string toString() const { if( m_cachedToString.empty() ) m_cachedToString = describe(); return m_cachedToString; } protected: virtual ~MatcherUntypedBase(); virtual std::string describe() const = 0; mutable std::string m_cachedToString; private: MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); }; template struct MatcherMethod { virtual bool match( ObjectT const& arg ) const = 0; }; template struct MatcherMethod { virtual bool match( PtrT* arg ) const = 0; }; template struct MatcherBase : MatcherUntypedBase, MatcherMethod { MatchAllOf operator && ( MatcherBase const& other ) const; MatchAnyOf operator || ( MatcherBase const& other ) const; MatchNotOf operator ! () const; }; template struct MatchAllOf : MatcherBase { virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if (!m_matchers[i]->match(arg)) return false; } return true; } virtual std::string describe() const CATCH_OVERRIDE { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) description += " and "; description += m_matchers[i]->toString(); } description += " )"; return description; } MatchAllOf& operator && ( MatcherBase const& other ) { m_matchers.push_back( &other ); return *this; } std::vector const*> m_matchers; }; template struct MatchAnyOf : MatcherBase { virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if (m_matchers[i]->match(arg)) return true; } return false; } virtual std::string describe() const CATCH_OVERRIDE { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) description += " or "; description += m_matchers[i]->toString(); } description += " )"; return description; } MatchAnyOf& operator || ( MatcherBase const& other ) { m_matchers.push_back( &other ); return *this; } std::vector const*> m_matchers; }; template struct MatchNotOf : MatcherBase { MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { return !m_underlyingMatcher.match( arg ); } virtual std::string describe() const CATCH_OVERRIDE { return "not " + m_underlyingMatcher.toString(); } MatcherBase const& m_underlyingMatcher; }; template MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { return MatchAllOf() && *this && other; } template MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { return MatchAnyOf() || *this || other; } template MatchNotOf MatcherBase::operator ! () const { return MatchNotOf( *this ); } } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred // - deprecated: prefer ||, && and ! template inline Impl::MatchNotOf Not( Impl::MatcherBase const& underlyingMatcher ) { return Impl::MatchNotOf( underlyingMatcher ); } template inline Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { return Impl::MatchAllOf() && m1 && m2; } template inline Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { return Impl::MatchAllOf() && m1 && m2 && m3; } template inline Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { return Impl::MatchAnyOf() || m1 || m2; } template inline Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { return Impl::MatchAnyOf() || m1 || m2 || m3; } } // namespace Matchers using namespace Matchers; using Matchers::Impl::MatcherBase; } // namespace Catch namespace Catch { struct TestFailureException{}; template class ExpressionLhs; struct CopyableStream { CopyableStream() {} CopyableStream( CopyableStream const& other ) { oss << other.oss.str(); } CopyableStream& operator=( CopyableStream const& other ) { oss.str(std::string()); oss << other.oss.str(); return *this; } std::ostringstream oss; }; class ResultBuilder : public DecomposedExpression { public: ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg = "" ); ~ResultBuilder(); template ExpressionLhs operator <= ( T const& operand ); ExpressionLhs operator <= ( bool value ); template ResultBuilder& operator << ( T const& value ) { m_stream.oss << value; return *this; } ResultBuilder& setResultType( ResultWas::OfType result ); ResultBuilder& setResultType( bool result ); void endExpression( DecomposedExpression const& expr ); virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; AssertionResult build() const; AssertionResult build( DecomposedExpression const& expr ) const; void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); void captureExpectedException( std::string const& expectedMessage ); void captureExpectedException( Matchers::Impl::MatcherBase const& matcher ); void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; template void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); void setExceptionGuard(); void unsetExceptionGuard(); private: AssertionInfo m_assertionInfo; AssertionResultData m_data; CopyableStream m_stream; bool m_shouldDebugBreak; bool m_shouldThrow; bool m_guardException; }; } // namespace Catch // Include after due to circular dependency: // #included from: catch_expression_lhs.hpp #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED // #included from: catch_evaluate.hpp #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #endif #include namespace Catch { namespace Internal { enum Operator { IsEqualTo, IsNotEqualTo, IsLessThan, IsGreaterThan, IsLessThanOrEqualTo, IsGreaterThanOrEqualTo }; template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; template inline T& opCast(T const& t) { return const_cast(t); } // nullptr_t support based on pull request #154 from Konstantin Baumann #ifdef CATCH_CONFIG_CPP11_NULLPTR inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } #endif // CATCH_CONFIG_CPP11_NULLPTR // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template class Evaluator{}; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs) { return bool( opCast( lhs ) == opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) != opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) < opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) > opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) >= opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) <= opCast( rhs ) ); } }; template bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // This level of indirection allows us to specialise for integer types // to avoid signed/ unsigned warnings // "base" overload template bool compare( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // unsigned X to int template bool compare( unsigned int lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // unsigned X to long template bool compare( unsigned int lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // int to unsigned X template bool compare( int lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // long to unsigned X template bool compare( long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long (when comparing against NULL) template bool compare( long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } // pointer to int (when comparing against NULL) template bool compare( int lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, int rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } #ifdef CATCH_CONFIG_CPP11_LONG_LONG // long long to unsigned X template bool compare( long long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned long long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // unsigned long long to X template bool compare( unsigned long long lhs, int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, long long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long long (when comparing against NULL) template bool compare( long long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, long long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } #endif // CATCH_CONFIG_CPP11_LONG_LONG #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR } // end of namespace Internal } // end of namespace Catch #ifdef _MSC_VER #pragma warning(pop) #endif // #included from: catch_tostring.h #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED #include #include #include #include #include #ifdef __OBJC__ // #included from: catch_objc_arc.hpp #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED #import #ifdef __has_feature #define CATCH_ARC_ENABLED __has_feature(objc_arc) #else #define CATCH_ARC_ENABLED 0 #endif void arcSafeRelease( NSObject* obj ); id performOptionalSelector( id obj, SEL sel ); #if !CATCH_ARC_ENABLED inline void arcSafeRelease( NSObject* obj ) { [obj release]; } inline id performOptionalSelector( id obj, SEL sel ) { if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; return nil; } #define CATCH_UNSAFE_UNRETAINED #define CATCH_ARC_STRONG #else inline void arcSafeRelease( NSObject* ){} inline id performOptionalSelector( id obj, SEL sel ) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" #endif if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; #ifdef __clang__ #pragma clang diagnostic pop #endif return nil; } #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained #define CATCH_ARC_STRONG __strong #endif #endif #ifdef CATCH_CONFIG_CPP11_TUPLE #include #endif #ifdef CATCH_CONFIG_CPP11_IS_ENUM #include #endif namespace Catch { // Why we're here. template std::string toString( T const& value ); // Built in overloads std::string toString( std::string const& value ); std::string toString( std::wstring const& value ); std::string toString( const char* const value ); std::string toString( char* const value ); std::string toString( const wchar_t* const value ); std::string toString( wchar_t* const value ); std::string toString( int value ); std::string toString( unsigned long value ); std::string toString( unsigned int value ); std::string toString( const double value ); std::string toString( const float value ); std::string toString( bool value ); std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); #ifdef CATCH_CONFIG_CPP11_LONG_LONG std::string toString( long long value ); std::string toString( unsigned long long value ); #endif #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ); std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); std::string toString( NSObject* const& nsObject ); #endif namespace Detail { extern const std::string unprintableString; #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) struct BorgType { template BorgType( T const& ); }; struct TrueType { char sizer[1]; }; struct FalseType { char sizer[2]; }; TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); FalseType operator<<( std::ostream const&, BorgType const& ); template struct IsStreamInsertable { static std::ostream &s; static T const&t; enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; #else template class IsStreamInsertable { template static auto test(int) -> decltype( std::declval() << std::declval(), std::true_type() ); template static auto test(...) -> std::false_type; public: static const bool value = decltype(test(0))::value; }; #endif #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template::value > struct EnumStringMaker { static std::string convert( T const& ) { return unprintableString; } }; template struct EnumStringMaker { static std::string convert( T const& v ) { return ::Catch::toString( static_cast::type>(v) ); } }; #endif template struct StringMakerBase { #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template static std::string convert( T const& v ) { return EnumStringMaker::convert( v ); } #else template static std::string convert( T const& ) { return unprintableString; } #endif }; template<> struct StringMakerBase { template static std::string convert( T const& _value ) { std::ostringstream oss; oss << _value; return oss.str(); } }; std::string rawMemoryToString( const void *object, std::size_t size ); template inline std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } } // end namespace Detail template struct StringMaker : Detail::StringMakerBase::value> {}; template struct StringMaker { template static std::string convert( U* p ) { if( !p ) return "NULL"; else return Detail::rawMemoryToString( p ); } }; template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) return "NULL"; else return Detail::rawMemoryToString( p ); } }; namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ); } //template //struct StringMaker > { // static std::string convert( std::vector const& v ) { // return Detail::rangeToString( v.begin(), v.end() ); // } //}; template std::string toString( std::vector const& v ) { return Detail::rangeToString( v.begin(), v.end() ); } #ifdef CATCH_CONFIG_CPP11_TUPLE // toString for tuples namespace TupleDetail { template< typename Tuple, std::size_t N = 0, bool = (N < std::tuple_size::value) > struct ElementPrinter { static void print( const Tuple& tuple, std::ostream& os ) { os << ( N ? ", " : " " ) << Catch::toString(std::get(tuple)); ElementPrinter::print(tuple,os); } }; template< typename Tuple, std::size_t N > struct ElementPrinter { static void print( const Tuple&, std::ostream& ) {} }; } template struct StringMaker> { static std::string convert( const std::tuple& tuple ) { std::ostringstream os; os << '{'; TupleDetail::ElementPrinter>::print( tuple, os ); os << " }"; return os.str(); } }; #endif // CATCH_CONFIG_CPP11_TUPLE namespace Detail { template std::string makeString( T const& value ) { return StringMaker::convert( value ); } } // end namespace Detail /// \brief converts any type to a string /// /// The default template forwards on to ostringstream - except when an /// ostringstream overload does not exist - in which case it attempts to detect /// that and writes {?}. /// Overload (not specialise) this template for custom typs that you don't want /// to provide an ostream overload for. template std::string toString( T const& value ) { return StringMaker::convert( value ); } namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ) { std::ostringstream oss; oss << "{ "; if( first != last ) { oss << Catch::toString( *first ); for( ++first ; first != last ; ++first ) oss << ", " << Catch::toString( *first ); } oss << " }"; return oss.str(); } } } // end namespace Catch namespace Catch { template class BinaryExpression; template class MatchExpression; // Wraps the LHS of an expression and overloads comparison operators // for also capturing those and RHS (if any) template class ExpressionLhs : public DecomposedExpression { public: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} ExpressionLhs& operator = ( const ExpressionLhs& ); template BinaryExpression operator == ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator != ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator < ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator > ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator <= ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator >= ( RhsT const& rhs ) { return captureExpression( rhs ); } BinaryExpression operator == ( bool rhs ) { return captureExpression( rhs ); } BinaryExpression operator != ( bool rhs ) { return captureExpression( rhs ); } void endExpression() { m_truthy = m_lhs ? true : false; m_rb .setResultType( m_truthy ) .endExpression( *this ); } virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { dest = Catch::toString( m_truthy ); } private: template BinaryExpression captureExpression( RhsT& rhs ) const { return BinaryExpression( m_rb, m_lhs, rhs ); } template BinaryExpression captureExpression( bool rhs ) const { return BinaryExpression( m_rb, m_lhs, rhs ); } private: ResultBuilder& m_rb; T m_lhs; bool m_truthy; }; template class BinaryExpression : public DecomposedExpression { public: BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} BinaryExpression& operator = ( BinaryExpression& ); void endExpression() const { m_rb .setResultType( Internal::compare( m_lhs, m_rhs ) ) .endExpression( *this ); } virtual bool isBinaryExpression() const CATCH_OVERRIDE { return true; } virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { std::string lhs = Catch::toString( m_lhs ); std::string rhs = Catch::toString( m_rhs ); char delim = lhs.size() + rhs.size() < 40 && lhs.find('\n') == std::string::npos && rhs.find('\n') == std::string::npos ? ' ' : '\n'; dest.reserve( 7 + lhs.size() + rhs.size() ); // 2 for spaces around operator // 2 for operator // 2 for parentheses (conditionally added later) // 1 for negation (conditionally added later) dest = lhs; dest += delim; dest += Internal::OperatorTraits::getName(); dest += delim; dest += rhs; } private: ResultBuilder& m_rb; LhsT m_lhs; RhsT m_rhs; }; template class MatchExpression : public DecomposedExpression { public: MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} virtual bool isBinaryExpression() const CATCH_OVERRIDE { return true; } virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { std::string matcherAsString = m_matcher.toString(); dest = Catch::toString( m_arg ); dest += ' '; if( matcherAsString == Detail::unprintableString ) dest += m_matcherString; else dest += matcherAsString; } private: ArgT m_arg; MatcherT m_matcher; char const* m_matcherString; }; } // end namespace Catch namespace Catch { template inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { return ExpressionLhs( *this, value ); } template inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ) { MatchExpression expr( arg, matcher, matcherString ); setResultType( matcher.match( arg ) ); endExpression( expr ); } } // namespace Catch // #included from: catch_message.h #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED #include namespace Catch { struct MessageInfo { MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ); std::string macroName; SourceLineInfo lineInfo; ResultWas::OfType type; std::string message; unsigned int sequence; bool operator == ( MessageInfo const& other ) const { return sequence == other.sequence; } bool operator < ( MessageInfo const& other ) const { return sequence < other.sequence; } private: static unsigned int globalCount; }; struct MessageBuilder { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ) : m_info( macroName, lineInfo, type ) {} template MessageBuilder& operator << ( T const& value ) { m_stream << value; return *this; } MessageInfo m_info; std::ostringstream m_stream; }; class ScopedMessage { public: ScopedMessage( MessageBuilder const& builder ); ScopedMessage( ScopedMessage const& other ); ~ScopedMessage(); MessageInfo m_info; }; } // end namespace Catch // #included from: catch_interfaces_capture.h #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #include namespace Catch { class TestCase; class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; struct IResultCapture { virtual ~IResultCapture(); virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; virtual void exceptionEarlyReported() = 0; virtual void handleFatalErrorCondition( std::string const& message ) = 0; }; IResultCapture& getResultCapture(); } // #included from: catch_debugger.h #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED // #included from: catch_platform.h #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) # define CATCH_PLATFORM_MAC #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) # define CATCH_PLATFORM_IPHONE #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) # define CATCH_PLATFORM_WINDOWS # if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) # define CATCH_DEFINES_NOMINMAX # endif # if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) # define CATCH_DEFINES_WIN32_LEAN_AND_MEAN # endif #endif #include namespace Catch{ bool isDebuggerActive(); void writeToDebugConsole( std::string const& text ); } #ifdef CATCH_PLATFORM_MAC // The following code snippet based on: // http://cocoawithlove.com/2008/03/break-into-debugger.html #if defined(__ppc64__) || defined(__ppc__) #define CATCH_TRAP() \ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ : : : "memory","r0","r3","r4" ) #else #define CATCH_TRAP() __asm__("int $3\n" : : ) #endif #elif defined(CATCH_PLATFORM_LINUX) // If we can use inline assembler, do it because this allows us to break // directly at the location of the failing check instead of breaking inside // raise() called from it, i.e. one stack frame below. #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) #define CATCH_TRAP() asm volatile ("int $3") #else // Fall back to the generic way. #include #define CATCH_TRAP() raise(SIGTRAP) #endif #elif defined(_MSC_VER) #define CATCH_TRAP() __debugbreak() #elif defined(__MINGW32__) extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #define CATCH_TRAP() DebugBreak() #endif #ifdef CATCH_TRAP #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } #else #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); #endif // #included from: catch_interfaces_runner.h #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED namespace Catch { class TestCase; struct IRunner { virtual ~IRunner(); virtual bool aborting() const = 0; }; } #if defined(CATCH_CONFIG_FAST_COMPILE) /////////////////////////////////////////////////////////////////////////////// // We can speedup compilation significantly by breaking into debugger lower in // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER // macro in each assertion #define INTERNAL_CATCH_REACT( resultBuilder ) \ resultBuilder.react(); /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. // This can potentially cause false negative, if the test code catches // the exception before it propagates back up to the runner. #define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ __catchResult.setExceptionGuard(); \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ ( __catchResult <= expr ).endExpression(); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ __catchResult.unsetExceptionGuard(); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. #define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ __catchResult.setExceptionGuard(); \ __catchResult.captureMatch( arg, matcher, #matcher ); \ __catchResult.unsetExceptionGuard(); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #else /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. // This needs to be done as a macro so the debugger will stop in the user // source code rather than in Catch library code #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ resultBuilder.react(); #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ ( __catchResult <= expr ).endExpression(); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ if( Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ if( !Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ if( __catchResult.allowThrows() ) \ try { \ static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( exceptionType ) { \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #else #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << log + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ try { \ __catchResult.captureMatch( arg, matcher, #matcher ); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) // #included from: internal/catch_section.h #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED // #included from: catch_section_info.h #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct Counts { Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} Counts operator - ( Counts const& other ) const { Counts diff; diff.passed = passed - other.passed; diff.failed = failed - other.failed; diff.failedButOk = failedButOk - other.failedButOk; return diff; } Counts& operator += ( Counts const& other ) { passed += other.passed; failed += other.failed; failedButOk += other.failedButOk; return *this; } std::size_t total() const { return passed + failed + failedButOk; } bool allPassed() const { return failed == 0 && failedButOk == 0; } bool allOk() const { return failed == 0; } std::size_t passed; std::size_t failed; std::size_t failedButOk; }; struct Totals { Totals operator - ( Totals const& other ) const { Totals diff; diff.assertions = assertions - other.assertions; diff.testCases = testCases - other.testCases; return diff; } Totals delta( Totals const& prevTotals ) const { Totals diff = *this - prevTotals; if( diff.assertions.failed > 0 ) ++diff.testCases.failed; else if( diff.assertions.failedButOk > 0 ) ++diff.testCases.failedButOk; else ++diff.testCases.passed; return diff; } Totals& operator += ( Totals const& other ) { assertions += other.assertions; testCases += other.testCases; return *this; } Counts assertions; Counts testCases; }; } #include namespace Catch { struct SectionInfo { SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description = std::string() ); std::string name; std::string description; SourceLineInfo lineInfo; }; struct SectionEndInfo { SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) {} SectionInfo sectionInfo; Counts prevAssertions; double durationInSeconds; }; } // end namespace Catch // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED #ifdef _MSC_VER namespace Catch { typedef unsigned long long UInt64; } #else #include namespace Catch { typedef uint64_t UInt64; } #endif namespace Catch { class Timer { public: Timer() : m_ticks( 0 ) {} void start(); unsigned int getElapsedMicroseconds() const; unsigned int getElapsedMilliseconds() const; double getElapsedSeconds() const; private: UInt64 m_ticks; }; } // namespace Catch #include namespace Catch { class Section : NonCopyable { public: Section( SectionInfo const& info ); ~Section(); // This indicates whether the section should be executed or not operator bool() const; private: SectionInfo m_info; std::string m_name; Counts m_assertions; bool m_sectionIncluded; Timer m_timer; }; } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_SECTION( ... ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) #else #define INTERNAL_CATCH_SECTION( name, desc ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) #endif // #included from: internal/catch_generators.hpp #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED #include #include #include namespace Catch { template struct IGenerator { virtual ~IGenerator() {} virtual T getValue( std::size_t index ) const = 0; virtual std::size_t size () const = 0; }; template class BetweenGenerator : public IGenerator { public: BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} virtual T getValue( std::size_t index ) const { return m_from+static_cast( index ); } virtual std::size_t size() const { return static_cast( 1+m_to-m_from ); } private: T m_from; T m_to; }; template class ValuesGenerator : public IGenerator { public: ValuesGenerator(){} void add( T value ) { m_values.push_back( value ); } virtual T getValue( std::size_t index ) const { return m_values[index]; } virtual std::size_t size() const { return m_values.size(); } private: std::vector m_values; }; template class CompositeGenerator { public: CompositeGenerator() : m_totalSize( 0 ) {} // *** Move semantics, similar to auto_ptr *** CompositeGenerator( CompositeGenerator& other ) : m_fileInfo( other.m_fileInfo ), m_totalSize( 0 ) { move( other ); } CompositeGenerator& setFileInfo( const char* fileInfo ) { m_fileInfo = fileInfo; return *this; } ~CompositeGenerator() { deleteAll( m_composed ); } operator T () const { size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); typename std::vector*>::const_iterator it = m_composed.begin(); typename std::vector*>::const_iterator itEnd = m_composed.end(); for( size_t index = 0; it != itEnd; ++it ) { const IGenerator* generator = *it; if( overallIndex >= index && overallIndex < index + generator->size() ) { return generator->getValue( overallIndex-index ); } index += generator->size(); } CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so } void add( const IGenerator* generator ) { m_totalSize += generator->size(); m_composed.push_back( generator ); } CompositeGenerator& then( CompositeGenerator& other ) { move( other ); return *this; } CompositeGenerator& then( T value ) { ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( value ); add( valuesGen ); return *this; } private: void move( CompositeGenerator& other ) { m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); m_totalSize += other.m_totalSize; other.m_composed.clear(); } std::vector*> m_composed; std::string m_fileInfo; size_t m_totalSize; }; namespace Generators { template CompositeGenerator between( T from, T to ) { CompositeGenerator generators; generators.add( new BetweenGenerator( from, to ) ); return generators; } template CompositeGenerator values( T val1, T val2 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3 ){ CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3, T val4 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); valuesGen->add( val4 ); generators.add( valuesGen ); return generators; } } // end namespace Generators using namespace Generators; } // end namespace Catch #define INTERNAL_CATCH_LINESTR2( line ) #line #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) // #included from: internal/catch_interfaces_exception.h #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include #include // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #include namespace Catch { class TestCase; struct ITestCaseRegistry; struct IExceptionTranslatorRegistry; struct IExceptionTranslator; struct IReporterRegistry; struct IReporterFactory; struct ITagAliasRegistry; struct IRegistryHub { virtual ~IRegistryHub(); virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; }; IRegistryHub& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); } namespace Catch { typedef std::string(*exceptionTranslateFunction)(); struct IExceptionTranslator; typedef std::vector ExceptionTranslators; struct IExceptionTranslator { virtual ~IExceptionTranslator(); virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { virtual ~IExceptionTranslatorRegistry(); virtual std::string translateActiveException() const = 0; }; class ExceptionTranslatorRegistrar { template class ExceptionTranslator : public IExceptionTranslator { public: ExceptionTranslator( std::string(*translateFunction)( T& ) ) : m_translateFunction( translateFunction ) {} virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { if( it == itEnd ) throw; else return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); } } protected: std::string(*m_translateFunction)( T& ); }; public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { getMutableRegistryHub().registerTranslator ( new ExceptionTranslator( translateFunction ) ); } }; } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ static std::string translatorName( signature ); \ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // #included from: internal/catch_approx.hpp #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED #include #include #if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) #include #endif namespace Catch { namespace Detail { class Approx { public: explicit Approx ( double value ) : m_epsilon( std::numeric_limits::epsilon()*100 ), m_margin( 0.0 ), m_scale( 1.0 ), m_value( value ) {} Approx( Approx const& other ) : m_epsilon( other.m_epsilon ), m_margin( other.m_margin ), m_scale( other.m_scale ), m_value( other.m_value ) {} static Approx custom() { return Approx( 0 ); } #if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) template ::value>::type> Approx operator()( T value ) { Approx approx( static_cast(value) ); approx.epsilon( m_epsilon ); approx.margin( m_margin ); approx.scale( m_scale ); return approx; } template ::value>::type> explicit Approx( T value ): Approx(static_cast(value)) {} template ::value>::type> friend bool operator == ( const T& lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula auto lhs_v = double(lhs); bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); if (relativeOK) { return true; } return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin; } template ::value>::type> friend bool operator == ( Approx const& lhs, const T& rhs ) { return operator==( rhs, lhs ); } template ::value>::type> friend bool operator != ( T lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } template ::value>::type> friend bool operator != ( Approx const& lhs, T rhs ) { return !operator==( rhs, lhs ); } template ::value>::type> friend bool operator <= ( T lhs, Approx const& rhs ) { return double(lhs) < rhs.m_value || lhs == rhs; } template ::value>::type> friend bool operator <= ( Approx const& lhs, T rhs ) { return lhs.m_value < double(rhs) || lhs == rhs; } template ::value>::type> friend bool operator >= ( T lhs, Approx const& rhs ) { return double(lhs) > rhs.m_value || lhs == rhs; } template ::value>::type> friend bool operator >= ( Approx const& lhs, T rhs ) { return lhs.m_value > double(rhs) || lhs == rhs; } template ::value>::type> Approx& epsilon( T newEpsilon ) { m_epsilon = double(newEpsilon); return *this; } template ::value>::type> Approx& margin( T newMargin ) { m_margin = double(newMargin); return *this; } template ::value>::type> Approx& scale( T newScale ) { m_scale = double(newScale); return *this; } #else Approx operator()( double value ) { Approx approx( value ); approx.epsilon( m_epsilon ); approx.margin( m_margin ); approx.scale( m_scale ); return approx; } friend bool operator == ( double lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); if (relativeOK) { return true; } return std::fabs(lhs - rhs.m_value) < rhs.m_margin; } friend bool operator == ( Approx const& lhs, double rhs ) { return operator==( rhs, lhs ); } friend bool operator != ( double lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } friend bool operator != ( Approx const& lhs, double rhs ) { return !operator==( rhs, lhs ); } friend bool operator <= ( double lhs, Approx const& rhs ) { return lhs < rhs.m_value || lhs == rhs; } friend bool operator <= ( Approx const& lhs, double rhs ) { return lhs.m_value < rhs || lhs == rhs; } friend bool operator >= ( double lhs, Approx const& rhs ) { return lhs > rhs.m_value || lhs == rhs; } friend bool operator >= ( Approx const& lhs, double rhs ) { return lhs.m_value > rhs || lhs == rhs; } Approx& epsilon( double newEpsilon ) { m_epsilon = newEpsilon; return *this; } Approx& margin( double newMargin ) { m_margin = newMargin; return *this; } Approx& scale( double newScale ) { m_scale = newScale; return *this; } #endif std::string toString() const { std::ostringstream oss; oss << "Approx( " << Catch::toString( m_value ) << " )"; return oss.str(); } private: double m_epsilon; double m_margin; double m_scale; double m_value; }; } template<> inline std::string toString( Detail::Approx const& value ) { return value.toString(); } } // end namespace Catch // #included from: internal/catch_matchers_string.h #define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED namespace Catch { namespace Matchers { namespace StdString { struct CasedString { CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); std::string adjustString( std::string const& str ) const; std::string caseSensitivitySuffix() const; CaseSensitive::Choice m_caseSensitivity; std::string m_str; }; struct StringMatcherBase : MatcherBase { StringMatcherBase( std::string const& operation, CasedString const& comparator ); virtual std::string describe() const CATCH_OVERRIDE; CasedString m_comparator; std::string m_operation; }; struct EqualsMatcher : StringMatcherBase { EqualsMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct ContainsMatcher : StringMatcherBase { ContainsMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct StartsWithMatcher : StringMatcherBase { StartsWithMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct EndsWithMatcher : StringMatcherBase { EndsWithMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; } // namespace StdString // The following functions create the actual matcher objects. // This allows the types to be inferred StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); } // namespace Matchers } // namespace Catch // #included from: internal/catch_matchers_vector.h #define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED namespace Catch { namespace Matchers { namespace Vector { template struct ContainsElementMatcher : MatcherBase, T> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} bool match(std::vector const &v) const CATCH_OVERRIDE { return std::find(v.begin(), v.end(), m_comparator) != v.end(); } virtual std::string describe() const CATCH_OVERRIDE { return "Contains: " + Catch::toString( m_comparator ); } T const& m_comparator; }; template struct ContainsMatcher : MatcherBase, std::vector > { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} bool match(std::vector const &v) const CATCH_OVERRIDE { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; for (size_t i = 0; i < m_comparator.size(); ++i) if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end()) return false; return true; } virtual std::string describe() const CATCH_OVERRIDE { return "Contains: " + Catch::toString( m_comparator ); } std::vector const& m_comparator; }; template struct EqualsMatcher : MatcherBase, std::vector > { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} bool match(std::vector const &v) const CATCH_OVERRIDE { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly if (m_comparator.size() != v.size()) return false; for (size_t i = 0; i < v.size(); ++i) if (m_comparator[i] != v[i]) return false; return true; } virtual std::string describe() const CATCH_OVERRIDE { return "Equals: " + Catch::toString( m_comparator ); } std::vector const& m_comparator; }; } // namespace Vector // The following functions create the actual matcher objects. // This allows the types to be inferred template Vector::ContainsMatcher Contains( std::vector const& comparator ) { return Vector::ContainsMatcher( comparator ); } template Vector::ContainsElementMatcher VectorContains( T const& comparator ) { return Vector::ContainsElementMatcher( comparator ); } template Vector::EqualsMatcher Equals( std::vector const& comparator ) { return Vector::EqualsMatcher( comparator ); } } // namespace Matchers } // namespace Catch // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED // #included from: catch_tag_alias.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED #include namespace Catch { struct TagAlias { TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} std::string tag; SourceLineInfo lineInfo; }; struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } // #included from: catch_option.hpp #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED namespace Catch { // An optional type template class Option { public: Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { reset(); } Option& operator= ( Option const& _other ) { if( &_other != this ) { reset(); if( _other ) nullableValue = new( storage ) T( *_other ); } return *this; } Option& operator = ( T const& _value ) { reset(); nullableValue = new( storage ) T( _value ); return *this; } void reset() { if( nullableValue ) nullableValue->~T(); nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } T const& operator*() const { return *nullableValue; } T* operator->() { return nullableValue; } const T* operator->() const { return nullableValue; } T valueOr( T const& defaultValue ) const { return nullableValue ? *nullableValue : defaultValue; } bool some() const { return nullableValue != CATCH_NULL; } bool none() const { return nullableValue == CATCH_NULL; } bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } private: T *nullableValue; union { char storage[sizeof(T)]; // These are here to force alignment for the storage long double dummy1; void (*dummy2)(); long double dummy3; #ifdef CATCH_CONFIG_CPP11_LONG_LONG long long dummy4; #endif }; }; } // end namespace Catch namespace Catch { struct ITagAliasRegistry { virtual ~ITagAliasRegistry(); virtual Option find( std::string const& alias ) const = 0; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; static ITagAliasRegistry const& get(); }; } // end namespace Catch // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections // #included from: internal/catch_test_case_info.h #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED #include #include #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { struct ITestCase; struct TestCaseInfo { enum SpecialProperties{ None = 0, IsHidden = 1 << 1, ShouldFail = 1 << 2, MayFail = 1 << 3, Throws = 1 << 4, NonPortable = 1 << 5 }; TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ); TestCaseInfo( TestCaseInfo const& other ); friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); bool isHidden() const; bool throws() const; bool okToFail() const; bool expectedToFail() const; std::string name; std::string className; std::string description; std::set tags; std::set lcaseTags; std::string tagsAsString; SourceLineInfo lineInfo; SpecialProperties properties; }; class TestCase : public TestCaseInfo { public: TestCase( ITestCase* testCase, TestCaseInfo const& info ); TestCase( TestCase const& other ); TestCase withName( std::string const& _newName ) const; void invoke() const; TestCaseInfo const& getTestCaseInfo() const; void swap( TestCase& other ); bool operator == ( TestCase const& other ) const; bool operator < ( TestCase const& other ) const; TestCase& operator = ( TestCase const& other ); private: Ptr test; }; TestCase makeTestCase( ITestCase* testCase, std::string const& className, std::string const& name, std::string const& description, SourceLineInfo const& lineInfo ); } #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef __OBJC__ // #included from: internal/catch_objc.hpp #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED #import #include // NB. Any general catch headers included here must be included // in catch.hpp first to make sure they are included by the single // header for non obj-usage /////////////////////////////////////////////////////////////////////////////// // This protocol is really only here for (self) documenting purposes, since // all its methods are optional. @protocol OcFixture @optional -(void) setUp; -(void) tearDown; @end namespace Catch { class OcMethod : public SharedImpl { public: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} virtual void invoke() const { id obj = [[m_cls alloc] init]; performOptionalSelector( obj, @selector(setUp) ); performOptionalSelector( obj, m_sel ); performOptionalSelector( obj, @selector(tearDown) ); arcSafeRelease( obj ); } private: virtual ~OcMethod() {} Class m_cls; SEL m_sel; }; namespace Detail{ inline std::string getAnnotation( Class cls, std::string const& annotationName, std::string const& testCaseName ) { NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; SEL sel = NSSelectorFromString( selStr ); arcSafeRelease( selStr ); id value = performOptionalSelector( cls, sel ); if( value ) return [(NSString*)value UTF8String]; return ""; } } inline size_t registerTestMethods() { size_t noTestMethods = 0; int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); for( int c = 0; c < noClasses; c++ ) { Class cls = classes[c]; { u_int count; Method* methods = class_copyMethodList( cls, &count ); for( u_int m = 0; m < count ; m++ ) { SEL selector = method_getName(methods[m]); std::string methodName = sel_getName(selector); if( startsWith( methodName, "Catch_TestCase_" ) ) { std::string testCaseName = methodName.substr( 15 ); std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); noTestMethods++; } } free(methods); } } return noTestMethods; } namespace Matchers { namespace Impl { namespace NSStringMatchers { struct StringHolder : MatcherBase{ StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolder() { arcSafeRelease( m_substr ); } virtual bool match( NSString* arg ) const CATCH_OVERRIDE { return false; } NSString* m_substr; }; struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const CATCH_OVERRIDE { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } virtual std::string describe() const CATCH_OVERRIDE { return "equals string: " + Catch::toString( m_substr ); } }; struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } virtual std::string describe() const CATCH_OVERRIDE { return "contains string: " + Catch::toString( m_substr ); } }; struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } virtual std::string describe() const CATCH_OVERRIDE { return "starts with: " + Catch::toString( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } virtual std::string describe() const CATCH_OVERRIDE { return "ends with: " + Catch::toString( m_substr ); } }; } // namespace NSStringMatchers } // namespace Impl inline Impl::NSStringMatchers::Equals Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } inline Impl::NSStringMatchers::Contains Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } inline Impl::NSStringMatchers::StartsWith StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } inline Impl::NSStringMatchers::EndsWith EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } } // namespace Matchers using namespace Matchers; } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define OC_TEST_CASE( name, desc )\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ {\ return @ name; \ }\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ { \ return @ desc; \ } \ -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) #endif #ifdef CATCH_IMPL // !TBD: Move the leak detector code into a separate header #ifdef CATCH_CONFIG_WINDOWS_CRTDBG #include class LeakDetector { public: LeakDetector() { int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); flag |= _CRTDBG_LEAK_CHECK_DF; flag |= _CRTDBG_ALLOC_MEM_DF; _CrtSetDbgFlag(flag); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); // Change this to leaking allocation's number to break there _CrtSetBreakAlloc(-1); } }; #else class LeakDetector {}; #endif LeakDetector leakDetector; // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED // Collect all the implementation files together here // These are the equivalent of what would usually be cpp files #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #endif // #included from: ../catch_session.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED // #included from: catch_config.hpp #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED // #included from: catch_test_spec_parser.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: catch_test_spec.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: catch_wildcard_pattern.hpp #define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED #include namespace Catch { class WildcardPattern { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, WildcardAtEnd = 2, WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd }; public: WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_wildcard( NoWildcard ), m_pattern( adjustCase( pattern ) ) { if( startsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 1 ); m_wildcard = WildcardAtStart; } if( endsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); } } virtual ~WildcardPattern(); virtual bool matches( std::string const& str ) const { switch( m_wildcard ) { case NoWildcard: return m_pattern == adjustCase( str ); case WildcardAtStart: return endsWith( adjustCase( str ), m_pattern ); case WildcardAtEnd: return startsWith( adjustCase( str ), m_pattern ); case WildcardAtBothEnds: return contains( adjustCase( str ), m_pattern ); } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif throw std::logic_error( "Unknown enum" ); #ifdef __clang__ #pragma clang diagnostic pop #endif } private: std::string adjustCase( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } CaseSensitive::Choice m_caseSensitivity; WildcardPosition m_wildcard; std::string m_pattern; }; } #include #include namespace Catch { class TestSpec { struct Pattern : SharedImpl<> { virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { public: NamePattern( std::string const& name ) : m_wildcardPattern( toLower( name ), CaseSensitive::No ) {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} virtual ~TagPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); } private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} virtual ~ExcludedPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } private: Ptr m_underlyingPattern; }; struct Filter { std::vector > m_patterns; bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { if( !(*it)->matches( testCase ) ) return false; } return true; } }; public: bool hasFilters() const { return !m_filters.empty(); } bool matches( TestCaseInfo const& testCase ) const { // A TestSpec matches if any filter matches for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) if( it->matches( testCase ) ) return true; return false; } private: std::vector m_filters; friend class TestSpecParser; }; } #ifdef __clang__ #pragma clang diagnostic pop #endif namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag, EscapedName }; Mode m_mode; bool m_exclusion; std::size_t m_start, m_pos; std::string m_arg; std::vector m_escapeChars; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; ITagAliasRegistry const* m_tagAliases; public: TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} TestSpecParser& parse( std::string const& arg ) { m_mode = None; m_exclusion = false; m_start = std::string::npos; m_arg = m_tagAliases->expandAliases( arg ); m_escapeChars.clear(); for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) visitChar( m_arg[m_pos] ); if( m_mode == Name ) addPattern(); return *this; } TestSpec testSpec() { addFilter(); return m_testSpec; } private: void visitChar( char c ) { if( m_mode == None ) { switch( c ) { case ' ': return; case '~': m_exclusion = true; return; case '[': return startNewMode( Tag, ++m_pos ); case '"': return startNewMode( QuotedName, ++m_pos ); case '\\': return escape(); default: startNewMode( Name, m_pos ); break; } } if( m_mode == Name ) { if( c == ',' ) { addPattern(); addFilter(); } else if( c == '[' ) { if( subString() == "exclude:" ) m_exclusion = true; else addPattern(); startNewMode( Tag, ++m_pos ); } else if( c == '\\' ) escape(); } else if( m_mode == EscapedName ) m_mode = Name; else if( m_mode == QuotedName && c == '"' ) addPattern(); else if( m_mode == Tag && c == ']' ) addPattern(); } void startNewMode( Mode mode, std::size_t start ) { m_mode = mode; m_start = start; } void escape() { if( m_mode == None ) m_start = m_pos; m_mode = EscapedName; m_escapeChars.push_back( m_pos ); } std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } template void addPattern() { std::string token = subString(); for( size_t i = 0; i < m_escapeChars.size(); ++i ) token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); m_escapeChars.clear(); if( startsWith( token, "exclude:" ) ) { m_exclusion = true; token = token.substr( 8 ); } if( !token.empty() ) { Ptr pattern = new T( token ); if( m_exclusion ) pattern = new TestSpec::ExcludedPattern( pattern ); m_currentFilter.m_patterns.push_back( pattern ); } m_exclusion = false; m_mode = None; } void addFilter() { if( !m_currentFilter.m_patterns.empty() ) { m_testSpec.m_filters.push_back( m_currentFilter ); m_currentFilter = TestSpec::Filter(); } } }; inline TestSpec parseTestSpec( std::string const& arg ) { return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_interfaces_config.h #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED #include #include #include namespace Catch { struct Verbosity { enum Level { NoOutput = 0, Quiet, Normal }; }; struct WarnAbout { enum What { Nothing = 0x00, NoAssertions = 0x01 }; }; struct ShowDurations { enum OrNot { DefaultForReporter, Always, Never }; }; struct RunTests { enum InWhatOrder { InDeclarationOrder, InLexicographicalOrder, InRandomOrder }; }; struct UseColour { enum YesOrNo { Auto, Yes, No }; }; class TestSpec; struct IConfig : IShared { virtual ~IConfig(); virtual bool allowThrows() const = 0; virtual std::ostream& stream() const = 0; virtual std::string name() const = 0; virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; virtual bool warnAboutMissingAssertions() const = 0; virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; virtual TestSpec const& testSpec() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual UseColour::YesOrNo useColour() const = 0; virtual std::vector const& getSectionsToRun() const = 0; }; } // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED // #included from: catch_streambuf.h #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED #include namespace Catch { class StreamBufBase : public std::streambuf { public: virtual ~StreamBufBase() CATCH_NOEXCEPT; }; } #include #include #include #include namespace Catch { std::ostream& cout(); std::ostream& cerr(); struct IStream { virtual ~IStream() CATCH_NOEXCEPT; virtual std::ostream& stream() const = 0; }; class FileStream : public IStream { mutable std::ofstream m_ofs; public: FileStream( std::string const& filename ); virtual ~FileStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; class CoutStream : public IStream { mutable std::ostream m_os; public: CoutStream(); virtual ~CoutStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; class DebugOutStream : public IStream { CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); virtual ~DebugOutStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; } #include #include #include #include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 #endif namespace Catch { struct ConfigData { ConfigData() : listTests( false ), listTags( false ), listReporters( false ), listTestNamesOnly( false ), showSuccessfulTests( false ), shouldDebugBreak( false ), noThrow( false ), showHelp( false ), showInvisibles( false ), filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), showDurations( ShowDurations::DefaultForReporter ), runOrder( RunTests::InDeclarationOrder ), useColour( UseColour::Auto ) {} bool listTests; bool listTags; bool listReporters; bool listTestNamesOnly; bool showSuccessfulTests; bool shouldDebugBreak; bool noThrow; bool showHelp; bool showInvisibles; bool filenamesAsTags; int abortAfter; unsigned int rngSeed; Verbosity::Level verbosity; WarnAbout::What warnings; ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; UseColour::YesOrNo useColour; std::string outputFilename; std::string name; std::string processName; std::vector reporterNames; std::vector testsOrTags; std::vector sectionsToRun; }; class Config : public SharedImpl { private: Config( Config const& other ); Config& operator = ( Config const& other ); virtual void dummy(); public: Config() {} Config( ConfigData const& data ) : m_data( data ), m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) parser.parse( data.testsOrTags[i] ); m_testSpec = parser.testSpec(); } } virtual ~Config() {} std::string const& getFilename() const { return m_data.outputFilename ; } bool listTests() const { return m_data.listTests; } bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } bool listTags() const { return m_data.listTags; } bool listReporters() const { return m_data.listReporters; } std::string getProcessName() const { return m_data.processName; } std::vector const& getReporterNames() const { return m_data.reporterNames; } std::vector const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } bool showHelp() const { return m_data.showHelp; } // IConfig interface virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } private: IStream const* openStream() { if( m_data.outputFilename.empty() ) return new CoutStream(); else if( m_data.outputFilename[0] == '%' ) { if( m_data.outputFilename == "%debug" ) return new DebugOutStream(); else throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); } else return new FileStream( m_data.outputFilename ); } ConfigData m_data; CATCH_AUTO_PTR( IStream const ) m_stream; TestSpec m_testSpec; }; } // end namespace Catch // #included from: catch_clara.h #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED // Use Catch's value for console width (store Clara's off to the side, if present) #ifdef CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH #undef CLARA_CONFIG_CONSOLE_WIDTH #endif #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH // Declare Clara inside the Catch namespace #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { // #included from: ../external/clara.h // Version 0.0.2.4 // Only use header guard if we are not using an outer namespace #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) #ifndef STITCH_CLARA_OPEN_NAMESPACE #define TWOBLUECUBES_CLARA_H_INCLUDED #define STITCH_CLARA_OPEN_NAMESPACE #define STITCH_CLARA_CLOSE_NAMESPACE #else #define STITCH_CLARA_CLOSE_NAMESPACE } #endif #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE // ----------- #included from tbc_text_format.h ----------- // Only use header guard if we are not using an outer namespace #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE #define TBC_TEXT_FORMAT_H_INCLUDED #endif #include #include #include #include #include // Use optional outer namespace #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ), tabChar( '\t' ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap char tabChar; // If this char is seen the indent is changed to current pos }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { std::string wrappableChars = " [({.,/|\\-"; std::size_t indent = _attr.initialIndent != std::string::npos ? _attr.initialIndent : _attr.indent; std::string remainder = _str; while( !remainder.empty() ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::size_t tabPos = std::string::npos; std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); std::size_t pos = remainder.find_first_of( '\n' ); if( pos <= width ) { width = pos; } pos = remainder.find_last_of( _attr.tabChar, width ); if( pos != std::string::npos ) { tabPos = pos; if( remainder[width] == '\n' ) width--; remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); } if( width == remainder.size() ) { spliceLine( indent, remainder, width ); } else if( remainder[width] == '\n' ) { spliceLine( indent, remainder, width ); if( width <= 1 || remainder.size() != 1 ) remainder = remainder.substr( 1 ); indent = _attr.indent; } else { pos = remainder.find_last_of( wrappableChars, width ); if( pos != std::string::npos && pos > 0 ) { spliceLine( indent, remainder, pos ); if( remainder[0] == ' ' ) remainder = remainder.substr( 1 ); } else { spliceLine( indent, remainder, width-1 ); lines.back() += "-"; } if( lines.size() == 1 ) indent = _attr.indent; if( tabPos != std::string::npos ) indent += tabPos; } } } void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); _remainder = _remainder.substr( _pos ); } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TBC_TEXT_FORMAT_H_INCLUDED // ----------- end of #include from tbc_text_format.h ----------- // ........... back in clara.h #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE // ----------- #included from clara_compilers.h ----------- #ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED #define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED // Detect a number of compiler features - mostly C++11/14 conformance - by compiler // The following features are defined: // // CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? // CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? // CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CLARA_CONFIG_CPP11_OVERRIDE : is override supported? // CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? // In general each macro has a _NO_ form // (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. // All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 #ifdef __clang__ #if __has_feature(cxx_nullptr) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #endif #if __has_feature(cxx_noexcept) #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #endif #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ #if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #endif // - otherwise more recent versions define __cplusplus >= 201103L // and will get picked up below #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER #if (_MSC_VER >= 1600) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // C++ language feature support // catch all support for C++11 #if defined(__cplusplus) && __cplusplus >= 201103L #define CLARA_CPP11_OR_GREATER #if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #endif #ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #endif #ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) #define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE #endif #if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) #define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured #if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_NULLPTR #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_NOEXCEPT #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_GENERATED_METHODS #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_OVERRIDE #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_UNIQUE_PTR #endif // noexcept support: #if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) #define CLARA_NOEXCEPT noexcept # define CLARA_NOEXCEPT_IS(x) noexcept(x) #else #define CLARA_NOEXCEPT throw() # define CLARA_NOEXCEPT_IS(x) #endif // nullptr support #ifdef CLARA_CONFIG_CPP11_NULLPTR #define CLARA_NULL nullptr #else #define CLARA_NULL NULL #endif // override support #ifdef CLARA_CONFIG_CPP11_OVERRIDE #define CLARA_OVERRIDE override #else #define CLARA_OVERRIDE #endif // unique_ptr support #ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR # define CLARA_AUTO_PTR( T ) std::unique_ptr #else # define CLARA_AUTO_PTR( T ) std::auto_ptr #endif #endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED // ----------- end of #include from clara_compilers.h ----------- // ........... back in clara.h #include #include #include #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) #define CLARA_PLATFORM_WINDOWS #endif // Use optional outer namespace #ifdef STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE #endif namespace Clara { struct UnpositionalTag {}; extern UnpositionalTag _; #ifdef CLARA_CONFIG_MAIN UnpositionalTag _; #endif namespace Detail { #ifdef CLARA_CONSOLE_WIDTH const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif using namespace Tbc; inline bool startsWith( std::string const& str, std::string const& prefix ) { return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; } template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct IsBool { static const bool value = false; }; template<> struct IsBool { static const bool value = true; }; template void convertInto( std::string const& _source, T& _dest ) { std::stringstream ss; ss << _source; ss >> _dest; if( ss.fail() ) throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); } inline void convertInto( std::string const& _source, std::string& _dest ) { _dest = _source; } char toLowerCh(char c) { return static_cast( std::tolower( c ) ); } inline void convertInto( std::string const& _source, bool& _dest ) { std::string sourceLC = _source; std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) _dest = true; else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) _dest = false; else throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } template struct IArgFunction { virtual ~IArgFunction() {} #ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS IArgFunction() = default; IArgFunction( IArgFunction const& ) = default; #endif virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual bool takesArg() const = 0; virtual IArgFunction* clone() const = 0; }; template class BoundArgFunction { public: BoundArgFunction() : functionObj( CLARA_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; delete functionObj; functionObj = newFunctionObj; return *this; } ~BoundArgFunction() { delete functionObj; } void set( ConfigT& config, std::string const& value ) const { functionObj->set( config, value ); } bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { return functionObj != CLARA_NULL; } private: IArgFunction* functionObj; }; template struct NullBinder : IArgFunction{ virtual void set( C&, std::string const& ) const {} virtual bool takesArg() const { return true; } virtual IArgFunction* clone() const { return new NullBinder( *this ); } }; template struct BoundDataMember : IArgFunction{ BoundDataMember( M C::* _member ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { convertInto( stringValue, p.*member ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } M C::* member; }; template struct BoundUnaryMethod : IArgFunction{ BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); (p.*member)( value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } void (C::*member)( M ); }; template struct BoundNullaryMethod : IArgFunction{ BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) (p.*member)(); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } void (C::*member)(); }; template struct BoundUnaryFunction : IArgFunction{ BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) function( obj ); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } void (*function)( C& ); }; template struct BoundBinaryFunction : IArgFunction{ BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); function( obj, value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } void (*function)( C&, T ); }; } // namespace Detail inline std::vector argsToVector( int argc, char const* const* const argv ) { std::vector args( static_cast( argc ) ); for( std::size_t i = 0; i < static_cast( argc ); ++i ) args[i] = argv[i]; return args; } class Parser { enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; Mode mode; std::size_t from; bool inQuotes; public: struct Token { enum Type { Positional, ShortOpt, LongOpt }; Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} Type type; std::string data; }; Parser() : mode( None ), from( 0 ), inQuotes( false ){} void parseIntoTokens( std::vector const& args, std::vector& tokens ) { const std::string doubleDash = "--"; for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) parseIntoTokens( args[i], tokens); } void parseIntoTokens( std::string const& arg, std::vector& tokens ) { for( std::size_t i = 0; i < arg.size(); ++i ) { char c = arg[i]; if( c == '"' ) inQuotes = !inQuotes; mode = handleMode( i, c, arg, tokens ); } mode = handleMode( arg.size(), '\0', arg, tokens ); } Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { switch( mode ) { case None: return handleNone( i, c ); case MaybeShortOpt: return handleMaybeShortOpt( i, c ); case ShortOpt: case LongOpt: case SlashOpt: return handleOpt( i, c, arg, tokens ); case Positional: return handlePositional( i, c, arg, tokens ); default: throw std::logic_error( "Unknown mode" ); } } Mode handleNone( std::size_t i, char c ) { if( inQuotes ) { from = i; return Positional; } switch( c ) { case '-': return MaybeShortOpt; #ifdef CLARA_PLATFORM_WINDOWS case '/': from = i+1; return SlashOpt; #endif default: from = i; return Positional; } } Mode handleMaybeShortOpt( std::size_t i, char c ) { switch( c ) { case '-': from = i+1; return LongOpt; default: from = i; return ShortOpt; } } Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) return mode; std::string optName = arg.substr( from, i-from ); if( mode == ShortOpt ) for( std::size_t j = 0; j < optName.size(); ++j ) tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); else if( mode == SlashOpt && optName.size() == 1 ) tokens.push_back( Token( Token::ShortOpt, optName ) ); else tokens.push_back( Token( Token::LongOpt, optName ) ); return None; } Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) return mode; std::string data = arg.substr( from, i-from ); tokens.push_back( Token( Token::Positional, data ) ); return None; } }; template struct CommonArgProperties { CommonArgProperties() {} CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} Detail::BoundArgFunction boundField; std::string description; std::string detail; std::string placeholder; // Only value if boundField takes an arg bool takesArg() const { return !placeholder.empty(); } void validate() const { if( !boundField.isSet() ) throw std::logic_error( "option not bound" ); } }; struct OptionArgProperties { std::vector shortNames; std::string longName; bool hasShortName( std::string const& shortName ) const { return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); } bool hasLongName( std::string const& _longName ) const { return _longName == longName; } }; struct PositionalArgProperties { PositionalArgProperties() : position( -1 ) {} int position; // -1 means non-positional (floating) bool isFixedPositional() const { return position != -1; } }; template class CommandLine { struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { Arg() {} Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} using CommonArgProperties::placeholder; // !TBD std::string dbgName() const { if( !longName.empty() ) return "--" + longName; if( !shortNames.empty() ) return "-" + shortNames[0]; return "positional args"; } std::string commands() const { std::ostringstream oss; bool first = true; std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); for(; it != itEnd; ++it ) { if( first ) first = false; else oss << ", "; oss << "-" << *it; } if( !longName.empty() ) { if( !first ) oss << ", "; oss << "--" << longName; } if( !placeholder.empty() ) oss << " <" << placeholder << ">"; return oss.str(); } }; typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { if( optName.empty() ) return; if( Detail::startsWith( optName, "--" ) ) { if( !arg.longName.empty() ) throw std::logic_error( "Only one long opt may be specified. '" + arg.longName + "' already specified, now attempting to add '" + optName + "'" ); arg.longName = optName.substr( 2 ); } else if( Detail::startsWith( optName, "-" ) ) arg.shortNames.push_back( optName.substr( 1 ) ); else throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); } friend void setPositionalArg( Arg& arg, int position ) { arg.position = position; } class ArgBuilder { public: ArgBuilder( Arg* arg ) : m_arg( arg ) {} // Bind a non-boolean data member (requires placeholder string) template void bind( M C::* field, std::string const& placeholder ) { m_arg->boundField = new Detail::BoundDataMember( field ); m_arg->placeholder = placeholder; } // Bind a boolean data member (no placeholder required) template void bind( bool C::* field ) { m_arg->boundField = new Detail::BoundDataMember( field ); } // Bind a method taking a single, non-boolean argument (requires a placeholder string) template void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); m_arg->placeholder = placeholder; } // Bind a method taking a single, boolean argument (no placeholder string required) template void bind( void (C::* unaryMethod)( bool ) ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); } // Bind a method that takes no arguments (will be called if opt is present) template void bind( void (C::* nullaryMethod)() ) { m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); } // Bind a free function taking a single argument - the object to operate on (no placeholder string required) template void bind( void (* unaryFunction)( C& ) ) { m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); } // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) template void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); m_arg->placeholder = placeholder; } ArgBuilder& describe( std::string const& description ) { m_arg->description = description; return *this; } ArgBuilder& detail( std::string const& detail ) { m_arg->detail = detail; return *this; } protected: Arg* m_arg; }; class OptBuilder : public ArgBuilder { public: OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} OptBuilder& operator[]( std::string const& optName ) { addOptName( *ArgBuilder::m_arg, optName ); return *this; } }; public: CommandLine() : m_boundProcessName( new Detail::NullBinder() ), m_highestSpecifiedArgPosition( 0 ), m_throwOnUnrecognisedTokens( false ) {} CommandLine( CommandLine const& other ) : m_boundProcessName( other.m_boundProcessName ), m_options ( other.m_options ), m_positionalArgs( other.m_positionalArgs ), m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) { if( other.m_floatingArg.get() ) m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); } CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { m_throwOnUnrecognisedTokens = shouldThrow; return *this; } OptBuilder operator[]( std::string const& optName ) { m_options.push_back( Arg() ); addOptName( m_options.back(), optName ); OptBuilder builder( &m_options.back() ); return builder; } ArgBuilder operator[]( int position ) { m_positionalArgs.insert( std::make_pair( position, Arg() ) ); if( position > m_highestSpecifiedArgPosition ) m_highestSpecifiedArgPosition = position; setPositionalArg( m_positionalArgs[position], position ); ArgBuilder builder( &m_positionalArgs[position] ); return builder; } // Invoke this with the _ instance ArgBuilder operator[]( UnpositionalTag ) { if( m_floatingArg.get() ) throw std::logic_error( "Only one unpositional argument can be added" ); m_floatingArg.reset( new Arg() ); ArgBuilder builder( m_floatingArg.get() ); return builder; } template void bindProcessName( M C::* field ) { m_boundProcessName = new Detail::BoundDataMember( field ); } template void bindProcessName( void (C::*_unaryMethod)( M ) ) { m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); } void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; std::size_t maxWidth = 0; for( it = itBegin; it != itEnd; ++it ) maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { Detail::Text usage( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { std::string usageCol = i < usage.size() ? usage[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) << desc[i]; os << "\n"; } } } std::string optUsage() const { std::ostringstream oss; optUsage( oss ); return oss.str(); } void argSynopsis( std::ostream& os ) const { for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { if( i > 1 ) os << " "; typename std::map::const_iterator it = m_positionalArgs.find( i ); if( it != m_positionalArgs.end() ) os << "<" << it->second.placeholder << ">"; else if( m_floatingArg.get() ) os << "<" << m_floatingArg->placeholder << ">"; else throw std::logic_error( "non consecutive positional arguments with no floating args" ); } // !TBD No indication of mandatory args if( m_floatingArg.get() ) { if( m_highestSpecifiedArgPosition > 1 ) os << " "; os << "[<" << m_floatingArg->placeholder << "> ...]"; } } std::string argSynopsis() const { std::ostringstream oss; argSynopsis( oss ); return oss.str(); } void usage( std::ostream& os, std::string const& procName ) const { validate(); os << "usage:\n " << procName << " "; argSynopsis( os ); if( !m_options.empty() ) { os << " [options]\n\nwhere options are: \n"; optUsage( os, 2 ); } os << "\n"; } std::string usage( std::string const& procName ) const { std::ostringstream oss; usage( oss, procName ); return oss.str(); } ConfigT parse( std::vector const& args ) const { ConfigT config; parseInto( args, config ); return config; } std::vector parseInto( std::vector const& args, ConfigT& config ) const { std::string processName = args.empty() ? std::string() : args[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); m_boundProcessName.set( config, processName ); std::vector tokens; Parser parser; parser.parseIntoTokens( args, tokens ); return populate( tokens, config ); } std::vector populate( std::vector const& tokens, ConfigT& config ) const { validate(); std::vector unusedTokens = populateOptions( tokens, config ); unusedTokens = populateFixedArgs( unusedTokens, config ); unusedTokens = populateFloatingArgs( unusedTokens, config ); return unusedTokens; } std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; std::vector errors; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); for(; it != itEnd; ++it ) { Arg const& arg = *it; try { if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { if( arg.takesArg() ) { if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) errors.push_back( "Expected argument to option: " + token.data ); else arg.boundField.set( config, tokens[++i].data ); } else { arg.boundField.set( config, "true" ); } break; } } catch( std::exception& ex ) { errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); } } if( it == itEnd ) { if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) unusedTokens.push_back( token ); else if( errors.empty() && m_throwOnUnrecognisedTokens ) errors.push_back( "unrecognised option: " + token.data ); } } if( !errors.empty() ) { std::ostringstream oss; for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); it != itEnd; ++it ) { if( it != errors.begin() ) oss << "\n"; oss << *it; } throw std::runtime_error( oss.str() ); } return unusedTokens; } std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; int position = 1; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::map::const_iterator it = m_positionalArgs.find( position ); if( it != m_positionalArgs.end() ) it->second.boundField.set( config, token.data ); else unusedTokens.push_back( token ); if( token.type == Parser::Token::Positional ) position++; } return unusedTokens; } std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { if( !m_floatingArg.get() ) return tokens; std::vector unusedTokens; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; if( token.type == Parser::Token::Positional ) m_floatingArg->boundField.set( config, token.data ); else unusedTokens.push_back( token ); } return unusedTokens; } void validate() const { if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) throw std::logic_error( "No options or arguments specified" ); for( typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); it != itEnd; ++it ) it->validate(); } private: Detail::BoundArgFunction m_boundProcessName; std::vector m_options; std::map m_positionalArgs; ArgAutoPtr m_floatingArg; int m_highestSpecifiedArgPosition; bool m_throwOnUnrecognisedTokens; }; } // end namespace Clara STITCH_CLARA_CLOSE_NAMESPACE #undef STITCH_CLARA_OPEN_NAMESPACE #undef STITCH_CLARA_CLOSE_NAMESPACE #endif // TWOBLUECUBES_CLARA_H_INCLUDED #undef STITCH_CLARA_OPEN_NAMESPACE // Restore Clara's value for console width, if present #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #endif #include #include namespace Catch { inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } inline void abortAfterX( ConfigData& config, int x ) { if( x < 1 ) throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); else throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); } inline void setOrder( ConfigData& config, std::string const& order ) { if( startsWith( "declared", order ) ) config.runOrder = RunTests::InDeclarationOrder; else if( startsWith( "lexical", order ) ) config.runOrder = RunTests::InLexicographicalOrder; else if( startsWith( "random", order ) ) config.runOrder = RunTests::InRandomOrder; else throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); } inline void setRngSeed( ConfigData& config, std::string const& seed ) { if( seed == "time" ) { config.rngSeed = static_cast( std::time(0) ); } else { std::stringstream ss; ss << seed; ss >> config.rngSeed; if( ss.fail() ) throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); } } inline void setVerbosity( ConfigData& config, int level ) { // !TBD: accept strings? config.verbosity = static_cast( level ); } inline void setShowDurations( ConfigData& config, bool _showDurations ) { config.showDurations = _showDurations ? ShowDurations::Always : ShowDurations::Never; } inline void setUseColour( ConfigData& config, std::string const& value ) { std::string mode = toLower( value ); if( mode == "yes" ) config.useColour = UseColour::Yes; else if( mode == "no" ) config.useColour = UseColour::No; else if( mode == "auto" ) config.useColour = UseColour::Auto; else throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); } inline void forceColour( ConfigData& config ) { config.useColour = UseColour::Yes; } inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { std::ifstream f( _filename.c_str() ); if( !f.is_open() ) throw std::domain_error( "Unable to load input file: " + _filename ); std::string line; while( std::getline( f, line ) ) { line = trim(line); if( !line.empty() && !startsWith( line, '#' ) ) { if( !startsWith( line, '"' ) ) line = '"' + line + '"'; addTestOrTags( config, line + ',' ); } } } inline Clara::CommandLine makeCommandLineParser() { using namespace Clara; CommandLine cli; cli.bindProcessName( &ConfigData::processName ); cli["-?"]["-h"]["--help"] .describe( "display usage information" ) .bind( &ConfigData::showHelp ); cli["-l"]["--list-tests"] .describe( "list all/matching test cases" ) .bind( &ConfigData::listTests ); cli["-t"]["--list-tags"] .describe( "list all/matching tags" ) .bind( &ConfigData::listTags ); cli["-s"]["--success"] .describe( "include successful tests in output" ) .bind( &ConfigData::showSuccessfulTests ); cli["-b"]["--break"] .describe( "break into debugger on failure" ) .bind( &ConfigData::shouldDebugBreak ); cli["-e"]["--nothrow"] .describe( "skip exception tests" ) .bind( &ConfigData::noThrow ); cli["-i"]["--invisibles"] .describe( "show invisibles (tabs, newlines)" ) .bind( &ConfigData::showInvisibles ); cli["-o"]["--out"] .describe( "output filename" ) .bind( &ConfigData::outputFilename, "filename" ); cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) .bind( &ConfigData::name, "name" ); cli["-a"]["--abort"] .describe( "abort at first failure" ) .bind( &abortAfterFirst ); cli["-x"]["--abortx"] .describe( "abort after x failures" ) .bind( &abortAfterX, "no. failures" ); cli["-w"]["--warn"] .describe( "enable warnings" ) .bind( &addWarning, "warning name" ); // - needs updating if reinstated // cli.into( &setVerbosity ) // .describe( "level of verbosity (0=no output)" ) // .shortOpt( "v") // .longOpt( "verbosity" ) // .placeholder( "level" ); cli[_] .describe( "which test or tests to use" ) .bind( &addTestOrTags, "test name, pattern or tags" ); cli["-d"]["--durations"] .describe( "show test durations" ) .bind( &setShowDurations, "yes|no" ); cli["-f"]["--input-file"] .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); cli["-#"]["--filenames-as-tags"] .describe( "adds a tag for the filename" ) .bind( &ConfigData::filenamesAsTags ); cli["-c"]["--section"] .describe( "specify section to run" ) .bind( &addSectionToRun, "section name" ); // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) .bind( &ConfigData::listTestNamesOnly ); cli["--list-reporters"] .describe( "list all reporters" ) .bind( &ConfigData::listReporters ); cli["--order"] .describe( "test case order (defaults to decl)" ) .bind( &setOrder, "decl|lex|rand" ); cli["--rng-seed"] .describe( "set a specific seed for random numbers" ) .bind( &setRngSeed, "'time'|number" ); cli["--force-colour"] .describe( "force colourised output (deprecated)" ) .bind( &forceColour ); cli["--use-colour"] .describe( "should output be colourised" ) .bind( &setUseColour, "yes|no" ); return cli; } } // end namespace Catch // #included from: internal/catch_list.hpp #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED // #included from: catch_text.h #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch // #included from: ../external/tbc_text_format.h // Only use header guard if we are not using an outer namespace #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # endif # else # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # endif #endif #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #include #include #include // Use optional outer namespace #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { const std::string wrappableBeforeChars = "[({<\t"; const std::string wrappableAfterChars = "])}>-,./|\\"; const std::string wrappableInsteadOfChars = " \n\r"; std::string indent = _attr.initialIndent != std::string::npos ? std::string( _attr.initialIndent, ' ' ) : std::string( _attr.indent, ' ' ); typedef std::string::const_iterator iterator; iterator it = _str.begin(); const iterator strEnd = _str.end(); while( it != strEnd ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::string suffix; std::size_t width = (std::min)( static_cast( strEnd-it ), _attr.width-static_cast( indent.size() ) ); iterator itEnd = it+width; iterator itNext = _str.end(); iterator itNewLine = std::find( it, itEnd, '\n' ); if( itNewLine != itEnd ) itEnd = itNewLine; if( itEnd != strEnd ) { bool foundWrapPoint = false; iterator findIt = itEnd; do { if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { itEnd = findIt+1; itNext = findIt+1; foundWrapPoint = true; } else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { itEnd = findIt; itNext = findIt; foundWrapPoint = true; } else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { itNext = findIt+1; itEnd = findIt; foundWrapPoint = true; } if( findIt == it ) break; else --findIt; } while( !foundWrapPoint ); if( !foundWrapPoint ) { // No good wrap char, so we'll break mid word and add a hyphen --itEnd; itNext = itEnd; suffix = "-"; } else { while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) --itEnd; } } lines.push_back( indent + std::string( it, itEnd ) + suffix ); if( indent.size() != _attr.indent ) indent = std::string( _attr.indent, ' ' ); it = itNext; } } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace Catch { using Tbc::Text; using Tbc::TextAttributes; } // #included from: catch_console_colour.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED namespace Catch { struct Colour { enum Code { None = 0, White, Red, Green, Blue, Cyan, Yellow, Grey, Bright = 0x10, BrightRed = Bright | Red, BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, // By intention FileName = LightGrey, Warning = Yellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, Error = BrightRed, Success = Green, OriginalExpression = Cyan, ReconstructedExpression = Yellow, SecondaryText = LightGrey, Headers = White }; // Use constructed object for RAII guard Colour( Code _colourCode ); Colour( Colour const& other ); ~Colour(); // Use static method for one-shot changes static void use( Code _colourCode ); private: bool m_moved; }; inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } } // end namespace Catch // #included from: catch_interfaces_reporter.h #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED #include #include #include namespace Catch { struct ReporterConfig { explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; Ptr m_fullConfig; }; struct ReporterPreferences { ReporterPreferences() : shouldRedirectStdOut( false ) {} bool shouldRedirectStdOut; }; template struct LazyStat : Option { LazyStat() : used( false ) {} LazyStat& operator=( T const& _value ) { Option::operator=( _value ); used = false; return *this; } void reset() { Option::reset(); used = false; } bool used; }; struct TestRunInfo { TestRunInfo( std::string const& _name ) : name( _name ) {} std::string name; }; struct GroupInfo { GroupInfo( std::string const& _name, std::size_t _groupIndex, std::size_t _groupsCount ) : name( _name ), groupIndex( _groupIndex ), groupsCounts( _groupsCount ) {} std::string name; std::size_t groupIndex; std::size_t groupsCounts; }; struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, Totals const& _totals ) : assertionResult( _assertionResult ), infoMessages( _infoMessages ), totals( _totals ) { if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); builder << assertionResult.getMessage(); builder.m_info.message = builder.m_stream.str(); infoMessages.push_back( builder.m_info ); } } virtual ~AssertionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = default; AssertionStats& operator = ( AssertionStats && ) = default; # endif AssertionResult assertionResult; std::vector infoMessages; Totals totals; }; struct SectionStats { SectionStats( SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ) : sectionInfo( _sectionInfo ), assertions( _assertions ), durationInSeconds( _durationInSeconds ), missingAssertions( _missingAssertions ) {} virtual ~SectionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; SectionStats& operator = ( SectionStats && ) = default; # endif SectionInfo sectionInfo; Counts assertions; double durationInSeconds; bool missingAssertions; }; struct TestCaseStats { TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, std::string const& _stdOut, std::string const& _stdErr, bool _aborting ) : testInfo( _testInfo ), totals( _totals ), stdOut( _stdOut ), stdErr( _stdErr ), aborting( _aborting ) {} virtual ~TestCaseStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; TestCaseStats& operator = ( TestCaseStats && ) = default; # endif TestCaseInfo testInfo; Totals totals; std::string stdOut; std::string stdErr; bool aborting; }; struct TestGroupStats { TestGroupStats( GroupInfo const& _groupInfo, Totals const& _totals, bool _aborting ) : groupInfo( _groupInfo ), totals( _totals ), aborting( _aborting ) {} TestGroupStats( GroupInfo const& _groupInfo ) : groupInfo( _groupInfo ), aborting( false ) {} virtual ~TestGroupStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; TestGroupStats& operator = ( TestGroupStats && ) = default; # endif GroupInfo groupInfo; Totals totals; bool aborting; }; struct TestRunStats { TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting ) : runInfo( _runInfo ), totals( _totals ), aborting( _aborting ) {} virtual ~TestRunStats(); # ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS TestRunStats( TestRunStats const& _other ) : runInfo( _other.runInfo ), totals( _other.totals ), aborting( _other.aborting ) {} # else TestRunStats( TestRunStats const& ) = default; TestRunStats( TestRunStats && ) = default; TestRunStats& operator = ( TestRunStats const& ) = default; TestRunStats& operator = ( TestRunStats && ) = default; # endif TestRunInfo runInfo; Totals totals; bool aborting; }; class MultipleReporters; struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); // Implementing class must also provide the following static method: // static std::string getDescription(); virtual ReporterPreferences getPreferences() const = 0; virtual void noMatchingTestCases( std::string const& spec ) = 0; virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } }; struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { typedef std::map > FactoryMap; typedef std::vector > Listeners; virtual ~IReporterRegistry(); virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; virtual Listeners const& getListeners() const = 0; }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); } #include #include namespace Catch { inline std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::size_t matchedTests = 0; TextAttributes nameAttr, tagsAttr; nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); Colour::Code colour = testCaseInfo.isHidden() ? Colour::SecondaryText : Colour::None; Colour colourGuard( colour ); Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; if( !testCaseInfo.tags.empty() ) Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; } if( !config.testSpec().hasFilters() ) Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; else Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; return matchedTests; } inline std::size_t listTestsNamesOnly( Config const& config ) { TestSpec testSpec = config.testSpec(); if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); if( startsWith( testCaseInfo.name, '#' ) ) Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl; else Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } struct TagInfo { TagInfo() : count ( 0 ) {} void add( std::string const& spelling ) { ++count; spellings.insert( spelling ); } std::string all() const { std::string out; for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); it != itEnd; ++it ) out += "[" + *it + "]"; return out; } std::set spellings; std::size_t count; }; inline std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::map tagCounts; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), tagItEnd = it->getTestCaseInfo().tags.end(); tagIt != tagItEnd; ++tagIt ) { std::string tagName = *tagIt; std::string lcaseTagName = toLower( tagName ); std::map::iterator countIt = tagCounts.find( lcaseTagName ); if( countIt == tagCounts.end() ) countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; countIt->second.add( tagName ); } } for( std::map::const_iterator countIt = tagCounts.begin(), countItEnd = tagCounts.end(); countIt != countItEnd; ++countIt ) { std::ostringstream oss; oss << " " << std::setw(2) << countIt->second.count << " "; Text wrapper( countIt->second.all(), TextAttributes() .setInitialIndent( 0 ) .setIndent( oss.str().size() ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); Catch::cout() << oss.str() << wrapper << '\n'; } Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; return tagCounts.size(); } inline std::size_t listReporters( Config const& /*config*/ ) { Catch::cout() << "Available reporters:\n"; IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; std::size_t maxNameLen = 0; for(it = itBegin; it != itEnd; ++it ) maxNameLen = (std::max)( maxNameLen, it->first.size() ); for(it = itBegin; it != itEnd; ++it ) { Text wrapper( it->second->getDescription(), TextAttributes() .setInitialIndent( 0 ) .setIndent( 7+maxNameLen ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); Catch::cout() << " " << it->first << ':' << std::string( maxNameLen - it->first.size() + 2, ' ' ) << wrapper << '\n'; } Catch::cout() << std::endl; return factories.size(); } inline Option list( Config const& config ) { Option listedCount; if( config.listTests() ) listedCount = listedCount.valueOr(0) + listTests( config ); if( config.listTestNamesOnly() ) listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); if( config.listTags() ) listedCount = listedCount.valueOr(0) + listTags( config ); if( config.listReporters() ) listedCount = listedCount.valueOr(0) + listReporters( config ); return listedCount; } } // end namespace Catch // #included from: internal/catch_run_context.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED #include #include #include #include #include CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS namespace Catch { namespace TestCaseTracking { struct NameAndLocation { std::string name; SourceLineInfo location; NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) : name( _name ), location( _location ) {} }; struct ITracker : SharedImpl<> { virtual ~ITracker(); // static queries virtual NameAndLocation const& nameAndLocation() const = 0; // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; virtual ITracker& parent() = 0; // actions virtual void close() = 0; // Successfully complete virtual void fail() = 0; virtual void markAsNeedingAnotherRun() = 0; virtual void addChild( Ptr const& child ) = 0; virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; virtual void openChild() = 0; // Debug/ checking virtual bool isSectionTracker() const = 0; virtual bool isIndexTracker() const = 0; }; class TrackerContext { enum RunState { NotStarted, Executing, CompletedCycle }; Ptr m_rootTracker; ITracker* m_currentTracker; RunState m_runState; public: static TrackerContext& instance() { static TrackerContext s_instance; return s_instance; } TrackerContext() : m_currentTracker( CATCH_NULL ), m_runState( NotStarted ) {} ITracker& startRun(); void endRun() { m_rootTracker.reset(); m_currentTracker = CATCH_NULL; m_runState = NotStarted; } void startCycle() { m_currentTracker = m_rootTracker.get(); m_runState = Executing; } void completeCycle() { m_runState = CompletedCycle; } bool completedCycle() const { return m_runState == CompletedCycle; } ITracker& currentTracker() { return *m_currentTracker; } void setCurrentTracker( ITracker* tracker ) { m_currentTracker = tracker; } }; class TrackerBase : public ITracker { protected: enum CycleState { NotStarted, Executing, ExecutingChildren, NeedsAnotherRun, CompletedSuccessfully, Failed }; class TrackerHasName { NameAndLocation m_nameAndLocation; public: TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} bool operator ()( Ptr const& tracker ) { return tracker->nameAndLocation().name == m_nameAndLocation.name && tracker->nameAndLocation().location == m_nameAndLocation.location; } }; typedef std::vector > Children; NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; CycleState m_runState; public: TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : m_nameAndLocation( nameAndLocation ), m_ctx( ctx ), m_parent( parent ), m_runState( NotStarted ) {} virtual ~TrackerBase(); virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { return m_nameAndLocation; } virtual bool isComplete() const CATCH_OVERRIDE { return m_runState == CompletedSuccessfully || m_runState == Failed; } virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { return m_runState == CompletedSuccessfully; } virtual bool isOpen() const CATCH_OVERRIDE { return m_runState != NotStarted && !isComplete(); } virtual bool hasChildren() const CATCH_OVERRIDE { return !m_children.empty(); } virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { m_children.push_back( child ); } virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); return( it != m_children.end() ) ? it->get() : CATCH_NULL; } virtual ITracker& parent() CATCH_OVERRIDE { assert( m_parent ); // Should always be non-null except for root return *m_parent; } virtual void openChild() CATCH_OVERRIDE { if( m_runState != ExecutingChildren ) { m_runState = ExecutingChildren; if( m_parent ) m_parent->openChild(); } } virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } void open() { m_runState = Executing; moveToThis(); if( m_parent ) m_parent->openChild(); } virtual void close() CATCH_OVERRIDE { // Close any still open children (e.g. generators) while( &m_ctx.currentTracker() != this ) m_ctx.currentTracker().close(); switch( m_runState ) { case NotStarted: case CompletedSuccessfully: case Failed: throw std::logic_error( "Illogical state" ); case NeedsAnotherRun: break;; case Executing: m_runState = CompletedSuccessfully; break; case ExecutingChildren: if( m_children.empty() || m_children.back()->isComplete() ) m_runState = CompletedSuccessfully; break; default: throw std::logic_error( "Unexpected state" ); } moveToParent(); m_ctx.completeCycle(); } virtual void fail() CATCH_OVERRIDE { m_runState = Failed; if( m_parent ) m_parent->markAsNeedingAnotherRun(); moveToParent(); m_ctx.completeCycle(); } virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { m_runState = NeedsAnotherRun; } private: void moveToParent() { assert( m_parent ); m_ctx.setCurrentTracker( m_parent ); } void moveToThis() { m_ctx.setCurrentTracker( this ); } }; class SectionTracker : public TrackerBase { std::vector m_filters; public: SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : TrackerBase( nameAndLocation, ctx, parent ) { if( parent ) { while( !parent->isSectionTracker() ) parent = &parent->parent(); SectionTracker& parentSection = static_cast( *parent ); addNextFilters( parentSection.m_filters ); } } virtual ~SectionTracker(); virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { SectionTracker* section = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isSectionTracker() ); section = static_cast( childTracker ); } else { section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( section ); } if( !ctx.completedCycle() ) section->tryOpen(); return *section; } void tryOpen() { if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) open(); } void addInitialFilters( std::vector const& filters ) { if( !filters.empty() ) { m_filters.push_back(""); // Root - should never be consulted m_filters.push_back(""); // Test Case - not a section filter m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); } } void addNextFilters( std::vector const& filters ) { if( filters.size() > 1 ) m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); } }; class IndexTracker : public TrackerBase { int m_size; int m_index; public: IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) : TrackerBase( nameAndLocation, ctx, parent ), m_size( size ), m_index( -1 ) {} virtual ~IndexTracker(); virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { IndexTracker* tracker = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isIndexTracker() ); tracker = static_cast( childTracker ); } else { tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); currentTracker.addChild( tracker ); } if( !ctx.completedCycle() && !tracker->isComplete() ) { if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) tracker->moveNext(); tracker->open(); } return *tracker; } int index() const { return m_index; } void moveNext() { m_index++; m_children.clear(); } virtual void close() CATCH_OVERRIDE { TrackerBase::close(); if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) m_runState = Executing; } }; inline ITracker& TrackerContext::startRun() { m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); m_currentTracker = CATCH_NULL; m_runState = Executing; return *m_rootTracker; } } // namespace TestCaseTracking using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; using TestCaseTracking::IndexTracker; } // namespace Catch CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS // #included from: catch_fatal_condition.hpp #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED namespace Catch { // Report the error condition inline void reportFatal( std::string const& message ) { IContext& context = Catch::getCurrentContext(); IResultCapture* resultCapture = context.getResultCapture(); resultCapture->handleFatalErrorCondition( message ); } } // namespace Catch #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// // #included from: catch_windows_h_proxy.h #define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED #ifdef CATCH_DEFINES_NOMINMAX # define NOMINMAX #endif #ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #ifdef __AFXDLL #include #else #include #endif #ifdef CATCH_DEFINES_NOMINMAX # undef NOMINMAX #endif #ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN # undef WIN32_LEAN_AND_MEAN #endif # if !defined ( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { struct FatalConditionHandler { void reset() {} }; } # else // CATCH_CONFIG_WINDOWS_SEH is defined namespace Catch { struct SignalDefs { DWORD id; const char* name; }; extern SignalDefs signalDefs[]; // There is no 1-1 mapping between signals and windows exceptions. // Windows can easily distinguish between SO and SigSegV, // but SigInt, SigTerm, etc are handled differently. SignalDefs signalDefs[] = { { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, }; struct FatalConditionHandler { static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { reportFatal(signalDefs[i].name); } } // If its not an exception we care about, pass it along. // This stops us from eating debugger breaks etc. return EXCEPTION_CONTINUE_SEARCH; } FatalConditionHandler() { isSet = true; // 32k seems enough for Catch to handle stack overflow, // but the value was found experimentally, so there is no strong guarantee guaranteeSize = 32 * 1024; exceptionHandlerHandle = CATCH_NULL; // Register as first handler in current chain exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); // Pass in guarantee size to be filled SetThreadStackGuarantee(&guaranteeSize); } static void reset() { if (isSet) { // Unregister handler and restore the old guarantee RemoveVectoredExceptionHandler(exceptionHandlerHandle); SetThreadStackGuarantee(&guaranteeSize); exceptionHandlerHandle = CATCH_NULL; isSet = false; } } ~FatalConditionHandler() { reset(); } private: static bool isSet; static ULONG guaranteeSize; static PVOID exceptionHandlerHandle; }; bool FatalConditionHandler::isSet = false; ULONG FatalConditionHandler::guaranteeSize = 0; PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; } // namespace Catch # endif // CATCH_CONFIG_WINDOWS_SEH #else // Not Windows - assumed to be POSIX compatible ////////////////////////// # if !defined(CATCH_CONFIG_POSIX_SIGNALS) namespace Catch { struct FatalConditionHandler { void reset() {} }; } # else // CATCH_CONFIG_POSIX_SIGNALS is defined #include namespace Catch { struct SignalDefs { int id; const char* name; }; extern SignalDefs signalDefs[]; SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, { SIGFPE, "SIGFPE - Floating point error signal" }, { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, { SIGTERM, "SIGTERM - Termination request signal" }, { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } }; struct FatalConditionHandler { static bool isSet; static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; static stack_t oldSigStack; static char altStackMem[SIGSTKSZ]; static void handleSignal( int sig ) { std::string name = ""; for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { SignalDefs &def = signalDefs[i]; if (sig == def.id) { name = def.name; break; } } reset(); reportFatal(name); raise( sig ); } FatalConditionHandler() { isSet = true; stack_t sigStack; sigStack.ss_sp = altStackMem; sigStack.ss_size = SIGSTKSZ; sigStack.ss_flags = 0; sigaltstack(&sigStack, &oldSigStack); struct sigaction sa = { 0 }; sa.sa_handler = handleSignal; sa.sa_flags = SA_ONSTACK; for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); } } ~FatalConditionHandler() { reset(); } static void reset() { if( isSet ) { // Set signals back to previous values -- hopefully nobody overwrote them in the meantime for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); } // Return the old stack sigaltstack(&oldSigStack, CATCH_NULL); isSet = false; } } }; bool FatalConditionHandler::isSet = false; struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; stack_t FatalConditionHandler::oldSigStack = {}; char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; } // namespace Catch # endif // CATCH_CONFIG_POSIX_SIGNALS #endif // not Windows #include #include namespace Catch { class StreamRedirect { public: StreamRedirect( std::ostream& stream, std::string& targetString ) : m_stream( stream ), m_prevBuf( stream.rdbuf() ), m_targetString( targetString ) { stream.rdbuf( m_oss.rdbuf() ); } ~StreamRedirect() { m_targetString += m_oss.str(); m_stream.rdbuf( m_prevBuf ); } private: std::ostream& m_stream; std::streambuf* m_prevBuf; std::ostringstream m_oss; std::string& m_targetString; }; /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { RunContext( RunContext const& ); void operator =( RunContext const& ); public: explicit RunContext( Ptr const& _config, Ptr const& reporter ) : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), m_activeTestCase( CATCH_NULL ), m_config( _config ), m_reporter( reporter ), m_shouldReportUnexpected ( true ) { m_context.setRunner( this ); m_context.setConfig( m_config ); m_context.setResultCapture( this ); m_reporter->testRunStarting( m_runInfo ); } virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); } void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); } Totals runTest( TestCase const& testCase ) { Totals prevTotals = m_totals; std::string redirectedCout; std::string redirectedCerr; TestCaseInfo testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; do { ITracker& rootTracker = m_trackerContext.startRun(); assert( rootTracker.isSectionTracker() ); static_cast( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); do { m_trackerContext.startCycle(); m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); runCurrentTest( redirectedCout, redirectedCerr ); } while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { deltaTotals.assertions.failed++; deltaTotals.testCases.passed--; deltaTotals.testCases.failed++; } m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, redirectedCout, redirectedCerr, aborting() ) ); m_activeTestCase = CATCH_NULL; m_testCaseTracker = CATCH_NULL; return deltaTotals; } Ptr config() const { return m_config; } private: // IResultCapture virtual void assertionEnded( AssertionResult const& result ) { if( result.getResultType() == ResultWas::Ok ) { m_totals.assertions.passed++; } else if( !result.isOk() ) { m_totals.assertions.failed++; } // We have no use for the return value (whether messages should be cleared), because messages were made scoped // and should be let to clear themselves out. static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); m_lastResult = result; } virtual bool sectionStarted ( SectionInfo const& sectionInfo, Counts& assertions ) { ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); if( !sectionTracker.isOpen() ) return false; m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_reporter->sectionStarting( sectionInfo ); assertions = m_totals.assertions; return true; } bool testForMissingAssertions( Counts& assertions ) { if( assertions.total() != 0 ) return false; if( !m_config->warnAboutMissingAssertions() ) return false; if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } virtual void sectionEnded( SectionEndInfo const& endInfo ) { Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); if( !m_activeSections.empty() ) { m_activeSections.back()->close(); m_activeSections.pop_back(); } m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { if( m_unfinishedSections.empty() ) m_activeSections.back()->fail(); else m_activeSections.back()->close(); m_activeSections.pop_back(); m_unfinishedSections.push_back( endInfo ); } virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } virtual void popScopedMessage( MessageInfo const& message ) { m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); } virtual std::string getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name : std::string(); } virtual const AssertionResult* getLastResult() const { return &m_lastResult; } virtual void exceptionEarlyReported() { m_shouldReportUnexpected = false; } virtual void handleFatalErrorCondition( std::string const& message ) { // Don't rebuild the result -- the stringification itself can cause more fatal errors // Instead, fake a result data. AssertionResultData tempResult; tempResult.resultType = ResultWas::FatalErrorCondition; tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); getResultCapture().assertionEnded(result); handleUnfinishedSections(); // Recreate section for test case (as we will lose the one that was in scope) TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); Counts assertions; assertions.failed = 1; SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); m_reporter->sectionEnded( testCaseSectionStats ); TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); Totals deltaTotals; deltaTotals.testCases.failed = 1; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, std::string(), std::string(), false ) ); m_totals.testCases.failed++; testGroupEnded( std::string(), m_totals, 1, 1 ); m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); } public: // !TBD We need to do this another way! bool aborting() const { return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); } private: void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); m_reporter->sectionStarting( testCaseSection ); Counts prevAssertions = m_totals.assertions; double duration = 0; m_shouldReportUnexpected = true; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal ); seedRng( *m_config ); Timer timer; timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { StreamRedirect coutRedir( Catch::cout(), redirectedCout ); StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); invokeActiveTestCase(); } else { invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); } catch( TestFailureException& ) { // This just means the test was aborted due to failure } catch(...) { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. if (m_shouldReportUnexpected) { makeUnexpectedResultBuilder().useActiveException(); } } m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); Counts assertions = m_totals.assertions - prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); if( testCaseInfo.okToFail() ) { std::swap( assertions.failedButOk, assertions.failed ); m_totals.assertions.failed -= assertions.failedButOk; m_totals.assertions.failedButOk += assertions.failedButOk; } SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); m_reporter->sectionEnded( testCaseSectionStats ); } void invokeActiveTestCase() { FatalConditionHandler fatalConditionHandler; // Handle signals m_activeTestCase->invoke(); fatalConditionHandler.reset(); } private: ResultBuilder makeUnexpectedResultBuilder() const { return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), m_lastAssertionInfo.lineInfo, m_lastAssertionInfo.capturedExpression.c_str(), m_lastAssertionInfo.resultDisposition ); } void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) sectionEnded( *it ); m_unfinishedSections.clear(); } TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; ITracker* m_testCaseTracker; ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; AssertionInfo m_lastAssertionInfo; std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; bool m_shouldReportUnexpected; }; IResultCapture& getResultCapture() { if( IResultCapture* capture = getCurrentContext().getResultCapture() ) return *capture; else throw std::logic_error( "No result capture instance" ); } } // end namespace Catch // #included from: internal/catch_version.h #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED namespace Catch { // Versioning information struct Version { Version( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, char const * const _branchName, unsigned int _buildNumber ); unsigned int const majorVersion; unsigned int const minorVersion; unsigned int const patchNumber; // buildNumber is only used if branchName is not null char const * const branchName; unsigned int const buildNumber; friend std::ostream& operator << ( std::ostream& os, Version const& version ); private: void operator=( Version const& ); }; inline Version libraryVersion(); } #include #include #include namespace Catch { Ptr createReporter( std::string const& reporterName, Ptr const& config ) { Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); if( !reporter ) { std::ostringstream oss; oss << "No reporter registered with name: '" << reporterName << "'"; throw std::domain_error( oss.str() ); } return reporter; } Ptr makeReporter( Ptr const& config ) { std::vector reporters = config->getReporterNames(); if( reporters.empty() ) reporters.push_back( "console" ); Ptr reporter; for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); it != itEnd; ++it ) reporter = addReporter( reporter, createReporter( *it, config ) ); return reporter; } Ptr addListeners( Ptr const& config, Ptr reporters ) { IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); it != itEnd; ++it ) reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); return reporters; } Totals runTests( Ptr const& config ) { Ptr iconfig = config.get(); Ptr reporter = makeReporter( config ); reporter = addListeners( iconfig, reporter ); RunContext context( iconfig, reporter ); Totals totals; context.testGroupStarting( config->name(), 1, 1 ); TestSpec testSpec = config->testSpec(); if( !testSpec.hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); it != itEnd; ++it ) { if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) totals += context.runTest( *it ); else reporter->skipTest( *it ); } context.testGroupEnded( iconfig->name(), totals, 1, 1 ); return totals; } void applyFilenamesAsTags( IConfig const& config ) { std::vector const& tests = getAllTestCasesSorted( config ); for(std::size_t i = 0; i < tests.size(); ++i ) { TestCase& test = const_cast( tests[i] ); std::set tags = test.tags; std::string filename = test.lineInfo.file; std::string::size_type lastSlash = filename.find_last_of( "\\/" ); if( lastSlash != std::string::npos ) filename = filename.substr( lastSlash+1 ); std::string::size_type lastDot = filename.find_last_of( "." ); if( lastDot != std::string::npos ) filename = filename.substr( 0, lastDot ); tags.insert( "#" + filename ); setTags( test, tags ); } } class Session : NonCopyable { static bool alreadyInstantiated; public: struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; Session() : m_cli( makeCommandLineParser() ) { if( alreadyInstantiated ) { std::string msg = "Only one instance of Catch::Session can ever be used"; Catch::cerr() << msg << std::endl; throw std::logic_error( msg ); } alreadyInstantiated = true; } ~Session() { Catch::cleanUp(); } void showHelp( std::string const& processName ) { Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; m_cli.usage( Catch::cout(), processName ); Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); m_config.reset(); } catch( std::exception& ex ) { { Colour colourGuard( Colour::Red ); Catch::cerr() << "\nError(s) in input:\n" << Text( ex.what(), TextAttributes().setIndent(2) ) << "\n\n"; } m_cli.usage( Catch::cout(), m_configData.processName ); return (std::numeric_limits::max)(); } return 0; } void useConfigData( ConfigData const& _configData ) { m_configData = _configData; m_config.reset(); } int run( int argc, char const* const* const argv ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) returnCode = run(); return returnCode; } #if defined(WIN32) && defined(UNICODE) int run( int argc, wchar_t const* const* const argv ) { char **utf8Argv = new char *[ argc ]; for ( int i = 0; i < argc; ++i ) { int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); utf8Argv[ i ] = new char[ bufSize ]; WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); } int returnCode = applyCommandLine( argc, utf8Argv ); if( returnCode == 0 ) returnCode = run(); for ( int i = 0; i < argc; ++i ) delete [] utf8Argv[ i ]; delete [] utf8Argv; return returnCode; } #endif int run() { if( m_configData.showHelp ) return 0; try { config(); // Force config to be constructed seedRng( *m_config ); if( m_configData.filenamesAsTags ) applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; return (std::numeric_limits::max)(); } } Clara::CommandLine const& cli() const { return m_cli; } std::vector const& unusedTokens() const { return m_unusedTokens; } ConfigData& configData() { return m_configData; } Config& config() { if( !m_config ) m_config = new Config( m_configData ); return *m_config; } private: Clara::CommandLine m_cli; std::vector m_unusedTokens; ConfigData m_configData; Ptr m_config; }; bool Session::alreadyInstantiated = false; } // end namespace Catch // #included from: catch_registry_hub.hpp #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED // #included from: catch_test_case_registry_impl.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED #include #include #include #include namespace Catch { struct RandomNumberGenerator { typedef std::ptrdiff_t result_type; result_type operator()( result_type n ) const { return std::rand() % n; } #ifdef CATCH_CONFIG_CPP11_SHUFFLE static constexpr result_type min() { return 0; } static constexpr result_type max() { return 1000000; } result_type operator()() const { return std::rand() % max(); } #endif template static void shuffle( V& vector ) { RandomNumberGenerator rng; #ifdef CATCH_CONFIG_CPP11_SHUFFLE std::shuffle( vector.begin(), vector.end(), rng ); #else std::random_shuffle( vector.begin(), vector.end(), rng ); #endif } }; inline std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { std::vector sorted = unsortedTestCases; switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: std::sort( sorted.begin(), sorted.end() ); break; case RunTests::InRandomOrder: { seedRng( config ); RandomNumberGenerator::shuffle( sorted ); } break; case RunTests::InDeclarationOrder: // already in declaration order break; } return sorted; } bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); } void enforceNoDuplicateTestCases( std::vector const& functions ) { std::set seenFunctions; for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); it != itEnd; ++it ) { std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); if( !prev.second ) { std::ostringstream ss; ss << Colour( Colour::Red ) << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n' << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; throw std::runtime_error(ss.str()); } } } std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); it != itEnd; ++it ) if( matchTest( *it, testSpec, config ) ) filtered.push_back( *it ); return filtered; } std::vector const& getAllTestCasesSorted( IConfig const& config ) { return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); } class TestRegistry : public ITestCaseRegistry { public: TestRegistry() : m_currentSortOrder( RunTests::InDeclarationOrder ), m_unnamedCount( 0 ) {} virtual ~TestRegistry(); virtual void registerTest( TestCase const& testCase ) { std::string name = testCase.getTestCaseInfo().name; if( name.empty() ) { std::ostringstream oss; oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { return m_functions; } virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { if( m_sortedFunctions.empty() ) enforceNoDuplicateTestCases( m_functions ); if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { m_sortedFunctions = sortTests( config, m_functions ); m_currentSortOrder = config.runOrder(); } return m_sortedFunctions; } private: std::vector m_functions; mutable RunTests::InWhatOrder m_currentSortOrder; mutable std::vector m_sortedFunctions; size_t m_unnamedCount; std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// class FreeFunctionTestCase : public SharedImpl { public: FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} virtual void invoke() const { m_fun(); } private: virtual ~FreeFunctionTestCase(); TestFunction m_fun; }; inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, '&' ) ) { std::size_t lastColons = className.rfind( "::" ); std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); if( penultimateColons == std::string::npos ) penultimateColons = 1; className = className.substr( penultimateColons, lastColons-penultimateColons ); } return className; } void registerTestCase ( ITestCase* testCase, char const* classOrQualifiedMethodName, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { getMutableRegistryHub().registerTest ( makeTestCase ( testCase, extractClassName( classOrQualifiedMethodName ), nameAndDesc.name, nameAndDesc.description, lineInfo ) ); } void registerTestCaseFunction ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } /////////////////////////////////////////////////////////////////////////// AutoReg::AutoReg ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ) { registerTestCaseFunction( function, lineInfo, nameAndDesc ); } AutoReg::~AutoReg() {} } // end namespace Catch // #included from: catch_reporter_registry.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED #include namespace Catch { class ReporterRegistry : public IReporterRegistry { public: virtual ~ReporterRegistry() CATCH_OVERRIDE {} virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } void registerListener( Ptr const& factory ) { m_listeners.push_back( factory ); } virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } virtual Listeners const& getListeners() const CATCH_OVERRIDE { return m_listeners; } private: FactoryMap m_factories; Listeners m_listeners; }; } // #included from: catch_exception_translator_registry.hpp #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED #ifdef __OBJC__ #import "Foundation/Foundation.h" #endif namespace Catch { class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { public: ~ExceptionTranslatorRegistry() { deleteAll( m_translators ); } virtual void registerTranslator( const IExceptionTranslator* translator ) { m_translators.push_back( translator ); } virtual std::string translateActiveException() const { try { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else return tryTranslators(); #endif } catch( TestFailureException& ) { throw; } catch( std::exception& ex ) { return ex.what(); } catch( std::string& msg ) { return msg; } catch( const char* msg ) { return msg; } catch(...) { return "Unknown exception"; } } std::string tryTranslators() const { if( m_translators.empty() ) throw; else return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: std::vector m_translators; }; } // #included from: catch_tag_alias_registry.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED #include namespace Catch { class TagAliasRegistry : public ITagAliasRegistry { public: virtual ~TagAliasRegistry(); virtual Option find( std::string const& alias ) const; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); private: std::map m_registry; }; } // end namespace Catch namespace Catch { namespace { class RegistryHub : public IRegistryHub, public IMutableRegistryHub { RegistryHub( RegistryHub const& ); void operator=( RegistryHub const& ); public: // IRegistryHub RegistryHub() { } virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE { return m_tagAliasRegistry; } public: // IMutableRegistryHub virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerListener( factory ); } virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE { m_tagAliasRegistry.add( alias, tag, lineInfo ); } private: TestRegistry m_testCaseRegistry; ReporterRegistry m_reporterRegistry; ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; TagAliasRegistry m_tagAliasRegistry; }; // Single, global, instance inline RegistryHub*& getTheRegistryHub() { static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; } } IRegistryHub& getRegistryHub() { return *getTheRegistryHub(); } IMutableRegistryHub& getMutableRegistryHub() { return *getTheRegistryHub(); } void cleanUp() { delete getTheRegistryHub(); getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); } } // end namespace Catch // #included from: catch_notimplemented_exception.hpp #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED #include namespace Catch { NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) : m_lineInfo( lineInfo ) { std::ostringstream oss; oss << lineInfo << ": function "; oss << "not implemented"; m_what = oss.str(); } const char* NotImplementedException::what() const CATCH_NOEXCEPT { return m_what.c_str(); } } // end namespace Catch // #included from: catch_context_impl.hpp #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #include #include #include namespace Catch { template class StreamBufImpl : public StreamBufBase { char data[bufferSize]; WriterF m_writer; public: StreamBufImpl() { setp( data, data + sizeof(data) ); } ~StreamBufImpl() CATCH_NOEXCEPT { sync(); } private: int overflow( int c ) { sync(); if( c != EOF ) { if( pbase() == epptr() ) m_writer( std::string( 1, static_cast( c ) ) ); else sputc( static_cast( c ) ); } return 0; } int sync() { if( pbase() != pptr() ) { m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); setp( pbase(), epptr() ); } return 0; } }; /////////////////////////////////////////////////////////////////////////// FileStream::FileStream( std::string const& filename ) { m_ofs.open( filename.c_str() ); if( m_ofs.fail() ) { std::ostringstream oss; oss << "Unable to open file: '" << filename << '\''; throw std::domain_error( oss.str() ); } } std::ostream& FileStream::stream() const { return m_ofs; } struct OutputDebugWriter { void operator()( std::string const&str ) { writeToDebugConsole( str ); } }; DebugOutStream::DebugOutStream() : m_streamBuf( new StreamBufImpl() ), m_os( m_streamBuf.get() ) {} std::ostream& DebugOutStream::stream() const { return m_os; } // Store the streambuf from cout up-front because // cout may get redirected when running tests CoutStream::CoutStream() : m_os( Catch::cout().rdbuf() ) {} std::ostream& CoutStream::stream() const { return m_os; } #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } std::ostream& cerr() { return std::cerr; } #endif } namespace Catch { class Context : public IMutableContext { Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); public: virtual ~Context() { deleteAllValues( m_generatorsByTestName ); } public: // IContext virtual IResultCapture* getResultCapture() { return m_resultCapture; } virtual IRunner* getRunner() { return m_runner; } virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { return getGeneratorsForCurrentTest() .getGeneratorInfo( fileInfo, totalSize ) .getCurrentIndex(); } virtual bool advanceGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); return generators && generators->moveNext(); } virtual Ptr getConfig() const { return m_config; } public: // IMutableContext virtual void setResultCapture( IResultCapture* resultCapture ) { m_resultCapture = resultCapture; } virtual void setRunner( IRunner* runner ) { m_runner = runner; } virtual void setConfig( Ptr const& config ) { m_config = config; } friend IMutableContext& getCurrentMutableContext(); private: IGeneratorsForTest* findGeneratorsForCurrentTest() { std::string testName = getResultCapture()->getCurrentTestName(); std::map::const_iterator it = m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); if( !generators ) { std::string testName = getResultCapture()->getCurrentTestName(); generators = createGeneratorsForTest(); m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); } return *generators; } private: Ptr m_config; IRunner* m_runner; IResultCapture* m_resultCapture; std::map m_generatorsByTestName; }; namespace { Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) currentContext = new Context(); return *currentContext; } IContext& getCurrentContext() { return getCurrentMutableContext(); } void cleanUpContext() { delete currentContext; currentContext = CATCH_NULL; } } // #included from: catch_console_colour_impl.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED // #included from: catch_errno_guard.hpp #define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED #include namespace Catch { class ErrnoGuard { public: ErrnoGuard():m_oldErrno(errno){} ~ErrnoGuard() { errno = m_oldErrno; } private: int m_oldErrno; }; } namespace Catch { namespace { struct IColourImpl { virtual ~IColourImpl() {} virtual void use( Colour::Code _colourCode ) = 0; }; struct NoColourImpl : IColourImpl { void use( Colour::Code ) {} static IColourImpl* instance() { static NoColourImpl s_instance; return &s_instance; } }; } // anon namespace } // namespace Catch #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) # ifdef CATCH_PLATFORM_WINDOWS # define CATCH_CONFIG_COLOUR_WINDOWS # else # define CATCH_CONFIG_COLOUR_ANSI # endif #endif #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// namespace Catch { namespace { class Win32ColourImpl : public IColourImpl { public: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); case Colour::Grey: return setTextAttribute( 0 ); case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } private: void setTextAttribute( WORD _textAttribute ) { SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; WORD originalForegroundAttributes; WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; Ptr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) colourMode = !isDebuggerActive() ? UseColour::Yes : UseColour::No; return colourMode == UseColour::Yes ? &s_instance : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// #include namespace Catch { namespace { // use POSIX/ ANSI console terminal codes // Thanks to Adam Strzelecki for original contribution // (http://github.com/nanoant) // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); case Colour::Red: return setColour( "[0;31m" ); case Colour::Green: return setColour( "[0;32m" ); case Colour::Blue: return setColour( "[0;34m" ); case Colour::Cyan: return setColour( "[0;36m" ); case Colour::Yellow: return setColour( "[0;33m" ); case Colour::Grey: return setColour( "[1;30m" ); case Colour::LightGrey: return setColour( "[0;37m" ); case Colour::BrightRed: return setColour( "[1;31m" ); case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } static IColourImpl* instance() { static PosixColourImpl s_instance; return &s_instance; } private: void setColour( const char* _escapeCode ) { Catch::cout() << '\033' << _escapeCode; } }; IColourImpl* platformColourInstance() { ErrnoGuard guard; Ptr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) ? UseColour::Yes : UseColour::No; return colourMode == UseColour::Yes ? PosixColourImpl::instance() : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #else // not Windows or ANSI /////////////////////////////////////////////// namespace Catch { static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } } // end namespace Catch #endif // Windows/ ANSI/ None namespace Catch { Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { static IColourImpl* impl = platformColourInstance(); impl->use( _colourCode ); } } // end namespace Catch // #included from: catch_generators_impl.hpp #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED #include #include #include namespace Catch { struct GeneratorInfo : IGeneratorInfo { GeneratorInfo( std::size_t size ) : m_size( size ), m_currentIndex( 0 ) {} bool moveNext() { if( ++m_currentIndex == m_size ) { m_currentIndex = 0; return false; } return true; } std::size_t getCurrentIndex() const { return m_currentIndex; } std::size_t m_size; std::size_t m_currentIndex; }; /////////////////////////////////////////////////////////////////////////// class GeneratorsForTest : public IGeneratorsForTest { public: ~GeneratorsForTest() { deleteAll( m_generatorsInOrder ); } IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { std::map::const_iterator it = m_generatorsByName.find( fileInfo ); if( it == m_generatorsByName.end() ) { IGeneratorInfo* info = new GeneratorInfo( size ); m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); m_generatorsInOrder.push_back( info ); return *info; } return *it->second; } bool moveNext() { std::vector::const_iterator it = m_generatorsInOrder.begin(); std::vector::const_iterator itEnd = m_generatorsInOrder.end(); for(; it != itEnd; ++it ) { if( (*it)->moveNext() ) return true; } return false; } private: std::map m_generatorsByName; std::vector m_generatorsInOrder; }; IGeneratorsForTest* createGeneratorsForTest() { return new GeneratorsForTest(); } } // end namespace Catch // #included from: catch_assertionresult.hpp #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED namespace Catch { AssertionInfo::AssertionInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, std::string const& _capturedExpression, ResultDisposition::Flags _resultDisposition ) : macroName( _macroName ), lineInfo( _lineInfo ), capturedExpression( _capturedExpression ), resultDisposition( _resultDisposition ) {} AssertionResult::AssertionResult() {} AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) : m_info( info ), m_resultData( data ) {} AssertionResult::~AssertionResult() {} // Result was a success bool AssertionResult::succeeded() const { return Catch::isOk( m_resultData.resultType ); } // Result was a success, or failure is suppressed bool AssertionResult::isOk() const { return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); } ResultWas::OfType AssertionResult::getResultType() const { return m_resultData.resultType; } bool AssertionResult::hasExpression() const { return !m_info.capturedExpression.empty(); } bool AssertionResult::hasMessage() const { return !m_resultData.message.empty(); } std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) return '!' + m_info.capturedExpression; else return m_info.capturedExpression; } std::string AssertionResult::getExpressionInMacro() const { if( m_info.macroName.empty() ) return m_info.capturedExpression; else return m_info.macroName + "( " + m_info.capturedExpression + " )"; } bool AssertionResult::hasExpandedExpression() const { return hasExpression() && getExpandedExpression() != getExpression(); } std::string AssertionResult::getExpandedExpression() const { return m_resultData.reconstructExpression(); } std::string AssertionResult::getMessage() const { return m_resultData.message; } SourceLineInfo AssertionResult::getSourceInfo() const { return m_info.lineInfo; } std::string AssertionResult::getTestMacroName() const { return m_info.macroName; } void AssertionResult::discardDecomposedExpression() const { m_resultData.decomposedExpression = CATCH_NULL; } void AssertionResult::expandDecomposedExpression() const { m_resultData.reconstructExpression(); } } // end namespace Catch // #included from: catch_test_case_info.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED #include namespace Catch { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { if( startsWith( tag, '.' ) || tag == "hide" || tag == "!hide" ) return TestCaseInfo::IsHidden; else if( tag == "!throws" ) return TestCaseInfo::Throws; else if( tag == "!shouldfail" ) return TestCaseInfo::ShouldFail; else if( tag == "!mayfail" ) return TestCaseInfo::MayFail; else if( tag == "!nonportable" ) return TestCaseInfo::NonPortable; else return TestCaseInfo::None; } inline bool isReservedTag( std::string const& tag ) { return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); } inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { if( isReservedTag( tag ) ) { std::ostringstream ss; ss << Colour(Colour::Red) << "Tag name [" << tag << "] not allowed.\n" << "Tag names starting with non alpha-numeric characters are reserved\n" << Colour(Colour::FileName) << _lineInfo << '\n'; throw std::runtime_error(ss.str()); } } TestCase makeTestCase( ITestCase* _testCase, std::string const& _className, std::string const& _name, std::string const& _descOrTags, SourceLineInfo const& _lineInfo ) { bool isHidden( startsWith( _name, "./" ) ); // Legacy support // Parse out tags std::set tags; std::string desc, tag; bool inTag = false; for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { char c = _descOrTags[i]; if( !inTag ) { if( c == '[' ) inTag = true; else desc += c; } else { if( c == ']' ) { TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); if( prop == TestCaseInfo::IsHidden ) isHidden = true; else if( prop == TestCaseInfo::None ) enforceNotReservedTag( tag, _lineInfo ); tags.insert( tag ); tag.clear(); inTag = false; } else tag += c; } } if( isHidden ) { tags.insert( "hide" ); tags.insert( "." ); } TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); return TestCase( _testCase, info ); } void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) { testCaseInfo.tags = tags; testCaseInfo.lcaseTags.clear(); std::ostringstream oss; for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { oss << '[' << *it << ']'; std::string lcaseTag = toLower( *it ); testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); testCaseInfo.lcaseTags.insert( lcaseTag ); } testCaseInfo.tagsAsString = oss.str(); } TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ) : name( _name ), className( _className ), description( _description ), lineInfo( _lineInfo ), properties( None ) { setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) : name( other.name ), className( other.className ), description( other.description ), tags( other.tags ), lcaseTags( other.lcaseTags ), tagsAsString( other.tagsAsString ), lineInfo( other.lineInfo ), properties( other.properties ) {} bool TestCaseInfo::isHidden() const { return ( properties & IsHidden ) != 0; } bool TestCaseInfo::throws() const { return ( properties & Throws ) != 0; } bool TestCaseInfo::okToFail() const { return ( properties & (ShouldFail | MayFail ) ) != 0; } bool TestCaseInfo::expectedToFail() const { return ( properties & (ShouldFail ) ) != 0; } TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} TestCase::TestCase( TestCase const& other ) : TestCaseInfo( other ), test( other.test ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); other.name = _newName; return other; } void TestCase::swap( TestCase& other ) { test.swap( other.test ); name.swap( other.name ); className.swap( other.className ); description.swap( other.description ); tags.swap( other.tags ); lcaseTags.swap( other.lcaseTags ); tagsAsString.swap( other.tagsAsString ); std::swap( TestCaseInfo::properties, static_cast( other ).properties ); std::swap( lineInfo, other.lineInfo ); } void TestCase::invoke() const { test->invoke(); } bool TestCase::operator == ( TestCase const& other ) const { return test.get() == other.test.get() && name == other.name && className == other.className; } bool TestCase::operator < ( TestCase const& other ) const { return name < other.name; } TestCase& TestCase::operator = ( TestCase const& other ) { TestCase temp( other ); swap( temp ); return *this; } TestCaseInfo const& TestCase::getTestCaseInfo() const { return *this; } } // end namespace Catch // #included from: catch_version.hpp #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED namespace Catch { Version::Version ( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, char const * const _branchName, unsigned int _buildNumber ) : majorVersion( _majorVersion ), minorVersion( _minorVersion ), patchNumber( _patchNumber ), branchName( _branchName ), buildNumber( _buildNumber ) {} std::ostream& operator << ( std::ostream& os, Version const& version ) { os << version.majorVersion << '.' << version.minorVersion << '.' << version.patchNumber; // branchName is never null -> 0th char is \0 if it is empty if (version.branchName[0]) { os << '-' << version.branchName << '.' << version.buildNumber; } return os; } inline Version libraryVersion() { static Version version( 1, 9, 4, "", 0 ); return version; } } // #included from: catch_message.hpp #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED namespace Catch { MessageInfo::MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), lineInfo( _lineInfo ), type( _type ), sequence( ++globalCount ) {} // This may need protecting if threading support is added unsigned int MessageInfo::globalCount = 0; //////////////////////////////////////////////////////////////////////////// ScopedMessage::ScopedMessage( MessageBuilder const& builder ) : m_info( builder.m_info ) { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } ScopedMessage::ScopedMessage( ScopedMessage const& other ) : m_info( other.m_info ) {} ScopedMessage::~ScopedMessage() { if ( !std::uncaught_exception() ){ getResultCapture().popScopedMessage(m_info); } } } // end namespace Catch // #included from: catch_legacy_reporter_adapter.hpp #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED // #included from: catch_legacy_reporter_adapter.h #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED namespace Catch { // Deprecated struct IReporter : IShared { virtual ~IReporter(); virtual bool shouldRedirectStdout() const = 0; virtual void StartTesting() = 0; virtual void EndTesting( Totals const& totals ) = 0; virtual void StartGroup( std::string const& groupName ) = 0; virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; virtual void Aborted() = 0; virtual void Result( AssertionResult const& result ) = 0; }; class LegacyReporterAdapter : public SharedImpl { public: LegacyReporterAdapter( Ptr const& legacyReporter ); virtual ~LegacyReporterAdapter(); virtual ReporterPreferences getPreferences() const; virtual void noMatchingTestCases( std::string const& ); virtual void testRunStarting( TestRunInfo const& ); virtual void testGroupStarting( GroupInfo const& groupInfo ); virtual void testCaseStarting( TestCaseInfo const& testInfo ); virtual void sectionStarting( SectionInfo const& sectionInfo ); virtual void assertionStarting( AssertionInfo const& ); virtual bool assertionEnded( AssertionStats const& assertionStats ); virtual void sectionEnded( SectionStats const& sectionStats ); virtual void testCaseEnded( TestCaseStats const& testCaseStats ); virtual void testGroupEnded( TestGroupStats const& testGroupStats ); virtual void testRunEnded( TestRunStats const& testRunStats ); virtual void skipTest( TestCaseInfo const& ); private: Ptr m_legacyReporter; }; } namespace Catch { LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) : m_legacyReporter( legacyReporter ) {} LegacyReporterAdapter::~LegacyReporterAdapter() {} ReporterPreferences LegacyReporterAdapter::getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); return prefs; } void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { m_legacyReporter->StartTesting(); } void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { m_legacyReporter->StartGroup( groupInfo.name ); } void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { m_legacyReporter->StartTestCase( testInfo ); } void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); } void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { // Not on legacy interface } bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); rb << it->message; rb.setResultType( ResultWas::Info ); AssertionResult result = rb.build(); m_legacyReporter->Result( result ); } } } m_legacyReporter->Result( assertionStats.assertionResult ); return true; } void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { if( sectionStats.missingAssertions ) m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); } void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { m_legacyReporter->EndTestCase ( testCaseStats.testInfo, testCaseStats.totals, testCaseStats.stdOut, testCaseStats.stdErr ); } void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { if( testGroupStats.aborting ) m_legacyReporter->Aborted(); m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); } void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { m_legacyReporter->EndTesting( testRunStats.totals ); } void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { } } // #included from: catch_timer.hpp #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc++11-long-long" #endif #ifdef CATCH_PLATFORM_WINDOWS #else #include #endif namespace Catch { namespace { #ifdef CATCH_PLATFORM_WINDOWS UInt64 getCurrentTicks() { static UInt64 hz=0, hzo=0; if (!hz) { QueryPerformanceFrequency( reinterpret_cast( &hz ) ); QueryPerformanceCounter( reinterpret_cast( &hzo ) ); } UInt64 t; QueryPerformanceCounter( reinterpret_cast( &t ) ); return ((t-hzo)*1000000)/hz; } #else UInt64 getCurrentTicks() { timeval t; gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif } void Timer::start() { m_ticks = getCurrentTicks(); } unsigned int Timer::getElapsedMicroseconds() const { return static_cast(getCurrentTicks() - m_ticks); } unsigned int Timer::getElapsedMilliseconds() const { return static_cast(getElapsedMicroseconds()/1000); } double Timer::getElapsedSeconds() const { return getElapsedMicroseconds()/1000000.0; } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_common.hpp #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED #include #include namespace Catch { bool startsWith( std::string const& s, std::string const& prefix ) { return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); } bool startsWith( std::string const& s, char prefix ) { return !s.empty() && s[0] == prefix; } bool endsWith( std::string const& s, std::string const& suffix ) { return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); } bool endsWith( std::string const& s, char suffix ) { return !s.empty() && s[s.size()-1] == suffix; } bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } char toLowerCh(char c) { return static_cast( std::tolower( c ) ); } void toLowerInPlace( std::string& s ) { std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } std::string toLower( std::string const& s ) { std::string lc = s; toLowerInPlace( lc ); return lc; } std::string trim( std::string const& str ) { static char const* whitespaceChars = "\n\r\t "; std::string::size_type start = str.find_first_not_of( whitespaceChars ); std::string::size_type end = str.find_last_not_of( whitespaceChars ); return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); } bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { bool replaced = false; std::size_t i = str.find( replaceThis ); while( i != std::string::npos ) { replaced = true; str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); if( i < str.size()-withThis.size() ) i = str.find( replaceThis, i+withThis.size() ); else i = std::string::npos; } return replaced; } pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) {} std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { os << pluraliser.m_count << ' ' << pluraliser.m_label; if( pluraliser.m_count != 1 ) os << 's'; return os; } SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) : file( _file ), line( _line ) {} bool SourceLineInfo::empty() const { return file[0] == '\0'; } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); } bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); } void seedRng( IConfig const& config ) { if( config.rngSeed() != 0 ) std::srand( config.rngSeed() ); } unsigned int rngSeed() { return getCurrentContext().getConfig()->rngSeed(); } std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << '(' << info.line << ')'; #else os << info.file << ':' << info.line; #endif return os; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { std::ostringstream oss; oss << locationInfo << ": Internal Catch error: '" << message << '\''; if( alwaysTrue() ) throw std::logic_error( oss.str() ); } } // #included from: catch_section.hpp #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED namespace Catch { SectionInfo::SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description ) : name( _name ), description( _description ), lineInfo( _lineInfo ) {} Section::Section( SectionInfo const& info ) : m_info( info ), m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) { m_timer.start(); } Section::~Section() { if( m_sectionIncluded ) { SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); if( std::uncaught_exception() ) getResultCapture().sectionEndedEarly( endInfo ); else getResultCapture().sectionEnded( endInfo ); } } // This indicates whether the section should be executed or not Section::operator bool() const { return m_sectionIncluded; } } // end namespace Catch // #included from: catch_debugger.hpp #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #ifdef CATCH_PLATFORM_MAC #include #include #include #include #include namespace Catch{ // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). bool isDebuggerActive(){ int mib[4]; struct kinfo_proc info; size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } // We're being debugged if the P_TRACED flag is set. return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } } // namespace Catch #elif defined(CATCH_PLATFORM_LINUX) #include #include namespace Catch{ // The standard POSIX way of detecting a debugger is to attempt to // ptrace() the process, but this needs to be done from a child and not // this process itself to still allow attaching to this process later // if wanted, so is rather heavy. Under Linux we have the PID of the // "debugger" (which doesn't need to be gdb, of course, it could also // be strace, for example) in /proc/$PID/status, so just get it from // there instead. bool isDebuggerActive(){ // Libstdc++ has a bug, where std::ifstream sets errno to 0 // This way our users can properly assert over errno values ErrnoGuard guard; std::ifstream in("/proc/self/status"); for( std::string line; std::getline(in, line); ) { static const int PREFIX_LEN = 11; if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { // We're traced if the PID is not 0 and no other PID starts // with 0 digit, so it's enough to check for just a single // character. return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; } } return false; } } // namespace Catch #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #else namespace Catch { inline bool isDebuggerActive() { return false; } } #endif // Platform #ifdef CATCH_PLATFORM_WINDOWS namespace Catch { void writeToDebugConsole( std::string const& text ) { ::OutputDebugStringA( text.c_str() ); } } #else namespace Catch { void writeToDebugConsole( std::string const& text ) { // !TBD: Need a version for Mac/ XCode and other IDEs Catch::cout() << text; } } #endif // Platform // #included from: catch_tostring.hpp #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED namespace Catch { namespace Detail { const std::string unprintableString = "{?}"; namespace { const int hexThreshold = 255; struct Endianness { enum Arch { Big, Little }; static Arch which() { union _{ int asInt; char asChar[sizeof (int)]; } u; u.asInt = 1; return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; } }; } std::string rawMemoryToString( const void *object, std::size_t size ) { // Reverse order for little endian architectures int i = 0, end = static_cast( size ), inc = 1; if( Endianness::which() == Endianness::Little ) { i = end-1; end = inc = -1; } unsigned char const *bytes = static_cast(object); std::ostringstream os; os << "0x" << std::setfill('0') << std::hex; for( ; i != end; i += inc ) os << std::setw(2) << static_cast(bytes[i]); return os.str(); } } std::string toString( std::string const& value ) { std::string s = value; if( getCurrentContext().getConfig()->showInvisibles() ) { for(size_t i = 0; i < s.size(); ++i ) { std::string subs; switch( s[i] ) { case '\n': subs = "\\n"; break; case '\t': subs = "\\t"; break; default: break; } if( !subs.empty() ) { s = s.substr( 0, i ) + subs + s.substr( i+1 ); ++i; } } } return '"' + s + '"'; } std::string toString( std::wstring const& value ) { std::string s; s.reserve( value.size() ); for(size_t i = 0; i < value.size(); ++i ) s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; return Catch::toString( s ); } std::string toString( const char* const value ) { return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); } std::string toString( char* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( const wchar_t* const value ) { return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); } std::string toString( wchar_t* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( int value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } std::string toString( unsigned int value ) { return Catch::toString( static_cast( value ) ); } template std::string fpToString( T value, int precision ) { std::ostringstream oss; oss << std::setprecision( precision ) << std::fixed << value; std::string d = oss.str(); std::size_t i = d.find_last_not_of( '0' ); if( i != std::string::npos && i != d.size()-1 ) { if( d[i] == '.' ) i++; d = d.substr( 0, i+1 ); } return d; } std::string toString( const double value ) { return fpToString( value, 10 ); } std::string toString( const float value ) { return fpToString( value, 5 ) + 'f'; } std::string toString( bool value ) { return value ? "true" : "false"; } std::string toString( char value ) { if ( value == '\r' ) return "'\\r'"; if ( value == '\f' ) return "'\\f'"; if ( value == '\n' ) return "'\\n'"; if ( value == '\t' ) return "'\\t'"; if ( '\0' <= value && value < ' ' ) return toString( static_cast( value ) ); char chstr[] = "' '"; chstr[1] = value; return chstr; } std::string toString( signed char value ) { return toString( static_cast( value ) ); } std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } #ifdef CATCH_CONFIG_CPP11_LONG_LONG std::string toString( long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } std::string toString( unsigned long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } #endif #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; } #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSObject* const& nsObject ) { return toString( [nsObject description] ); } #endif } // end namespace Catch // #included from: catch_result_builder.hpp #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED namespace Catch { std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { return secondArg.empty() || secondArg == "\"\"" ? capturedExpression : capturedExpression + ", " + secondArg; } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg ) : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ), m_guardException( false ) {} ResultBuilder::~ResultBuilder() { #if defined(CATCH_CONFIG_FAST_COMPILE) if ( m_guardException ) { m_stream.oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; captureResult( ResultWas::ThrewException ); getCurrentContext().getResultCapture()->exceptionEarlyReported(); } #endif } ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { m_data.resultType = result; return *this; } ResultBuilder& ResultBuilder::setResultType( bool result ) { m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; return *this; } void ResultBuilder::endExpression( DecomposedExpression const& expr ) { AssertionResult result = build( expr ); handleResult( result ); } void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { m_assertionInfo.resultDisposition = resultDisposition; m_stream.oss << Catch::translateActiveException(); captureResult( ResultWas::ThrewException ); } void ResultBuilder::captureResult( ResultWas::OfType resultType ) { setResultType( resultType ); captureExpression(); } void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { if( expectedMessage.empty() ) captureExpectedException( Matchers::Impl::MatchAllOf() ); else captureExpectedException( Matchers::Equals( expectedMessage ) ); } void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase const& matcher ) { assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); AssertionResultData data = m_data; data.resultType = ResultWas::Ok; data.reconstructedExpression = m_assertionInfo.capturedExpression; std::string actualMessage = Catch::translateActiveException(); if( !matcher.match( actualMessage ) ) { data.resultType = ResultWas::ExpressionFailed; data.reconstructedExpression = actualMessage; } AssertionResult result( m_assertionInfo, data ); handleResult( result ); } void ResultBuilder::captureExpression() { AssertionResult result = build(); handleResult( result ); } void ResultBuilder::handleResult( AssertionResult const& result ) { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { if( getCurrentContext().getConfig()->shouldDebugBreak() ) m_shouldDebugBreak = true; if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) m_shouldThrow = true; } } void ResultBuilder::react() { #if defined(CATCH_CONFIG_FAST_COMPILE) if (m_shouldDebugBreak) { /////////////////////////////////////////////////////////////////// // To inspect the state during test, you need to go one level up the callstack // To go back to the test and change execution, jump over the throw statement /////////////////////////////////////////////////////////////////// CATCH_BREAK_INTO_DEBUGGER(); } #endif if( m_shouldThrow ) throw Catch::TestFailureException(); } bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } AssertionResult ResultBuilder::build() const { return build( *this ); } // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, // a temporary DecomposedExpression, which in turn holds references to // operands, possibly temporary as well. // It should immediately be passed to handleResult; if the expression // needs to be reported, its string expansion must be composed before // the temporaries are destroyed. AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const { assert( m_data.resultType != ResultWas::Unknown ); AssertionResultData data = m_data; // Flip bool results if FalseTest flag is set if( isFalseTest( m_assertionInfo.resultDisposition ) ) { data.negate( expr.isBinaryExpression() ); } data.message = m_stream.oss.str(); data.decomposedExpression = &expr; // for lazy reconstruction return AssertionResult( m_assertionInfo, data ); } void ResultBuilder::reconstructExpression( std::string& dest ) const { dest = m_assertionInfo.capturedExpression; } void ResultBuilder::setExceptionGuard() { m_guardException = true; } void ResultBuilder::unsetExceptionGuard() { m_guardException = false; } } // end namespace Catch // #included from: catch_tag_alias_registry.hpp #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} Option TagAliasRegistry::find( std::string const& alias ) const { std::map::const_iterator it = m_registry.find( alias ); if( it != m_registry.end() ) return it->second; else return Option(); } std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { std::string expandedTestSpec = unexpandedTestSpec; for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); it != itEnd; ++it ) { std::size_t pos = expandedTestSpec.find( it->first ); if( pos != std::string::npos ) { expandedTestSpec = expandedTestSpec.substr( 0, pos ) + it->second.tag + expandedTestSpec.substr( pos + it->first.size() ); } } return expandedTestSpec; } void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { std::ostringstream oss; oss << Colour( Colour::Red ) << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << Colour( Colour::FileName ) << lineInfo << '\n'; throw std::domain_error( oss.str().c_str() ); } if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { std::ostringstream oss; oss << Colour( Colour::Red ) << "error: tag alias, \"" << alias << "\" already registered.\n" << "\tFirst seen at " << Colour( Colour::Red ) << find(alias)->lineInfo << '\n' << Colour( Colour::Red ) << "\tRedefined at " << Colour( Colour::FileName) << lineInfo << '\n'; throw std::domain_error( oss.str().c_str() ); } } ITagAliasRegistry::~ITagAliasRegistry() {} ITagAliasRegistry const& ITagAliasRegistry::get() { return getRegistryHub().getTagAliasRegistry(); } RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo ); } } // end namespace Catch // #included from: catch_matchers_string.hpp namespace Catch { namespace Matchers { namespace StdString { CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_str( adjustString( str ) ) {} std::string CasedString::adjustString( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } std::string CasedString::caseSensitivitySuffix() const { return m_caseSensitivity == CaseSensitive::No ? " (case insensitive)" : std::string(); } StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) : m_comparator( comparator ), m_operation( operation ) { } std::string StringMatcherBase::describe() const { std::string description; description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + m_comparator.caseSensitivitySuffix().size()); description += m_operation; description += ": \""; description += m_comparator.m_str; description += "\""; description += m_comparator.caseSensitivitySuffix(); return description; } EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} bool EqualsMatcher::match( std::string const& source ) const { return m_comparator.adjustString( source ) == m_comparator.m_str; } ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} bool ContainsMatcher::match( std::string const& source ) const { return contains( m_comparator.adjustString( source ), m_comparator.m_str ); } StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} bool StartsWithMatcher::match( std::string const& source ) const { return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); } EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} bool EndsWithMatcher::match( std::string const& source ) const { return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); } } // namespace StdString StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); } } // namespace Matchers } // namespace Catch // #included from: ../reporters/catch_reporter_multi.hpp #define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED namespace Catch { class MultipleReporters : public SharedImpl { typedef std::vector > Reporters; Reporters m_reporters; public: void add( Ptr const& reporter ) { m_reporters.push_back( reporter ); } public: // IStreamingReporter virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporters[0]->getPreferences(); } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->noMatchingTestCases( spec ); } virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testRunStarting( testRunInfo ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testGroupStarting( groupInfo ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testCaseStarting( testInfo ); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->sectionStarting( sectionInfo ); } virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->assertionStarting( assertionInfo ); } // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { bool clearBuffer = false; for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) clearBuffer |= (*it)->assertionEnded( assertionStats ); return clearBuffer; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->sectionEnded( sectionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testGroupEnded( testGroupStats ); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testRunEnded( testRunStats ); } virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->skipTest( testInfo ); } virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { return this; } }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { Ptr resultingReporter; if( existingReporter ) { MultipleReporters* multi = existingReporter->tryAsMulti(); if( !multi ) { multi = new MultipleReporters; resultingReporter = Ptr( multi ); if( existingReporter ) multi->add( existingReporter ); } else resultingReporter = existingReporter; multi->add( additionalReporter ); } else resultingReporter = additionalReporter; return resultingReporter; } } // end namespace Catch // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED // #included from: catch_reporter_bases.hpp #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED #include #include #include #include namespace Catch { namespace { // Because formatting using c++ streams is stateful, drop down to C is required // Alternatively we could use stringstream, but its performance is... not good. std::string getFormattedDuration( double duration ) { // Max exponent + 1 is required to represent the whole part // + 1 for decimal point // + 3 for the 3 decimal places // + 1 for null terminator const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; char buffer[maxDoubleSize]; // Save previous errno, to prevent sprintf from overwriting it ErrnoGuard guard; #ifdef _MSC_VER sprintf_s(buffer, "%.3f", duration); #else sprintf(buffer, "%.3f", duration); #endif return std::string(buffer); } } struct StreamingReporterBase : SharedImpl { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; } virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporterPrefs; } virtual ~StreamingReporterBase() CATCH_OVERRIDE; virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; LazyStat currentGroupInfo; LazyStat currentTestCaseInfo; std::vector m_sectionStack; ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { template struct Node : SharedImpl<> { explicit Node( T const& _value ) : value( _value ) {} virtual ~Node() {} typedef std::vector > ChildNodes; T value; ChildNodes children; }; struct SectionNode : SharedImpl<> { explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} virtual ~SectionNode(); bool operator == ( SectionNode const& other ) const { return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; } bool operator == ( Ptr const& other ) const { return operator==( *other ); } SectionStats stats; typedef std::vector > ChildSections; typedef std::vector Assertions; ChildSections childSections; Assertions assertions; std::string stdOut; std::string stdErr; }; struct BySectionInfo { BySectionInfo( SectionInfo const& other ) : m_other( other ) {} BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} bool operator() ( Ptr const& node ) const { return node->stats.sectionInfo.lineInfo == m_other.lineInfo; } private: void operator=( BySectionInfo const& ); SectionInfo const& m_other; }; typedef Node TestCaseNode; typedef Node TestGroupNode; typedef Node TestRunNode; CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; } ~CumulativeReporterBase(); virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporterPrefs; } virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { if( !m_rootSection ) m_rootSection = new SectionNode( incompleteStats ); node = m_rootSection; } else { SectionNode& parentNode = *m_sectionStack.back(); SectionNode::ChildSections::const_iterator it = std::find_if( parentNode.childSections.begin(), parentNode.childSections.end(), BySectionInfo( sectionInfo ) ); if( it == parentNode.childSections.end() ) { node = new SectionNode( incompleteStats ); parentNode.childSections.push_back( node ); } else node = *it; } m_sectionStack.push_back( node ); m_deepestSection = node; } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); // AssertionResult holds a pointer to a temporary DecomposedExpression, // which getExpandedExpression() calls to build the expression string. // Our section stack copy of the assertionResult will likely outlive the // temporary, so it must be expanded or discarded now to avoid calling // a destroyed object later. prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); m_testCases.push_back( node ); m_rootSection.reset(); assert( m_deepestSection ); m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); testRunEndedCumulative(); } virtual void testRunEndedCumulative() = 0; virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} virtual void prepareExpandedExpression( AssertionResult& result ) const { if( result.isOk() ) result.discardDecomposedExpression(); else result.expandDecomposedExpression(); } Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; std::vector > m_testCases; std::vector > m_testGroups; std::vector > m_testRuns; Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; ReporterPreferences m_reporterPrefs; }; template char const* getLineOfChars() { static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; if( !*line ) { std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; } return line; } struct TestEventListenerBase : StreamingReporterBase { TestEventListenerBase( ReporterConfig const& _config ) : StreamingReporterBase( _config ) {} virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { return false; } }; } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED namespace Catch { template class LegacyReporterRegistrar { class ReporterFactory : public IReporterFactory { virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new LegacyReporterAdapter( new T( config ) ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: LegacyReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; template class ReporterRegistrar { class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register // your custom reporter class be aware that the native reporter interface has changed // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. // However please consider updating to the new interface as the old one is now // deprecated and will probably be removed quite soon! // Please contact me via github if you have any questions at all about this. // In fact, ideally, please contact me anyway to let me know you've hit this - as I have // no idea who is actually using custom reporters at all (possibly no-one!). // The new interface is designed to minimise exposure to interface changes in the future. virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new T( config ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; template class ListenerRegistrar { class ListenerFactory : public SharedImpl { virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new T( config ); } virtual std::string getDescription() const { return std::string(); } }; public: ListenerRegistrar() { getMutableRegistryHub().registerListener( new ListenerFactory() ); } }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } // Deprecated - use the form without INTERNAL_ #define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } #define CATCH_REGISTER_LISTENER( listenerType ) \ namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include #include namespace Catch { class XmlEncode { public: enum ForWhat { ForTextNodes, ForAttributes }; XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) : m_str( str ), m_forWhat( forWhat ) {} void encodeTo( std::ostream& os ) const { // Apostrophe escaping not necessary if we always use " to write attributes // (see: http://www.w3.org/TR/xml/#syntax) for( std::size_t i = 0; i < m_str.size(); ++ i ) { char c = m_str[i]; switch( c ) { case '<': os << "<"; break; case '&': os << "&"; break; case '>': // See: http://www.w3.org/TR/xml/#syntax if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) os << ">"; else os << c; break; case '\"': if( m_forWhat == ForAttributes ) os << """; else os << c; break; default: // Escape control chars - based on contribution by @espenalb in PR #465 and // by @mrpi PR #588 if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast( c ); } else os << c; } } } friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { xmlEncode.encodeTo( os ); return os; } private: std::string m_str; ForWhat m_forWhat; }; class XmlWriter { public: class ScopedElement { public: ScopedElement( XmlWriter* writer ) : m_writer( writer ) {} ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ other.m_writer = CATCH_NULL; } ~ScopedElement() { if( m_writer ) m_writer->endElement(); } ScopedElement& writeText( std::string const& text, bool indent = true ) { m_writer->writeText( text, indent ); return *this; } template ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { m_writer->writeAttribute( name, attribute ); return *this; } private: mutable XmlWriter* m_writer; }; XmlWriter() : m_tagIsOpen( false ), m_needsNewline( false ), m_os( Catch::cout() ) { writeDeclaration(); } XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( os ) { writeDeclaration(); } ~XmlWriter() { while( !m_tags.empty() ) endElement(); } XmlWriter& startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); m_os << m_indent << '<' << name; m_tags.push_back( name ); m_indent += " "; m_tagIsOpen = true; return *this; } ScopedElement scopedElement( std::string const& name ) { ScopedElement scoped( this ); startElement( name ); return scoped; } XmlWriter& endElement() { newlineIfNecessary(); m_indent = m_indent.substr( 0, m_indent.size()-2 ); if( m_tagIsOpen ) { m_os << "/>"; m_tagIsOpen = false; } else { m_os << m_indent << ""; } m_os << std::endl; m_tags.pop_back(); return *this; } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { if( !name.empty() && !attribute.empty() ) m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; return *this; } XmlWriter& writeAttribute( std::string const& name, bool attribute ) { m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; return *this; } template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { std::ostringstream oss; oss << attribute; return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { if( !text.empty() ){ bool tagWasOpen = m_tagIsOpen; ensureTagClosed(); if( tagWasOpen && indent ) m_os << m_indent; m_os << XmlEncode( text ); m_needsNewline = true; } return *this; } XmlWriter& writeComment( std::string const& text ) { ensureTagClosed(); m_os << m_indent << ""; m_needsNewline = true; return *this; } void writeStylesheetRef( std::string const& url ) { m_os << "\n"; } XmlWriter& writeBlankLine() { ensureTagClosed(); m_os << '\n'; return *this; } void ensureTagClosed() { if( m_tagIsOpen ) { m_os << ">" << std::endl; m_tagIsOpen = false; } } private: XmlWriter( XmlWriter const& ); void operator=( XmlWriter const& ); void writeDeclaration() { m_os << "\n"; } void newlineIfNecessary() { if( m_needsNewline ) { m_os << std::endl; m_needsNewline = false; } } bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; std::string m_indent; std::ostream& m_os; }; } // #included from: catch_reenable_warnings.h #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(pop) # else # pragma clang diagnostic pop # endif #elif defined __GNUC__ # pragma GCC diagnostic pop #endif namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_xml(_config.stream()), m_sectionDepth( 0 ) { m_reporterPrefs.shouldRedirectStdOut = true; } virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as an XML document"; } virtual std::string getStylesheetRef() const { return std::string(); } void writeSourceInfo( SourceLineInfo const& sourceInfo ) { m_xml .writeAttribute( "filename", sourceInfo.file ) .writeAttribute( "line", sourceInfo.line ); } public: // StreamingReporterBase virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); std::string stylesheetRef = getStylesheetRef(); if( !stylesheetRef.empty() ) m_xml.writeStylesheetRef( stylesheetRef ); m_xml.startElement( "Catch" ); if( !m_config->name().empty() ) m_xml.writeAttribute( "name", m_config->name() ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ) .writeAttribute( "name", trim( testInfo.name ) ) .writeAttribute( "description", testInfo.description ) .writeAttribute( "tags", testInfo.tagsAsString ); writeSourceInfo( testInfo.lineInfo ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); m_xml.ensureTagClosed(); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) .writeAttribute( "name", trim( sectionInfo.name ) ) .writeAttribute( "description", sectionInfo.description ); writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); if( includeResults ) { // Print any info messages in tags. for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { m_xml.scopedElement( "Info" ) .writeText( it->message ); } else if ( it->type == ResultWas::Warning ) { m_xml.scopedElement( "Warning" ) .writeText( it->message ); } } } // Drop out if result was successful but we're not printing them. if( !includeResults && result.getResultType() != ResultWas::Warning ) return true; // Print the expression if there is one. if( result.hasExpression() ) { m_xml.startElement( "Expression" ) .writeAttribute( "success", result.succeeded() ) .writeAttribute( "type", result.getTestMacroName() ); writeSourceInfo( result.getSourceInfo() ); m_xml.scopedElement( "Original" ) .writeText( result.getExpression() ); m_xml.scopedElement( "Expanded" ) .writeText( result.getExpandedExpression() ); } // And... Print a result applicable to each result type. switch( result.getResultType() ) { case ResultWas::ThrewException: m_xml.startElement( "Exception" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; case ResultWas::FatalErrorCondition: m_xml.startElement( "FatalErrorCondition" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; case ResultWas::Info: m_xml.scopedElement( "Info" ) .writeText( result.getMessage() ); break; case ResultWas::Warning: // Warning will already have been written break; case ResultWas::ExplicitFailure: m_xml.startElement( "Failure" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; default: break; } if( result.hasExpression() ) m_xml.endElement(); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); e.writeAttribute( "successes", sectionStats.assertions.passed ); e.writeAttribute( "failures", sectionStats.assertions.failed ); e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); m_xml.endElement(); } } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); if( !testCaseStats.stdOut.empty() ) m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); if( !testCaseStats.stdErr.empty() ) m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); m_xml.endElement(); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); m_xml.endElement(); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); m_xml.endElement(); } private: Timer m_testCaseTimer; XmlWriter m_xml; int m_sectionDepth; }; INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_junit.hpp #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED #include namespace Catch { namespace { std::string getCurrentTimestamp() { // Beware, this is not reentrant because of backward compatibility issues // Also, UTC only, again because of backward compatibility (%z is C++11) time_t rawtime; std::time(&rawtime); const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); #ifdef _MSC_VER std::tm timeInfo = {}; gmtime_s(&timeInfo, &rawtime); #else std::tm* timeInfo; timeInfo = std::gmtime(&rawtime); #endif char timeStamp[timeStampSize]; const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif return std::string(timeStamp); } } class JunitReporter : public CumulativeReporterBase { public: JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ), m_okToFail( false ) { m_reporterPrefs.shouldRedirectStdOut = true; } virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); unexpectedExceptions = 0; CumulativeReporterBase::testGroupStarting( groupInfo ); } virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE { m_okToFail = testCaseInfo.okToFail(); } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); TestGroupStats const& stats = groupNode.value; xml.writeAttribute( "name", stats.groupInfo.name ); xml.writeAttribute( "errors", unexpectedExceptions ); xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); xml.writeAttribute( "tests", stats.totals.assertions.total() ); xml.writeAttribute( "hostname", "tbd" ); // !TBD if( m_config->showDurations() == ShowDurations::Never ) xml.writeAttribute( "time", "" ); else xml.writeAttribute( "time", suiteTime ); xml.writeAttribute( "timestamp", getCurrentTimestamp() ); // Write test cases for( TestGroupNode::ChildNodes::const_iterator it = groupNode.children.begin(), itEnd = groupNode.children.end(); it != itEnd; ++it ) writeTestCase( **it ); xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); } void writeTestCase( TestCaseNode const& testCaseNode ) { TestCaseStats const& stats = testCaseNode.value; // All test cases have exactly one section - which represents the // test case itself. That section may have 0-n nested sections assert( testCaseNode.children.size() == 1 ); SectionNode const& rootSection = *testCaseNode.children.front(); std::string className = stats.testInfo.className; if( className.empty() ) { if( rootSection.childSections.empty() ) className = "global"; } writeSection( className, "", rootSection ); } void writeSection( std::string const& className, std::string const& rootName, SectionNode const& sectionNode ) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + '/' + name; if( !sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty() ) { XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); if( className.empty() ) { xml.writeAttribute( "classname", name ); xml.writeAttribute( "name", "root" ); } else { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); writeAssertions( sectionNode ); if( !sectionNode.stdOut.empty() ) xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); if( !sectionNode.stdErr.empty() ) xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } for( SectionNode::ChildSections::const_iterator it = sectionNode.childSections.begin(), itEnd = sectionNode.childSections.end(); it != itEnd; ++it ) if( className.empty() ) writeSection( name, "", **it ); else writeSection( className, name, **it ); } void writeAssertions( SectionNode const& sectionNode ) { for( SectionNode::Assertions::const_iterator it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); it != itEnd; ++it ) writeAssertion( *it ); } void writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; if( !result.isOk() ) { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: case ResultWas::FatalErrorCondition: elementName = "error"; break; case ResultWas::ExplicitFailure: elementName = "failure"; break; case ResultWas::ExpressionFailed: elementName = "failure"; break; case ResultWas::DidntThrowException: elementName = "failure"; break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: case ResultWas::Ok: case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: elementName = "internalError"; break; } XmlWriter::ScopedElement e = xml.scopedElement( elementName ); xml.writeAttribute( "message", result.getExpandedExpression() ); xml.writeAttribute( "type", result.getTestMacroName() ); std::ostringstream oss; if( !result.getMessage().empty() ) oss << result.getMessage() << '\n'; for( std::vector::const_iterator it = stats.infoMessages.begin(), itEnd = stats.infoMessages.end(); it != itEnd; ++it ) if( it->type == ResultWas::Info ) oss << it->message << '\n'; oss << "at " << result.getSourceInfo(); xml.writeText( oss.str(), false ); } } XmlWriter xml; Timer suiteTimer; std::ostringstream stdOutForSuite; std::ostringstream stdErrForSuite; unsigned int unexpectedExceptions; bool m_okToFail; }; INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_console.hpp #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED #include #include namespace Catch { struct ConsoleReporter : StreamingReporterBase { ConsoleReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_headerPrinted( false ) {} virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << '\'' << std::endl; } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); // Drop out if result was successful but we're not printing them. if( !includeResults && result.getResultType() != ResultWas::Warning ) return false; lazyPrint(); AssertionPrinter printer( stream, _assertionStats, includeResults ); printer.print(); stream << std::endl; return true; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); if( m_sectionStack.size() > 1 ) stream << "\nNo assertions in section"; else stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } if( m_config->showDurations() == ShowDurations::Always ) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } if( m_headerPrinted ) { m_headerPrinted = false; } StreamingReporterBase::sectionEnded( _sectionStats ); } virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; printTotals( _testGroupStats.totals ); stream << '\n' << std::endl; } StreamingReporterBase::testGroupEnded( _testGroupStats ); } virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ), stats( _stats ), result( _stats.assertionResult ), colour( Colour::None ), message( result.getMessage() ), messages( _stats.infoMessages ), printInfoMessages( _printInfoMessages ) { switch( result.getResultType() ) { case ResultWas::Ok: colour = Colour::Success; passOrFail = "PASSED"; //if( result.hasMessage() ) if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ExpressionFailed: if( result.isOk() ) { colour = Colour::Success; passOrFail = "FAILED - but was ok"; } else { colour = Colour::Error; passOrFail = "FAILED"; } if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to unexpected exception with "; if (_stats.infoMessages.size() == 1) messageLabel += "message"; if (_stats.infoMessages.size() > 1) messageLabel += "messages"; break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to a fatal error condition"; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "because no exception was thrown where one was expected"; break; case ResultWas::Info: messageLabel = "info"; break; case ResultWas::Warning: messageLabel = "warning"; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"; colour = Colour::Error; if( _stats.infoMessages.size() == 1 ) messageLabel = "explicitly with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "explicitly with messages"; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: passOrFail = "** internal error **"; colour = Colour::Error; break; } } void print() const { printSourceInfo(); if( stats.totals.assertions.total() > 0 ) { if( result.isOk() ) stream << '\n'; printResultType(); printOriginalExpression(); printReconstructedExpression(); } else { stream << '\n'; } printMessage(); } private: void printResultType() const { if( !passOrFail.empty() ) { Colour colourGuard( colour ); stream << passOrFail << ":\n"; } } void printOriginalExpression() const { if( result.hasExpression() ) { Colour colourGuard( Colour::OriginalExpression ); stream << " "; stream << result.getExpressionInMacro(); stream << '\n'; } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { stream << "with expansion:\n"; Colour colourGuard( Colour::ReconstructedExpression ); stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; } } void printMessage() const { if( !messageLabel.empty() ) stream << messageLabel << ':' << '\n'; for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); it != itEnd; ++it ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || it->type != ResultWas::Info ) stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; } } void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ": "; } std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; Colour::Code colour; std::string passOrFail; std::string messageLabel; std::string message; std::vector messages; bool printInfoMessages; }; void lazyPrint() { if( !currentTestRunInfo.used ) lazyPrintRunInfo(); if( !currentGroupInfo.used ) lazyPrintGroupInfo(); if( !m_headerPrinted ) { printTestCaseAndSectionHeader(); m_headerPrinted = true; } } void lazyPrintRunInfo() { stream << '\n' << getLineOfChars<'~'>() << '\n'; Colour colour( Colour::SecondaryText ); stream << currentTestRunInfo->name << " is a Catch v" << libraryVersion() << " host application.\n" << "Run with -? for options\n\n"; if( m_config->rngSeed() != 0 ) stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; currentTestRunInfo.used = true; } void lazyPrintGroupInfo() { if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { printClosedHeader( "Group: " + currentGroupInfo->name ); currentGroupInfo.used = true; } } void printTestCaseAndSectionHeader() { assert( !m_sectionStack.empty() ); printOpenHeader( currentTestCaseInfo->name ); if( m_sectionStack.size() > 1 ) { Colour colourGuard( Colour::Headers ); std::vector::const_iterator it = m_sectionStack.begin()+1, // Skip first section (test case) itEnd = m_sectionStack.end(); for( ; it != itEnd; ++it ) printHeaderString( it->name, 2 ); } SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; if( !lineInfo.empty() ){ stream << getLineOfChars<'-'>() << '\n'; Colour colourGuard( Colour::FileName ); stream << lineInfo << '\n'; } stream << getLineOfChars<'.'>() << '\n' << std::endl; } void printClosedHeader( std::string const& _name ) { printOpenHeader( _name ); stream << getLineOfChars<'.'>() << '\n'; } void printOpenHeader( std::string const& _name ) { stream << getLineOfChars<'-'>() << '\n'; { Colour colourGuard( Colour::Headers ); printHeaderString( _name ); } } // if string has a : in first line will set indent to follow it on // subsequent lines void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { std::size_t i = _string.find( ": " ); if( i != std::string::npos ) i+=2; else i = 0; stream << Text( _string, TextAttributes() .setIndent( indent+i) .setInitialIndent( indent ) ) << '\n'; } struct SummaryColumn { SummaryColumn( std::string const& _label, Colour::Code _colour ) : label( _label ), colour( _colour ) {} SummaryColumn addRow( std::size_t count ) { std::ostringstream oss; oss << count; std::string row = oss.str(); for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { while( it->size() < row.size() ) *it = ' ' + *it; while( it->size() > row.size() ) row = ' ' + row; } rows.push_back( row ); return *this; } std::string label; Colour::Code colour; std::vector rows; }; void printTotals( Totals const& totals ) { if( totals.testCases.total() == 0 ) { stream << Colour( Colour::Warning ) << "No tests ran\n"; } else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { stream << Colour( Colour::ResultSuccess ) << "All tests passed"; stream << " (" << pluralise( totals.assertions.passed, "assertion" ) << " in " << pluralise( totals.testCases.passed, "test case" ) << ')' << '\n'; } else { std::vector columns; columns.push_back( SummaryColumn( "", Colour::None ) .addRow( totals.testCases.total() ) .addRow( totals.assertions.total() ) ); columns.push_back( SummaryColumn( "passed", Colour::Success ) .addRow( totals.testCases.passed ) .addRow( totals.assertions.passed ) ); columns.push_back( SummaryColumn( "failed", Colour::ResultError ) .addRow( totals.testCases.failed ) .addRow( totals.assertions.failed ) ); columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) .addRow( totals.testCases.failedButOk ) .addRow( totals.assertions.failedButOk ) ); printSummaryRow( "test cases", columns, 0 ); printSummaryRow( "assertions", columns, 1 ); } } void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { std::string value = it->rows[row]; if( it->label.empty() ) { stream << label << ": "; if( value != "0" ) stream << value; else stream << Colour( Colour::Warning ) << "- none -"; } else if( value != "0" ) { stream << Colour( Colour::LightGrey ) << " | "; stream << Colour( it->colour ) << value << ' ' << it->label; } } stream << '\n'; } static std::size_t makeRatio( std::size_t number, std::size_t total ) { std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; return ( ratio == 0 && number > 0 ) ? 1 : ratio; } static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { if( i > j && i > k ) return i; else if( j > k ) return j; else return k; } void printTotalsDivider( Totals const& totals ) { if( totals.testCases.total() > 0 ) { std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )++; while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )--; stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); if( totals.testCases.allPassed() ) stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); else stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); } else { stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); } stream << '\n'; } void printSummaryDivider() { stream << getLineOfChars<'-'>() << '\n'; } private: bool m_headerPrinted; }; INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_compact.hpp #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED namespace Catch { struct CompactReporter : StreamingReporterBase { CompactReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ) {} virtual ~CompactReporter(); static std::string getDescription() { return "Reports test results on a single line, suitable for IDEs"; } virtual ReporterPreferences getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = false; return prefs; } virtual void noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } virtual void assertionStarting( AssertionInfo const& ) {} virtual bool assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { if( result.getResultType() != ResultWas::Warning ) return false; printInfoMessages = false; } AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); printer.print(); stream << std::endl; return true; } virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE { if (m_config->showDurations() == ShowDurations::Always) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } virtual void testRunEnded( TestRunStats const& _testRunStats ) { printTotals( _testRunStats.totals ); stream << '\n' << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ) , stats( _stats ) , result( _stats.assertionResult ) , messages( _stats.infoMessages ) , itMessage( _stats.infoMessages.begin() ) , printInfoMessages( _printInfoMessages ) {} void print() { printSourceInfo(); itMessage = messages.begin(); switch( result.getResultType() ) { case ResultWas::Ok: printResultType( Colour::ResultSuccess, passedString() ); printOriginalExpression(); printReconstructedExpression(); if ( ! result.hasExpression() ) printRemainingMessages( Colour::None ); else printRemainingMessages(); break; case ResultWas::ExpressionFailed: if( result.isOk() ) printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); else printResultType( Colour::Error, failedString() ); printOriginalExpression(); printReconstructedExpression(); printRemainingMessages(); break; case ResultWas::ThrewException: printResultType( Colour::Error, failedString() ); printIssue( "unexpected exception with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::FatalErrorCondition: printResultType( Colour::Error, failedString() ); printIssue( "fatal error condition with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::DidntThrowException: printResultType( Colour::Error, failedString() ); printIssue( "expected exception, got none" ); printExpressionWas(); printRemainingMessages(); break; case ResultWas::Info: printResultType( Colour::None, "info" ); printMessage(); printRemainingMessages(); break; case ResultWas::Warning: printResultType( Colour::None, "warning" ); printMessage(); printRemainingMessages(); break; case ResultWas::ExplicitFailure: printResultType( Colour::Error, failedString() ); printIssue( "explicitly" ); printRemainingMessages( Colour::None ); break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: printResultType( Colour::Error, "** internal error **" ); break; } } private: // Colour::LightGrey static Colour::Code dimColour() { return Colour::FileName; } #ifdef CATCH_PLATFORM_MAC static const char* failedString() { return "FAILED"; } static const char* passedString() { return "PASSED"; } #else static const char* failedString() { return "failed"; } static const char* passedString() { return "passed"; } #endif void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ':'; } void printResultType( Colour::Code colour, std::string const& passOrFail ) const { if( !passOrFail.empty() ) { { Colour colourGuard( colour ); stream << ' ' << passOrFail; } stream << ':'; } } void printIssue( std::string const& issue ) const { stream << ' ' << issue; } void printExpressionWas() { if( result.hasExpression() ) { stream << ';'; { Colour colour( dimColour() ); stream << " expression was:"; } printOriginalExpression(); } } void printOriginalExpression() const { if( result.hasExpression() ) { stream << ' ' << result.getExpression(); } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { { Colour colour( dimColour() ); stream << " for: "; } stream << result.getExpandedExpression(); } } void printMessage() { if ( itMessage != messages.end() ) { stream << " '" << itMessage->message << '\''; ++itMessage; } } void printRemainingMessages( Colour::Code colour = dimColour() ) { if ( itMessage == messages.end() ) return; // using messages.end() directly yields compilation error: std::vector::const_iterator itEnd = messages.end(); const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); { Colour colourGuard( colour ); stream << " with " << pluralise( N, "message" ) << ':'; } for(; itMessage != itEnd; ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || itMessage->type != ResultWas::Info ) { stream << " '" << itMessage->message << '\''; if ( ++itMessage != itEnd ) { Colour colourGuard( dimColour() ); stream << " and"; } } } } private: std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; std::vector messages; std::vector::const_iterator itMessage; bool printInfoMessages; }; // Colour, message variants: // - white: No tests ran. // - red: Failed [both/all] N test cases, failed [both/all] M assertions. // - white: Passed [both/all] N test cases (no assertions). // - red: Failed N tests cases, failed M assertions. // - green: Passed [both/all] N tests cases with M assertions. std::string bothOrAll( std::size_t count ) const { return count == 1 ? std::string() : count == 2 ? "both " : "all " ; } void printTotals( const Totals& totals ) const { if( totals.testCases.total() == 0 ) { stream << "No tests ran."; } else if( totals.testCases.failed == totals.testCases.total() ) { Colour colour( Colour::ResultError ); const std::string qualify_assertions_failed = totals.assertions.failed == totals.assertions.total() ? bothOrAll( totals.assertions.failed ) : std::string(); stream << "Failed " << bothOrAll( totals.testCases.failed ) << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << qualify_assertions_failed << pluralise( totals.assertions.failed, "assertion" ) << '.'; } else if( totals.assertions.total() == 0 ) { stream << "Passed " << bothOrAll( totals.testCases.total() ) << pluralise( totals.testCases.total(), "test case" ) << " (no assertions)."; } else if( totals.assertions.failed ) { Colour colour( Colour::ResultError ); stream << "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; } else { Colour colour( Colour::ResultSuccess ); stream << "Passed " << bothOrAll( totals.testCases.passed ) << pluralise( totals.testCases.passed, "test case" ) << " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; } } }; INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch namespace Catch { // These are all here to avoid warnings about not having any out of line // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} IStream::~IStream() CATCH_NOEXCEPT {} FileStream::~FileStream() CATCH_NOEXCEPT {} CoutStream::~CoutStream() CATCH_NOEXCEPT {} DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} ITestCase::~ITestCase() {} ITestCaseRegistry::~ITestCaseRegistry() {} IRegistryHub::~IRegistryHub() {} IMutableRegistryHub::~IMutableRegistryHub() {} IExceptionTranslator::~IExceptionTranslator() {} IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} IReporter::~IReporter() {} IReporterFactory::~IReporterFactory() {} IReporterRegistry::~IReporterRegistry() {} IStreamingReporter::~IStreamingReporter() {} AssertionStats::~AssertionStats() {} SectionStats::~SectionStats() {} TestCaseStats::~TestCaseStats() {} TestGroupStats::~TestGroupStats() {} TestRunStats::~TestRunStats() {} CumulativeReporterBase::SectionNode::~SectionNode() {} CumulativeReporterBase::~CumulativeReporterBase() {} StreamingReporterBase::~StreamingReporterBase() {} ConsoleReporter::~ConsoleReporter() {} CompactReporter::~CompactReporter() {} IRunner::~IRunner() {} IMutableContext::~IMutableContext() {} IConfig::~IConfig() {} XmlReporter::~XmlReporter() {} JunitReporter::~JunitReporter() {} TestRegistry::~TestRegistry() {} FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} TestSpec::ExcludedPattern::~ExcludedPattern() {} Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {} void Config::dummy() {} namespace TestCaseTracking { ITracker::~ITracker() {} TrackerBase::~TrackerBase() {} SectionTracker::~SectionTracker() {} IndexTracker::~IndexTracker() {} } } #ifdef __clang__ #pragma clang diagnostic pop #endif #endif #ifdef CATCH_CONFIG_MAIN // #included from: internal/catch_default_main.hpp #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED #ifndef __OBJC__ #if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else // Standard C/C++ main entry point int main (int argc, char * argv[]) { #endif int result = Catch::Session().run( argc, argv ); return ( result < 0xff ? result : 0xff ); } #else // __OBJC__ // Objective-C entry point int main (int argc, char * const argv[]) { #if !CATCH_ARC_ENABLED NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; #endif Catch::registerTestMethods(); int result = Catch::Session().run( argc, (char* const*)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif return ( result < 0xff ? result : 0xff ); } #endif // __OBJC__ #endif #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL #if defined(CATCH_CONFIG_FAST_COMPILE) #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #else #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #endif #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #if defined(CATCH_CONFIG_FAST_COMPILE) #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #else #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #endif #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #else #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) #endif #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) #define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) #define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) #define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) #define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else #if defined(CATCH_CONFIG_FAST_COMPILE) #define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #else #define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #endif #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) #define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #if defined(CATCH_CONFIG_FAST_COMPILE) #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #else #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #endif #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #else #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) #endif #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) #define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) #define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) #define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) #define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED thrift-0.16.0/compiler/cpp/tests/netcore/000077500000000000000000000000001420101504100202575ustar00rootroot00000000000000thrift-0.16.0/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests.cc000066400000000000000000000252231420101504100302660ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #include "../catch/catch.hpp" #include #include #include "t_netstd_generator_functional_tests_helpers.h" TEST_CASE( "t_netstd_generator should generate valid enum", "[functional]" ) { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); std::pair pair = TestDataGenerator::get_test_enum_data(program); string expected_result = pair.first; t_enum* test_enum = pair.second; string file_path = test_enum->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_enum(out, test_enum)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete test_enum; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid void", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); std::pair pair = TestDataGenerator::get_test_void_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_THROWS(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); delete const_; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid string with escaping keyword", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); std::pair pair = TestDataGenerator::get_test_string_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete const_; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid bool with escaping keyword", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); std::pair pair = TestDataGenerator::get_test_bool_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete const_; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid sbyte (i8) with escaping keyword", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); std::pair pair = TestDataGenerator::get_test_i8_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete const_; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid short (i16) with escaping keyword", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); std::pair pair = TestDataGenerator::get_test_i16_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete const_; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid integer (i32) with escaping keyword", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); std::pair pair = TestDataGenerator::get_test_i32_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete const_; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid long (i64) with escaping keyword", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); std::pair pair = TestDataGenerator::get_test_i64_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete const_; delete gen; delete program; } TEST_CASE("t_netstd_generator should generate valid double with escaping keyword", "[functional]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); std::pair pair = TestDataGenerator::get_test_double_const_data(gen); string expected_result = pair.first; t_const* const_ = pair.second; vector consts_; consts_.push_back(const_); string file_path = const_->get_name() + ".cs"; ofstream out; out.open(file_path.c_str()); REQUIRE_NOTHROW(gen->generate_consts(out, consts_)); out.close(); std::ifstream ifs(file_path); string actual_result((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); std::remove(file_path.c_str()); REQUIRE(expected_result == actual_result); delete const_; delete gen; delete program; } thrift-0.16.0/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.cc000066400000000000000000000173351420101504100320150ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #include #include "thrift/common.h" #include #include "t_netstd_generator_functional_tests_helpers.h" const string TestDataGenerator::DEFAULT_FILE_HEADER = "/**" "\n" " * Autogenerated by Thrift Compiler ()" "\n" " *" "\n" " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING" "\n" " * @generated" "\n" " */"; std::pair TestDataGenerator::get_test_enum_data(t_program* program) { string expected_result = DEFAULT_FILE_HEADER + "\n" "\n" "/// \n" "/// TestDoc\n" "/// \n" "public enum TestName\n" "{\n" " None = 0,\n" " First = 1,\n" " Second = 2,\n" "}\n"; t_enum* enum_ = new t_enum(program); enum_->set_name("TestName"); enum_->set_doc("TestDoc"); enum_->append(new t_enum_value("None", 0)); enum_->append(new t_enum_value("First", 1)); enum_->append(new t_enum_value("Second", 2)); return std::pair(expected_result, enum_); } std::pair TestDataGenerator::get_test_void_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER; t_type* type_ = new t_base_type("void", t_base_type::TYPE_VOID); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_string("VoidValue"); t_const* const_ = new t_const(type_, "void", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } std::pair TestDataGenerator::get_test_string_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netstd_type_usings() + "\n" "public static class netstdConstants\n" "{\n" " /// \n" " /// TestDoc\n" " /// \n" " public const string @string = \"StringValue\";\n" "}\n"; t_type* type_ = new t_base_type("string", t_base_type::TYPE_STRING); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_string("StringValue"); t_const* const_ = new t_const(type_, "string", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } std::pair TestDataGenerator::get_test_bool_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netstd_type_usings() + "\n" "public static class netstdConstants\n" "{\n" " /// \n" " /// TestDoc\n" " /// \n" " public const bool @bool = true;\n" "}\n"; t_type* type_ = new t_base_type("bool", t_base_type::TYPE_BOOL); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_integer(1); t_const* const_ = new t_const(type_, "bool", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } std::pair TestDataGenerator::get_test_i8_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netstd_type_usings() + "\n" "public static class netstdConstants\n" "{\n" " /// \n" " /// TestDoc\n" " /// \n" " public const sbyte @sbyte = 127;\n" "}\n"; t_type* type_ = new t_base_type("I8", t_base_type::TYPE_I8); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_integer(127); t_const* const_ = new t_const(type_, "sbyte", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } std::pair TestDataGenerator::get_test_i16_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netstd_type_usings() + "\n" "public static class netstdConstants\n" "{\n" " /// \n" " /// TestDoc\n" " /// \n" " public const short @short = 32767;\n" "}\n"; t_type* type_ = new t_base_type("i16", t_base_type::TYPE_I16); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_integer(32767); t_const* const_ = new t_const(type_, "short", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } std::pair TestDataGenerator::get_test_i32_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netstd_type_usings() + "\n" "public static class netstdConstants\n" "{\n" " /// \n" " /// TestDoc\n" " /// \n" " public const int @int = 2147483647;\n" "}\n"; t_type* type_ = new t_base_type("i32", t_base_type::TYPE_I32); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_integer(2147483647); t_const* const_ = new t_const(type_, "int", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } std::pair TestDataGenerator::get_test_i64_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netstd_type_usings() + "\n" "public static class netstdConstants\n" "{\n" " /// \n" " /// TestDoc\n" " /// \n" " public const long @long = 9223372036854775807;\n" "}\n"; t_type* type_ = new t_base_type("i64", t_base_type::TYPE_I64); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_integer(9223372036854775807); t_const* const_ = new t_const(type_, "long", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } std::pair TestDataGenerator::get_test_double_const_data(t_netstd_generator* gen) { string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netstd_type_usings() + "\n" "public static class netstdConstants\n" "{\n" " /// \n" " /// TestDoc\n" " /// \n" " public const double @double = 9.22337e+18;\n" "}\n"; t_type* type_ = new t_base_type("double", t_base_type::TYPE_DOUBLE); type_->set_doc("TestDoc"); t_const_value* const_value_ = new t_const_value(); const_value_->set_double(9223372036854775807.1); t_const* const_ = new t_const(type_, "double", const_value_); const_->set_doc("TestDoc"); return std::pair(expected_result, const_); } thrift-0.16.0/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.h000066400000000000000000000032641420101504100316530ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #include class TestDataGenerator { public: static const string DEFAULT_FILE_HEADER; static std::pair get_test_enum_data(t_program* program); static std::pair get_test_void_const_data(t_netstd_generator* gen); static std::pair get_test_string_const_data(t_netstd_generator* gen); static std::pair get_test_bool_const_data(t_netstd_generator* gen); static std::pair get_test_i8_const_data(t_netstd_generator* gen); static std::pair get_test_i16_const_data(t_netstd_generator* gen); static std::pair get_test_i32_const_data(t_netstd_generator* gen); static std::pair get_test_i64_const_data(t_netstd_generator* gen); static std::pair get_test_double_const_data(t_netstd_generator* gen); }; thrift-0.16.0/compiler/cpp/tests/netcore/t_netcore_generator_helpers_tests.cc000066400000000000000000000144511420101504100275670ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #include "../catch/catch.hpp" #include #include using std::vector; TEST_CASE("t_netstd_generator::netstd_type_usings() without option wcf should return valid namespaces", "[helpers]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "union", "union" } }; string option_string = ""; string expected_namespaces = "using System;\n" "using System.Collections;\n" "using System.Collections.Generic;\n" "using System.Text;\n" "using System.IO;\n" "using System.Threading;\n" "using System.Threading.Tasks;\n" "using Thrift;\n" "using Thrift.Collections;\n" + endl; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); REQUIRE_FALSE(gen->is_wcf_enabled()); REQUIRE(gen->netstd_type_usings() == expected_namespaces); delete gen; delete program; } TEST_CASE("t_netstd_generator::netstd_type_usings() with option wcf should return valid namespaces", "[helpers]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; string expected_namespaces_wcf = "using System;\n" "using System.Collections;\n" "using System.Collections.Generic;\n" "using System.Text;\n" "using System.IO;\n" "using System.Threading;\n" "using System.Threading.Tasks;\n" "using Thrift;\n" "using Thrift.Collections;\n" "using System.ServiceModel;\n" "using System.Runtime.Serialization;\n" + endl; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); REQUIRE(gen->is_wcf_enabled()); REQUIRE(gen->netstd_type_usings() == expected_namespaces_wcf); delete gen; delete program; } TEST_CASE("t_netstd_generator should contains latest C# keywords to normalize with @", "[helpers]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" } }; string option_string = ""; vector current_keywords = { { "abstract" }, { "as" }, { "base" }, { "bool" }, { "break" }, { "byte" }, { "case" }, { "catch" }, { "char" }, { "checked" }, { "class" }, { "const" }, { "continue" }, { "decimal" }, { "default" }, { "delegate" }, { "do" }, { "double" }, { "else" }, { "enum" }, { "event" }, { "explicit" }, { "extern" }, { "false" }, { "finally" }, { "fixed" }, { "float" }, { "for" }, { "foreach" }, { "goto" }, { "if" }, { "implicit" }, { "in" }, { "int" }, { "interface" }, { "internal" }, { "is" }, { "lock" }, { "long" }, { "namespace" }, { "new" }, { "null" }, { "object" }, { "operator" }, { "out" }, { "override" }, { "params" }, { "private" }, { "protected" }, { "public" }, { "readonly" }, { "ref" }, { "return" }, { "sbyte" }, { "sealed" }, { "short" }, { "sizeof" }, { "stackalloc" }, { "static" }, { "string" }, { "struct" }, { "switch" }, { "this" }, { "throw" }, { "true" }, { "try" }, { "typeof" }, { "uint" }, { "ulong" }, { "unchecked" }, { "unsafe" }, { "ushort" }, { "using" }, { "void" }, { "volatile" }, { "while" }, // Contextual Keywords { "add" }, { "alias" }, { "ascending" }, { "async" }, { "await" }, { "descending" }, { "dynamic" }, { "from" }, { "get" }, { "global" }, { "group" }, { "into" }, { "join" }, { "let" }, { "orderby" }, { "partial" }, { "remove" }, { "select" }, { "set" }, { "value" }, { "var" }, { "when" }, { "where" }, { "yield" } }; string missed_keywords = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); gen->init_generator(); map generators_keywords = gen->get_keywords_list(); for (vector::iterator it = current_keywords.begin(); it != current_keywords.end(); ++it) { if (generators_keywords.find(*it) == generators_keywords.end()) { missed_keywords = missed_keywords + *it + ","; } } REQUIRE(missed_keywords == ""); delete gen; delete program; } thrift-0.16.0/compiler/cpp/tests/netcore/t_netcore_generator_initialization_tests.cc000066400000000000000000000051541420101504100311540ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #include "../catch/catch.hpp" #include #include TEST_CASE( "t_netstd_generator should throw error with unknown options", "[initialization]" ) { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "keys", "keys" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = nullptr; REQUIRE_THROWS(gen = new t_netstd_generator(program, parsed_options, option_string)); delete gen; delete program; } TEST_CASE("t_netstd_generator should create valid instance with valid options", "[initialization]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" }, { "nullable", "nullable"} }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = nullptr; REQUIRE_NOTHROW(gen = new t_netstd_generator(program, parsed_options, option_string)); REQUIRE(gen != nullptr); REQUIRE(gen->is_wcf_enabled()); REQUIRE(gen->is_nullable_enabled()); REQUIRE_FALSE(gen->is_hashcode_enabled()); REQUIRE_FALSE(gen->is_serialize_enabled()); REQUIRE_FALSE(gen->is_union_enabled()); delete gen; delete program; } TEST_CASE("t_netstd_generator should pass init succesfully", "[initialization]") { string path = "CassandraTest.thrift"; string name = "netstd"; map parsed_options = { { "wcf", "wcf" },{ "nullable", "nullable" } }; string option_string = ""; t_program* program = new t_program(path, name); t_netstd_generator* gen = new t_netstd_generator(program, parsed_options, option_string); REQUIRE_NOTHROW(gen->init_generator()); delete gen; delete program; } thrift-0.16.0/compiler/cpp/tests/tests_main.cc000066400000000000000000000015241420101504100212770ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #define CATCH_CONFIG_MAIN #include "catch/catch.hpp" thrift-0.16.0/composer.json000066400000000000000000000017521420101504100156110ustar00rootroot00000000000000{ "name": "apache/thrift", "description": "Apache Thrift RPC system", "homepage": "http://thrift.apache.org", "type": "library", "keywords": ["RPC"], "license": "Apache-2.0", "readme": "README.md", "authors": [ { "name": "Apache Thrift Developers", "email": "dev@thrift.apache.org", "homepage": "http://thrift.apache.org" } ], "support": { "email": "dev@thrift.apache.org", "issues": "https://issues.apache.org/jira/browse/THRIFT" }, "require": { "php": "^5.5 || ^7.0 || ^8.0" }, "require-dev": { "phpunit/phpunit": "~4.8.36", "squizlabs/php_codesniffer": "3.*" }, "autoload": { "psr-4": {"Thrift\\": "lib/php/lib/"} }, "autoload-dev": { "psr-4": {"Test\\Thrift\\": "lib/php/test/"} }, "minimum-stability": "stable", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } } } thrift-0.16.0/configure.ac000077500000000000000000000764531420101504100153720ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # AC_PREREQ(2.65) AC_CONFIG_MACRO_DIR([./aclocal]) AC_INIT([thrift], [0.16.0]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([1.13 subdir-objects tar-ustar foreign]) PKG_PROG_PKG_CONFIG AC_ARG_VAR([PY_PREFIX], [Prefix for installing Python modules. (Normal --prefix is ignored for Python because Python has different conventions.) Default = "/usr"]) AS_IF([test "x$PY_PREFIX" = x], [PY_PREFIX="/usr"]) AC_ARG_VAR([JAVA_PREFIX], [Prefix for installing the Java lib jar. Default = "/usr/local/lib"]) AS_IF([test "x$JAVA_PREFIX" != x], [JAVA_PREFIX="$JAVA_PREFIX/usr/local/lib"], [test "x$PREFIX" != x], [JAVA_PREFIX="$PREFIX/usr/local/lib"], [JAVA_PREFIX="/usr/local/lib"]) AC_ARG_VAR([RUBY_PREFIX], [Prefix for installing Ruby modules. (Normal --prefix is ignored for Ruby because Ruby has different conventions.) Default = none, let ruby setup decide]) AC_ARG_VAR([PHP_PREFIX], [Prefix for installing PHP modules. (Normal --prefix is ignored for PHP because PHP has different conventions.) Default = "/usr/lib/php"]) AS_IF([test "x$PHP_PREFIX" = x], [PHP_PREFIX="/usr/lib/php"]) AC_ARG_VAR([PHP_CONFIG_PREFIX], [Prefix for installing PHP extension module .ini file. (Normal --prefix is ignored for PHP because PHP has different conventions.) Default = "/etc/php.d"]) AS_IF([test "x$PHP_CONFIG_PREFIX" = x], [PHP_CONFIG_PREFIX="/etc/php.d"]) AC_ARG_VAR([INSTALLDIRS], [When installing Perl modules, specifies which of the sets of installation directories to choose: perl, site or vendor. Default = "vendor"]) AS_IF([test "x$INSTALLDIRS" = x], [INSTALLDIRS="vendor"]) AC_ARG_VAR([PERL_PREFIX], [Prefix for installing Perl modules. (Normal --prefix is ignored for Perl because Perl has different conventions.) Ignored, when INSTALLDIRS set to site or vendor. Default = "/usr/local/lib"]) AS_IF([test "x$PERL_PREFIX" = x], [PERL_PREFIX="/usr/local"]) AC_ARG_VAR([D_IMPORT_PREFIX], [Prefix for installing D modules. [INCLUDEDIR/d2]]) AS_IF([test "x$D_IMPORT_PREFIX" = x], [D_IMPORT_PREFIX="${includedir}/d2"]) AC_ARG_VAR([DMD_LIBEVENT_FLAGS], [DMD flags for linking libevent (auto-detected if not set).]) AC_ARG_VAR([DMD_OPENSSL_FLAGS], [DMD flags for linking OpenSSL (auto-detected if not set).]) AC_ARG_VAR([THRIFT], [Path to the thrift tool (needed for cross-compilation).]) AS_IF([test "x$THRIFT" = x], [THRIFT=`pwd`/compiler/cpp/thrift]) AC_PROG_CC AC_PROG_CPP AC_PROG_CXX AC_PROG_INSTALL AC_PROG_LIBTOOL AC_PROG_MAKE_SET AC_PROG_BISON(2.5) AC_PROG_YACC AC_PROG_LEX AM_PROG_LEX AC_PROG_LN_S AC_PROG_MKDIR_P AC_PROG_AWK AC_PROG_RANLIB AC_LANG([C++]) AX_CXX_COMPILE_STDCXX_11([noext], [mandatory]) AM_EXTRA_RECURSIVE_TARGETS([style]) AC_SUBST(CPPSTYLE_CMD, 'find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;') # ' # The above comment is to fix editor syntax highlighting AC_ARG_ENABLE([libs], AS_HELP_STRING([--enable-libs], [build the Apache Thrift libraries [default=yes]]), [], enable_libs=yes ) have_libs=yes if test "$enable_libs" = "no"; then have_libs="no" with_cpp="no" with_c_glib="no" with_cl="no" with_java="no" with_python="no" with_py3="no" with_ruby="no" with_haxe="no" with_netstd="no" with_perl="no" with_php="no" with_php_extension="no" with_dart="no" with_erlang="no" with_go="no" with_d="no" with_nodejs="no" with_nodets="no" with_lua="no" with_rs="no" with_swift="no" fi AX_THRIFT_LIB(cpp, [C++], yes) have_cpp=no if test "$with_cpp" = "yes"; then AX_BOOST_BASE([1.56.0]) if test "x$succeeded" = "xyes" ; then AC_SUBST([BOOST_LIB_DIR], [$(echo "$BOOST_LDFLAGS" | sed -e 's/^\-L//')]) AC_SUBST([BOOST_CHRONO_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_chrono.a")]) AC_SUBST([BOOST_FILESYSTEM_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_filesystem.a")]) AC_SUBST([BOOST_SYSTEM_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_system.a")]) AC_SUBST([BOOST_TEST_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_unit_test_framework.a")]) AC_SUBST([BOOST_THREAD_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_thread.a")]) have_cpp="yes" fi AX_LIB_EVENT([2.0]) have_libevent=$success AX_LIB_ZLIB([1.2.3]) have_zlib=$success AX_THRIFT_LIB(qt5, [Qt5], yes) have_qt5=no qt_reduce_reloc="" if test "$with_qt5" = "yes"; then PKG_CHECK_MODULES([QT5], [Qt5Core >= 5.0, Qt5Network >= 5.0], [have_qt5=yes;qt_reduce_reloc=`$PKG_CONFIG --variable=qt_config Qt5Core | grep "reduce_relocations"`], [have_qt5=no]) fi if test "$have_qt5" = "yes"; then AC_PATH_PROGS([QT5_MOC], [moc-qt5 moc], "fail") if test "$QT5_MOC" = "fail"; then have_qt5=no fi fi fi AM_CONDITIONAL([WITH_CPP], [test "$have_cpp" = "yes"]) AM_CONDITIONAL([AMX_HAVE_LIBEVENT], [test "$have_libevent" = "yes"]) AM_CONDITIONAL([AMX_HAVE_ZLIB], [test "$have_zlib" = "yes"]) AM_CONDITIONAL([AMX_HAVE_QT5], [test "$have_qt5" = "yes"]) AM_CONDITIONAL([QT5_REDUCE_RELOCATIONS], [test "x$qt_reduce_reloc" != "x"]) AX_THRIFT_LIB(c_glib, [C (GLib)], yes) if test "$with_c_glib" = "yes"; then PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.0], have_glib2=yes, have_glib2=no) PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 >= 2.0], have_gobject2=yes, have_gobject2=no) if test "$have_glib2" = "yes" -a "$have_gobject2" = "yes" ; then AC_PATH_PROG([GSETTINGS], [gsettings]) have_c_glib="yes" fi fi AM_CONDITIONAL(WITH_C_GLIB, [test "$have_glib2" = "yes" -a "$have_gobject2" = "yes"]) # echo "OpenSSL check" if test "$have_cpp" = "yes" -o "$have_c_glib" = "yes"; then # echo "Have cpp or c so we check for OpenSSL" AX_CHECK_OPENSSL() fi AX_THRIFT_LIB(java, [Java], yes) if test "$with_java" = "yes"; then AX_JAVAC_AND_JAVA AC_PATH_PROG([ANT], [ant]) AX_CHECK_ANT_VERSION($ANT, 1.7) AC_SUBST(CLASSPATH) AC_SUBST(ANT_FLAGS) AC_SUBST(GRADLE_OPTS) if test "x$JAVA" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then have_java="yes" fi fi AM_CONDITIONAL([WITH_JAVA], [test "$have_java" = "yes"]) AX_THRIFT_LIB(erlang, [Erlang], yes) if test "$with_erlang" = "yes"; then AC_ERLANG_PATH_ERL AC_ERLANG_PATH_ERLC AC_PATH_PROG([REBAR], [rebar3]) if test -n "$ERLC" ; then AC_ERLANG_SUBST_LIB_DIR # Install into the detected Erlang directory instead of $libdir/erlang/lib ERLANG_INSTALL_LIB_DIR="$ERLANG_LIB_DIR" AC_ERLANG_SUBST_INSTALL_LIB_SUBDIR(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) fi if test -n "$ERL" -a -n "$ERLC" && test "x$REBAR" != "x" ; then have_erlang="yes" fi fi AM_CONDITIONAL(WITH_ERLANG, [test "$have_erlang" = "yes"]) AX_THRIFT_LIB(nodejs, [Nodejs], yes) have_nodejs=no if test "$with_nodejs" = "yes"; then AC_PATH_PROGS([NODEJS], [nodejs node]) AC_PATH_PROG([NPM], [npm]) if test "x$NODEJS" != "x" -a "x$NPM" != "x"; then have_nodejs="yes" fi fi AM_CONDITIONAL(WITH_NODEJS, [test "$have_nodejs" = "yes"]) AM_CONDITIONAL(HAVE_NPM, [test "x$NPM" != "x"]) AX_THRIFT_LIB(nodets, [Nodets], yes) have_nodets=no if test "$with_nodets" = "yes"; then AC_PATH_PROGS([NODETS], [nodets node]) AC_PATH_PROG([NPM], [npm]) if test "x$NODETS" != "x" -a "x$NPM" != "x"; then have_nodets="yes" fi fi AM_CONDITIONAL(WITH_NODETS, [test "$have_nodets" = "yes"]) AM_CONDITIONAL(HAVE_NPM, [test "x$NPM" != "x"]) AX_THRIFT_LIB(lua, [Lua], yes) have_lua=no if test "$with_lua" = "yes"; then AX_PROG_LUA(5.2,, have_lua="yes", have_lua="no") if test "$have_lua" = "yes"; then AX_LUA_HEADERS(, have_lua="no") AX_LUA_LIBS(, have_lua="no") fi fi AM_CONDITIONAL(WITH_LUA, [test "$have_lua" = "yes"]) # Find python regardless of with_python value, because it's needed by make cross AM_PATH_PYTHON(2.6,, :) AX_THRIFT_LIB(python, [Python], yes) if test "$with_python" = "yes"; then if test -n "$PYTHON"; then have_python="yes" fi AC_PATH_PROG([TRIAL], [trial]) if test -n "$TRIAL"; then have_trial="yes" fi fi AM_CONDITIONAL(WITH_PYTHON, [test "$have_python" = "yes"]) AM_CONDITIONAL(WITH_TWISTED_TEST, [test "$have_trial" = "yes"]) # Find "python3" executable. # It's distro specific and far from ideal but needed to cross test py2-3 at once. # TODO: find "python2" if it's 3.x have_py3="no" AX_THRIFT_LIB(py3, [Py3], yes) if test "$with_py3" = "yes"; then # if $PYTHON is 2.x then search for python 3. otherwise, $PYTHON is already 3.x if $PYTHON --version 2>&1 | grep -q "Python 2"; then AC_PATH_PROGS([PYTHON3], [python3 python3.8 python38 python3.7 python37 python3.6 python36 python3.5 python35 python3.4 python34]) if test -n "$PYTHON3"; then have_py3="yes" fi elif $PYTHON --version 2>&1 | grep -q "Python 3"; then have_py3="yes" PYTHON3=$PYTHON fi fi AM_CONDITIONAL(WITH_PY3, [test "$have_py3" = "yes"]) AX_THRIFT_LIB(perl, [Perl], yes) if test "$with_perl" = "yes"; then AC_PATH_PROG([PERL], [perl]) if test -n "$PERL" ; then AC_PROG_PERL_MODULES([Bit::Vector], success="yes", success="no") have_perl_bit_vector="$success" AC_PROG_PERL_MODULES([Class::Accessor], success="yes", success="no") have_perl_class_accessor="$success" fi if test -n "$PERL" -a "$have_perl_bit_vector" = "yes" ; then if test -n "$PERL" -a "$have_perl_class_accessor" = "yes" ; then have_perl="yes" fi fi fi AM_CONDITIONAL(WITH_PERL, [test "$have_perl" = "yes"]) AX_THRIFT_LIB(php, [PHP], yes) if test "$with_php" = "yes"; then AC_PATH_PROG([PHP], [php]) if test -n "$PHP" ; then have_php="yes" fi fi AM_CONDITIONAL(WITH_PHP, [test "$have_php" = "yes"]) AX_THRIFT_LIB(php_extension, [PHP_EXTENSION], yes) if test "$with_php_extension" = "yes"; then if test -f "lib/php/src/ext/thrift_protocol/configure"; then AC_PATH_PROG([PHP_CONFIG], [php-config]) if test -n "$PHP_CONFIG" ; then AC_CONFIG_SUBDIRS([lib/php/src/ext/thrift_protocol]) have_php_extension="yes" fi fi fi AM_CONDITIONAL(WITH_PHP_EXTENSION, [test "$have_php_extension" = "yes"]) AX_THRIFT_LIB(dart, [DART], yes) if test "$with_dart" = "yes"; then AC_PATH_PROG([DART], [dart]) AC_PATH_PROG([DARTPUB], [pub]) if test "x$DART" != "x" -a "x$DARTPUB" != "x"; then have_dart="yes" fi fi AM_CONDITIONAL(WITH_DART, [test "$have_dart" = "yes"]) AX_THRIFT_LIB(ruby, [Ruby], yes) have_ruby=no if test "$with_ruby" = "yes"; then AC_PATH_PROG([RUBY], [ruby]) AC_PATH_PROG([BUNDLER], [bundle]) if test "x$RUBY" != "x" -a "x$BUNDLER" != "x"; then have_ruby="yes" fi fi AM_CONDITIONAL(WITH_RUBY, [test "$have_ruby" = "yes"]) AM_CONDITIONAL(HAVE_BUNDLER, [test "x$BUNDLER" != "x"]) AX_THRIFT_LIB(go, [Go], yes) if test "$with_go" = "yes"; then AC_PATH_PROG([GO], [go]) if [[ -x "$GO" ]] ; then AS_IF([test -n "$GO"],[ ax_go_version="1.4" ax_go17_version="1.7" AC_MSG_CHECKING([for Go version]) golang_version=`$GO version 2>&1 | $SED -e 's/\(go \)\(version \)\(go\)\(@<:@0-9@:>@.@<:@0-9@:>@.@<:@0-9@:>@\)\(@<:@\*@:>@*\).*/\4/'` AC_MSG_RESULT($golang_version) AC_SUBST([golang_version],[$golang_version]) AX_COMPARE_VERSION([$ax_go_version],[le],[$golang_version],[ : have_go="yes" ],[ : have_go="no" ]) AX_COMPARE_VERSION([$golang_version],[lt],[$ax_go17_version],[ : go_version_lt_17="yes" ],[ : go_version_lt_17="no" ]) ],[ AC_MSG_WARN([could not find Go ]) have_go="no" ]) fi fi AM_CONDITIONAL(WITH_GO, [test "$have_go" = "yes"]) AM_CONDITIONAL([GOVERSION_LT_17], [test "$go_version_lt_17" = "yes"]) AX_THRIFT_LIB(swift, [Swift], yes) have_swift="no" if test "$with_swift" = "yes"; then AC_PATH_PROG([SWIFT], [swift]) if test "x$SWIFT" != "x" -a "x$SWIFT" != "x"; then have_swift="yes" fi fi AM_CONDITIONAL([WITH_SWIFT], [test "$have_swift" = "yes"]) AX_THRIFT_LIB(rs, [Rust], yes) have_rs="no" if test "$with_rs" = "yes"; then AC_PATH_PROG([CARGO], [cargo]) AC_PATH_PROG([RUSTC], [rustc]) if [[ -x "$CARGO" ]] && [[ -x "$RUSTC" ]]; then min_rustc_version="1.13" AC_MSG_CHECKING([for rustc version]) rustc_version=`$RUSTC --version 2>&1 | $SED -e 's/\(rustc \)\([0-9]\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\2.\3/'` AC_MSG_RESULT($rustc_version) AC_SUBST([rustc_version],[$rustc_version]) AX_COMPARE_VERSION([$min_rustc_version],[le],[$rustc_version],[ : have_rs="yes" ],[ : have_rs="no" ]) fi fi AM_CONDITIONAL(WITH_RS, [test "$have_rs" = "yes"]) AX_THRIFT_LIB(cl, [Common Lisp], yes) have_cl="no" if test "$with_cl" = "yes"; then AC_PATH_PROG([SBCL], [sbcl]) if test "x$SBCL" != "x"; then have_cl="yes" fi fi AM_CONDITIONAL(WITH_CL, [test "$have_cl" = "yes"]) AX_THRIFT_LIB(haxe, [Haxe], yes) if test "$with_haxe" = "yes"; then AC_PATH_PROG([HAXE], [haxe]) if [[ -x "$HAXE" ]] ; then AX_PROG_HAXE_VERSION( [4.2.1], have_haxe="yes", have_haxe="no") fi fi AM_CONDITIONAL(WITH_HAXE, [test "$have_haxe" = "yes"]) AX_THRIFT_LIB(netstd, [.NET Core], yes) if test "$with_netstd" = "yes"; then AC_PATH_PROG([DOTNETCORE], [dotnet]) if [[ -x "$DOTNETCORE" ]] ; then AX_PROG_DOTNETCORE_VERSION( [3.1.0], have_netstd="yes", have_netstd="no") fi fi AM_CONDITIONAL(WITH_DOTNET, [test "$have_netstd" = "yes"]) AX_THRIFT_LIB(d, [D], yes) if test "$with_d" = "yes"; then AX_DMD AC_SUBST(DMD) if test "x$DMD" != "x"; then have_d="yes" fi fi # Determine actual name of the generated D library for use in the command line # when compiling tests. This is needed because the -l syntax doesn't work # with OPTLINK (Windows). lib_prefix=lib lib_suffix=a case "$host_os" in cygwin* | mingw* | pw32* | cegcc*) lib_prefix="" lib_suffix=lib ;; esac D_LIB_NAME="${lib_prefix}thriftd.${lib_suffix}" AC_SUBST(D_LIB_NAME) D_EVENT_LIB_NAME="${lib_prefix}thriftd-event.${lib_suffix}" AC_SUBST(D_EVENT_LIB_NAME) D_SSL_LIB_NAME="${lib_prefix}thriftd-ssl.${lib_suffix}" AC_SUBST(D_SSL_LIB_NAME) if test "$have_d" = "yes"; then AX_CHECK_D_MODULE(deimos.event2.event) have_deimos_event2=$success with_d_event_tests="no" if test "$have_deimos_event2" = "yes"; then if test "x$DMD_LIBEVENT_FLAGS" = "x"; then if test "$dmd_optlink" = "yes"; then AC_MSG_WARN([D libevent interface found, but cannot auto-detect \ linker flags for OPTLINK. Please set DMD_LIBEVENT_FLAGS manually.]) else AX_LIB_EVENT([2.0]) if test "$success" = "yes"; then DMD_LIBEVENT_FLAGS=$(echo "-fuse-ld=gold $LIBEVENT_LDFLAGS $LIBEVENT_LIBS" | \ sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/ */ -L/g') with_d_event_tests="yes" else AC_MSG_WARN([D libevent interface present, but libevent library not found.]) fi fi else with_d_event_tests="yes" fi fi AX_CHECK_D_MODULE(deimos.openssl.ssl) have_deimos_openssl=$success with_d_ssl_tests="no" if test "$have_deimos_openssl" = "yes"; then if test "x$DMD_OPENSSL_FLAGS" = "x"; then if test "$dmd_optlink" = "yes"; then AC_MSG_WARN([D OpenSSL interface found, but cannot auto-detect \ linker flags for OPTLINK. Please set DMD_OPENSSL_FLAGS manually.]) else AX_CHECK_OPENSSL([with_d_ssl_tests="yes"]) if test "$with_d_ssl_tests" = "yes"; then DMD_OPENSSL_FLAGS=$(echo "-fuse-ld=gold $OPENSSL_LDFLAGS $OPENSSL_LIBS" | \ sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/ */ -L/g') else AC_MSG_WARN([D OpenSSL interface present, but OpenSSL library not found.]) fi fi else with_d_ssl_tests="yes" fi fi fi AM_CONDITIONAL(WITH_D, [test "$have_d" = "yes"]) AM_CONDITIONAL(DMD_OPTLINK, [test "$dmd_optlink" = "yes"]) AC_SUBST(DMD_OF_DIRSEP, "$dmd_of_dirsep") AM_CONDITIONAL(HAVE_DEIMOS_EVENT2, [test "$have_deimos_event2" = "yes"]) AM_CONDITIONAL(WITH_D_EVENT_TESTS, [test "$with_d_event_tests" = "yes"]) AC_SUBST(DMD_LIBEVENT_FLAGS) AM_CONDITIONAL(HAVE_DEIMOS_OPENSSL, [test "$have_deimos_openssl" = "yes"]) AM_CONDITIONAL(WITH_D_SSL_TESTS, [test "$with_d_ssl_tests" = "yes"]) AC_SUBST(DMD_OPENSSL_FLAGS) AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [build tests [default=yes]]), [], enable_tests=yes ) have_tests=yes if test "$enable_tests" = "no"; then have_tests="no" fi AM_CONDITIONAL(WITH_TESTS, [test "$have_tests" = "yes"]) AC_ARG_ENABLE([tutorial], AS_HELP_STRING([--enable-tutorial], [build tutorial [default=yes]]), [], enable_tutorial=yes ) have_tutorial=yes if test "$enable_tutorial" = "no"; then have_tutorial="no" fi AM_CONDITIONAL(WITH_TUTORIAL, [test "$have_tutorial" = "yes"]) AM_CONDITIONAL(MINGW, false) case "${host_os}" in *mingw*) mingw32_support="yes" AC_CHECK_HEADER(windows.h) AM_CONDITIONAL(MINGW, true) ;; *) AC_ISC_POSIX ;; esac AC_C_CONST AC_C_INLINE AC_C_VOLATILE AC_HEADER_STDBOOL AC_HEADER_STDC AC_HEADER_TIME AC_HEADER_SYS_WAIT AC_TYPE_SIGNAL AC_CHECK_HEADERS([arpa/inet.h]) AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([inttypes.h]) AC_CHECK_HEADERS([limits.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([pthread.h]) AC_CHECK_HEADERS([signal.h]) AC_CHECK_HEADERS([stddef.h]) AC_CHECK_HEADERS([stdlib.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([sys/time.h]) AC_CHECK_HEADERS([sys/un.h]) AC_CHECK_HEADERS([poll.h]) AC_CHECK_HEADERS([sys/poll.h]) AC_CHECK_HEADERS([sys/resource.h]) AC_CHECK_HEADERS([unistd.h]) AC_CHECK_HEADERS([libintl.h]) AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([openssl/ssl.h]) AC_CHECK_HEADERS([openssl/rand.h]) AC_CHECK_HEADERS([openssl/x509v3.h]) AC_CHECK_HEADERS([sched.h]) AC_CHECK_HEADERS([wchar.h]) AC_CHECK_LIB(pthread, pthread_create) dnl NOTE(dreiss): I haven't been able to find any really solid docs dnl on what librt is and how it fits into various Unix systems. dnl My best guess is that it is where glibc stashes its implementation dnl of the POSIX Real-Time Extensions. This seems necessary on Linux, dnl and we haven't yet found a system where this is a problem. AC_CHECK_LIB(rt, clock_gettime) AC_CHECK_LIB(socket, setsockopt) AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_INT8_T AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T AC_CHECK_TYPES([ptrdiff_t], [], [echo "ptrdiff_t not found or g++ not installed - cannot continue" && exit 1]) AC_STRUCT_TM dnl NOTE(dreiss): AI_ADDRCONFIG is not defined on OpenBSD. AC_CHECK_DECL([AI_ADDRCONFIG], [], [AC_DEFINE([AI_ADDRCONFIG], 0, [Define if the AI_ADDRCONFIG symbol is unavailable])], [ #include #include #include ]) AC_FUNC_ALLOCA AC_FUNC_FORK AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_REALLOC AC_FUNC_SELECT_ARGTYPES AC_FUNC_STAT AC_FUNC_STRERROR_R AC_FUNC_STRFTIME AC_FUNC_VPRINTF AC_CHECK_FUNCS([strtoul]) AC_CHECK_FUNCS([bzero]) AC_CHECK_FUNCS([ftruncate]) AC_CHECK_FUNCS([gethostbyname]) AC_CHECK_FUNCS([gethostbyname_r]) AC_CHECK_FUNCS([gettimeofday]) AC_CHECK_FUNCS([memmove]) AC_CHECK_FUNCS([memset]) AC_CHECK_FUNCS([mkdir]) AC_CHECK_FUNCS([realpath]) AC_CHECK_FUNCS([select]) AC_CHECK_FUNCS([setlocale]) AC_CHECK_FUNCS([socket]) AC_CHECK_FUNCS([strchr]) AC_CHECK_FUNCS([strdup]) AC_CHECK_FUNCS([strerror]) AC_CHECK_FUNCS([strstr]) AC_CHECK_FUNCS([strtol]) AC_CHECK_FUNCS([sqrt]) dnl The following functions are optional. AC_CHECK_FUNCS([alarm]) AC_CHECK_FUNCS([clock_gettime]) AC_CHECK_FUNCS([sched_get_priority_min]) AC_CHECK_FUNCS([sched_get_priority_max]) AC_CHECK_FUNCS([inet_ntoa]) AC_CHECK_FUNCS([pow]) if test "$cross_compiling" = "no" ; then AX_SIGNED_RIGHT_SHIFT fi dnl autoscan thinks we need this macro because we have a member function dnl called "error". Invoke the macro but don't run the check so autoscan dnl thinks we are in the clear. It's highly unlikely that we will ever dnl actually use the function that this checks for. if false ; then AC_FUNC_ERROR_AT_LINE fi # --- Coverage hooks --- AC_ARG_ENABLE(coverage, [ --enable-coverage turn on -fprofile-arcs -ftest-coverage], [case "${enableval}" in yes) ENABLE_COVERAGE=1 ;; no) ENABLE_COVERAGE=0 ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-cov) ;; esac], [ENABLE_COVERAGE=2]) if test "x[$]ENABLE_COVERAGE" = "x1"; then AC_MSG_WARN(enable coverage) GCOV_CFLAGS="`echo \"[$]CFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage" GCOV_CXXFLAGS="`echo \"[$]CXXFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage" GCOV_LDFLAGS="-XCClinker -fprofile-arcs -XCClinker -ftest-coverage" fi AC_SUBST(ENABLE_COVERAGE) AC_SUBST(GCOV_CFLAGS) AC_SUBST(GCOV_CXXFLAGS) AC_SUBST(GCOV_LDFLAGS) AC_CONFIG_HEADERS(config.h:config.hin) AC_CONFIG_HEADERS(lib/cpp/src/thrift/config.h:config.hin) AC_CONFIG_HEADERS(lib/c_glib/src/thrift/config.h:config.hin) # guard against pre defined config.h AH_TOP([ #ifndef CONFIG_H #define CONFIG_H ]) AH_BOTTOM([ #endif ]) AC_CONFIG_FILES([ Makefile compiler/cpp/Makefile compiler/cpp/src/Makefile compiler/cpp/test/Makefile lib/Makefile lib/cl/Makefile lib/cpp/Makefile lib/cpp/test/Makefile lib/cpp/thrift-nb.pc lib/cpp/thrift-z.pc lib/cpp/thrift-qt5.pc lib/cpp/thrift.pc lib/c_glib/Makefile lib/c_glib/thrift_c_glib.pc lib/c_glib/test/Makefile lib/d/Makefile lib/d/test/Makefile lib/erl/Makefile lib/go/Makefile lib/go/test/Makefile lib/go/test/fuzz/Makefile lib/haxe/test/Makefile lib/java/Makefile lib/js/Makefile lib/js/test/Makefile lib/json/Makefile lib/json/test/Makefile lib/netstd/Makefile lib/nodejs/Makefile lib/nodets/Makefile lib/perl/Makefile lib/perl/t/Makefile lib/php/Makefile lib/php/test/Makefile lib/dart/Makefile lib/py/Makefile lib/rb/Makefile lib/rs/Makefile lib/rs/test/Makefile lib/rs/test_recursive/Makefile lib/rs/test_recursive/src/Makefile lib/rs/test_recursive/src/maintenance/Makefile lib/rs/test_recursive/src/transit/Makefile lib/rs/test_recursive/src/transit/light/Makefile lib/rs/test_recursive/src/transit/services/Makefile lib/lua/Makefile lib/swift/Makefile lib/ts/Makefile lib/xml/Makefile lib/xml/test/Makefile test/Makefile test/features/Makefile test/c_glib/Makefile test/cl/Makefile test/cpp/Makefile test/erl/Makefile test/go/Makefile test/haxe/Makefile test/lua/Makefile test/netstd/Makefile test/php/Makefile test/dart/Makefile test/perl/Makefile test/py/Makefile test/py.twisted/Makefile test/py.tornado/Makefile test/rb/Makefile test/rs/Makefile tutorial/Makefile tutorial/c_glib/Makefile tutorial/cl/Makefile tutorial/cpp/Makefile tutorial/d/Makefile tutorial/go/Makefile tutorial/haxe/Makefile tutorial/java/Makefile tutorial/js/Makefile tutorial/netstd/Makefile tutorial/nodejs/Makefile tutorial/dart/Makefile tutorial/perl/Makefile tutorial/php/Makefile tutorial/py/Makefile tutorial/py.twisted/Makefile tutorial/py.tornado/Makefile tutorial/rb/Makefile tutorial/rs/Makefile ]) if test "$have_cpp" = "yes" ; then MAYBE_CPP="cpp" ; else MAYBE_CPP="" ; fi AC_SUBST([MAYBE_CPP]) if test "$have_c_glib" = "yes" ; then MAYBE_C_GLIB="c_glib" ; else MAYBE_C_GLIB="" ; fi AC_SUBST([MAYBE_C_GLIB]) if test "$have_d" = "yes" -a "$have_deimos_event2" = "yes" -a "$have_deimos_openssl" = "yes"; then MAYBE_D="d" ; else MAYBE_D="" ; fi AC_SUBST([MAYBE_D]) if test "$have_java" = "yes" ; then MAYBE_JAVA="java" ; else MAYBE_JAVA="" ; fi AC_SUBST([MAYBE_JAVA]) if test "$have_python" = "yes" ; then MAYBE_PYTHON="py" ; else MAYBE_PYTHON="" ; fi AC_SUBST([MAYBE_PYTHON]) if test "$have_py3" = "yes" ; then MAYBE_PY3="py3" ; else MAYBE_PY3="" ; fi AC_SUBST([MAYBE_PY3]) if test "$have_ruby" = "yes" ; then MAYBE_RUBY="rb" ; else MAYBE_RUBY="" ; fi AC_SUBST([MAYBE_RUBY]) if test "$have_perl" = "yes" ; then MAYBE_PERL="perl" ; else MAYBE_PERL="" ; fi AC_SUBST([MAYBE_PERL]) if test "$have_php" = "yes" ; then MAYBE_PHP="php" ; else MAYBE_PHP="" ; fi AC_SUBST([MAYBE_PHP]) if test "$have_dart" = "yes" ; then MAYBE_DART="dart" ; else MAYBE_DART="" ; fi AC_SUBST([MAYBE_DART]) if test "$have_go" = "yes" ; then MAYBE_GO="go" ; else MAYBE_GO="" ; fi AC_SUBST([MAYBE_GO]) if test "$have_nodejs" = "yes" ; then MAYBE_NODEJS="nodejs" ; else MAYBE_NODEJS="" ; fi AC_SUBST([MAYBE_NODEJS]) if test "$have_nodets" = "yes" ; then MAYBE_NODETS="nodets" ; else MAYBE_NODETS="" ; fi AC_SUBST([MAYBE_NODETS]) if test "$have_erlang" = "yes" ; then MAYBE_ERLANG="erl" ; else MAYBE_ERLANG="" ; fi AC_SUBST([MAYBE_ERLANG]) if test "$have_lua" = "yes" ; then MAYBE_LUA="lua" ; else MAYBE_LUA="" ; fi AC_SUBST([MAYBE_LUA]) if test "$have_rs" = "yes" ; then MAYBE_RS="rs" ; else MAYBE_RS="" ; fi AC_SUBST([MAYBE_RS]) if test "$have_swift" = "yes" ; then MAYBE_SWIFT="swift" ; else MAYBE_SWIFT="" ; fi AC_SUBST([MAYBE_SWIFT]) if test "$have_netstd" = "yes" ; then MAYBE_NETSTD="netstd" ; else MAYBE_NETSTD="" ; fi AC_SUBST([MAYBE_NETSTD]) if test "$have_cl" = "yes" ; then MAYBE_CL="cl" ; else MAYBE_CL="" ; fi AC_SUBST([MAYBE_CL]) AC_OUTPUT echo echo "$PACKAGE $VERSION" echo echo "Building C (GLib) Library .... : $have_c_glib" echo "Building C++ Library ......... : $have_cpp" echo "Building Common Lisp Library.. : $have_cl" echo "Building D Library ........... : $have_d" echo "Building Dart Library ........ : $have_dart" echo "Building .NET Standard Library : $have_netstd" echo "Building Erlang Library ...... : $have_erlang" echo "Building Go Library .......... : $have_go" echo "Building Haxe Library ........ : $have_haxe" echo "Building Java Library ........ : $have_java" echo "Building Lua Library ......... : $have_lua" echo "Building NodeJS Library ...... : $have_nodejs" echo "Building Perl Library ........ : $have_perl" echo "Building PHP Library ......... : $have_php" echo "Building Python Library ...... : $have_python" echo "Building Py3 Library ......... : $have_py3" echo "Building Ruby Library ........ : $have_ruby" echo "Building Rust Library ........ : $have_rs" echo "Building Swift Library ....... : $have_swift" if test "$have_c_glib" = "yes" ; then echo echo "C (glib):" echo " Using glib version ........ : $($GSETTINGS --version)" fi if test "$have_cpp" = "yes" ; then echo echo "C++ Library:" echo " C++ compiler .............. : $CXX" echo " Build TZlibTransport ...... : $have_zlib" echo " Build TNonblockingServer .. : $have_libevent" echo " Build TQTcpServer (Qt5) ... : $have_qt5" echo " C++ compiler version ...... : $($CXX --version | head -1)" fi if test "$have_cl" = "yes" ; then echo echo "Common Lisp Library:" echo " Using Common Lisp ......... : $SBCL" echo " Using Common Lisp version . : $($SBCL --version)" fi if test "$have_d" = "yes" ; then echo echo "D Library:" echo " Using D Compiler .......... : $DMD" echo " Building D libevent tests . : $with_d_event_tests" echo " Building D SSL tests ...... : $with_d_ssl_tests" echo " Using D version ........... : $($DMD --version | head -1)" fi if test "$have_dart" = "yes" ; then echo echo "Dart Library:" echo " Using Dart ................ : $DART" echo " Using Pub ................. : $DARTPUB" echo " Using Dart version ........ : $($DART --version 2>&1)" fi if test "$have_netstd" = "yes" ; then echo echo ".NET Standard Library:" echo " Using dotnet .............. : $DOTNETCORE" echo " Using dotnet version ...... : $DOTNETCORE_VERSION" fi if test "$have_erlang" = "yes" ; then echo echo "Erlang Library:" echo " Using erlc ................ : $ERLC" echo " Using rebar ............... : $REBAR" echo " Using erlc version ........ : $($ERL -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell | tr -d '\"')" fi if test "$have_go" = "yes" ; then echo echo "Go Library:" echo " Using Go................... : $GO" echo " Using Go version........... : $($GO version)" fi if test "$have_haxe" = "yes" ; then echo echo "Haxe Library:" echo " Using Haxe ................ : $HAXE" echo " Using Haxe version ........ : $HAXE_VERSION" fi if test "$have_java" = "yes" ; then echo echo "Java Library:" echo " Using gradlew ............. : lib/java/gradlew" echo " Using java ................ : $JAVA" echo " Using javac ............... : $JAVAC" echo " Using Gradle version ...... : $(lib/java/gradlew --version --quiet | grep Gradle 2>&1)" echo " Using java version ........ : $($JAVA -version 2>&1 | grep 'version ')" fi if test "$have_lua" = "yes" ; then echo echo "Lua Library:" echo " Using Lua ................. : $LUA" echo " Using Lua version.......... : $($LUA -v)" fi if test "$have_nodejs" = "yes" ; then echo echo "NodeJS Library:" echo " Using NodeJS .............. : $NODEJS" echo " Using NodeJS version....... : $($NODEJS --version)" fi if test "$have_perl" = "yes" ; then echo echo "Perl Library:" echo " Using Perl ................ : $PERL" echo " Using Perl version ........ : $($PERL -v | grep 'version ')" fi if test "$have_php" = "yes" ; then echo echo "PHP Library:" echo " Using php-config .......... : $PHP_CONFIG" echo " Using php version ......... : $($PHP --version | head -1)" fi if test "$have_python" = "yes" ; then echo echo "Python Library:" echo " Using Python .............. : $PYTHON" echo " Using Python version ...... : $($PYTHON --version 2>&1)" if test "$have_py3" = "yes" ; then echo " Using Python3 ............. : $PYTHON3" echo " Using Python3 version ..... : $($PYTHON3 --version)" fi if test "$have_trial" = "yes"; then echo " Using trial ............... : $TRIAL" fi fi if test "$have_ruby" = "yes" ; then echo echo "Ruby Library:" echo " Using Ruby ................ : $RUBY" echo " Using Ruby version ........ : $($RUBY --version)" fi if test "$have_rs" = "yes" ; then echo echo "Rust Library:" echo " Using Cargo................ : $CARGO" echo " Using rustc................ : $RUSTC" echo " Using Rust version......... : $($RUSTC --version)" fi if test "$have_swift" = "yes" ; then echo echo "Swift Library:" echo " Using Swift ............... : $SWIFT" echo " Using Swift version ....... : $($SWIFT --version | head -1)" fi echo echo "If something is missing that you think should be present," echo "please skim the output of configure to find the missing" echo "component. Details are present in config.log." echo thrift-0.16.0/contrib/000077500000000000000000000000001420101504100145225ustar00rootroot00000000000000thrift-0.16.0/contrib/README.md000066400000000000000000000014301420101504100157770ustar00rootroot00000000000000Apache Thrift contrib folder ======================================== The code in the /contrib folder is not maintained on a regular basis and its purpose is mainly to serve as repository of (a) sample code what can be done with Thrift and (b) possibly helpfil utilities or other potentially useful stuff. You are of course free to provide patches for it, but other than that, the contrib stuff may or may not work for your purpose, environment or software version, as it does not part of regular testing procedures. Below are some links (3rd-party sites) that lead you to some fairly good explanations of how it works. * https://drewdevault.com/2020/06/06/Add-a-contrib-directory.html * https://softwareengineering.stackexchange.com/questions/252053/whats-in-the-contrib-folder thrift-0.16.0/contrib/Rebus/000077500000000000000000000000001420101504100156025ustar00rootroot00000000000000thrift-0.16.0/contrib/Rebus/App.config000066400000000000000000000025141420101504100175130ustar00rootroot00000000000000
thrift-0.16.0/contrib/Rebus/Program.cs000066400000000000000000000053751420101504100175520ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using Rebus.Configuration; using Rebus.RabbitMQ; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using RebusSample.Client; using RebusSample.Server; namespace RebusSample { class Program { static BuiltinContainerAdapter StartRequestServer(string server) { // client Rebus configuration var adapter = new BuiltinContainerAdapter(); Configure.With(adapter) .Transport(t => t.UseRabbitMq("amqp://" + server, "MathRequests", "MathRequestErrors")) .MessageOwnership(o => o.FromRebusConfigurationSection()) .CreateBus().Start(); // register all relevant message handlers adapter.Register(typeof(MathRequestCallHandler)); return adapter; } static BuiltinContainerAdapter StartResponseServer(string server) { // client Rebus configuration var adapter = new BuiltinContainerAdapter(); Configure.With(adapter) .Transport(t => t.UseRabbitMq("amqp://" + server, "MathResponses", "MathResponseErrors")) .MessageOwnership(o => o.FromRebusConfigurationSection()) .CreateBus().Start(); // register all relevant message handlers adapter.Register(typeof(MathResponseCallHandler)); return adapter; } static void Main(string[] args) { string server = "localhost"; // start all servers var req = StartRequestServer(server); var rsp = StartResponseServer(server); // send the first message var random = new Random(); var client = new MathRequestClient(server); client.DoTheMath(random.Next(), random.Next()); // now what? Console.Write("Hit to stop ... "); Console.ReadLine(); } } } thrift-0.16.0/contrib/Rebus/Properties/000077500000000000000000000000001420101504100177365ustar00rootroot00000000000000thrift-0.16.0/contrib/Rebus/Properties/AssemblyInfo.cs000066400000000000000000000025621420101504100226650ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("RebusSample")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RebusSample")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("0af10984-40d3-453d-b1e5-421529e8c7e2")] [assembly: AssemblyVersion("0.16.0.0")] [assembly: AssemblyFileVersion("0.16.0.0")] thrift-0.16.0/contrib/Rebus/README.md000066400000000000000000000022761420101504100170700ustar00rootroot00000000000000Sample code for the combination of Thrift with Rebus. Rebus is a .NET service bus, similar to NServiceBus, but more lightweight. It ihas been mainly written by Mogens Heller Grabe and is currently hosted on GitHub (https://github.com/rebus-org/Rebus) As with all ServiceBus or MQ scenarios, due to the highly asynchronous operations it is recommended to do all calls as "oneway void" calls. The configuration can be done via App.Config, via code or even mixed from both locations. Refer to the Rebus documentation for further details. For this example, since we are effectively implementing two queue listeners in only one single process, we do configuration of incoming and error queues in the code. If you want to communicate with non-NET languages, you may need a customized serializer as well, in order to override Rebus' default wire format. Please refer to the Rebus docs on how to do that (it's not that hard, really). Additional requirements: - RabbitMQ .NET client (see nuget) Deprecation notice: Csharp is not a supported Apache Thrift target anymore. Instead netstd is the recommended replacement. This code is left "as is" for educational purposes unless someone converts it to netstd thrift-0.16.0/contrib/Rebus/RebusSample.csproj000066400000000000000000000105441420101504100212520ustar00rootroot00000000000000 Debug AnyCPU {264E2126-EDE0-4B47-89C1-B397B25BB13D} Exe Properties RebusSample RebusSample v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 ..\..\..\..\..\Toolbox\ServiceBus\3rdparty\rabbitmq-dotnet-client-3.2.1-dotnet-3.0\bin\RabbitMQ.Client.dll ..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.dll ..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.RabbitMQ.dll {499eb63c-d74c-47e8-ae48-a2fc94538e9d} Thrift cd $(ProjectDir) if not exist gen-csharp\*.cs thrift -gen csharp sample.thrift thrift-0.16.0/contrib/Rebus/RebusSample.sln000066400000000000000000000026501420101504100205450ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.30110.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RebusSample", "RebusSample.csproj", "{264E2126-EDE0-4B47-89C1-B397B25BB13D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.Build.0 = Debug|Any CPU {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.ActiveCfg = Release|Any CPU {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.Build.0 = Release|Any CPU {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal thrift-0.16.0/contrib/Rebus/ServiceImpl/000077500000000000000000000000001420101504100200245ustar00rootroot00000000000000thrift-0.16.0/contrib/Rebus/ServiceImpl/Both.cs000066400000000000000000000022711420101504100212510ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using System; namespace RebusSample { // generic data container for serialized Thrift calls public class GenericThriftServiceCall { public byte[] rawBytes; } // specific containers (one per Thrift service) to leverage Rebus' handler routing public class MathRequestCall : GenericThriftServiceCall { } public class MathResponseCall : GenericThriftServiceCall { } }thrift-0.16.0/contrib/Rebus/ServiceImpl/Client.cs000066400000000000000000000116161420101504100215760ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using Rebus; using Rebus.Configuration; using Rebus.Messages; using Rebus.RabbitMQ; using System; using System.Collections.Generic; using System.IO; using Thrift.Protocol; using Thrift.Transport; /* * The client emits calls to BasicMathServers * * The client implements the BasicMathClient service. * If the server has processed our request, we get the results back through this service */ namespace RebusSample.Client { // handler to be registered with Rebus class MathResponseCallHandler : IHandleMessages { public void Handle(MathResponseCall message) { // Thrift protocol/transport stack var stm = new MemoryStream(message.rawBytes); var trns = new TStreamTransport(stm, null); var prot = new TBinaryProtocol(trns); // create a processor and let him handle the call var hndl = new MathResponsesHandler(); var proc = new BasicMathClient.Processor(hndl); proc.Process(prot, null); // oneway only } } // serves incoming responses with calculation results internal class MathResponsesHandler : BasicMathClient.Iface { public void FourResults(int added, int multiplied, int subtracted, int divided) { Console.WriteLine("added = {0}", added); Console.WriteLine("multiplied= {0}", multiplied); Console.WriteLine("subtracted = {0}", subtracted); Console.WriteLine("divided = {0}", divided); PingAndDoAnotherCalculation(); } public void ThreeResults(int added, int multiplied, int subtracted) { Console.WriteLine("added = {0}", added); Console.WriteLine("multiplied= {0}", multiplied); Console.WriteLine("subtracted = {0}", subtracted); Console.WriteLine("DIV/0 error during division"); PingAndDoAnotherCalculation(); } public void Pong(long value) { var latency = DateTime.Now.Ticks - value; Console.WriteLine("Ping took {0} ms", new DateTime(latency).Millisecond); } private void PingAndDoAnotherCalculation() { var random = new Random(); var client = new MathRequestClient("localhost"); client.Ping(DateTime.Now.Ticks); client.DoTheMath(random.Next(), random.Next()); } } // provides the client-side interface for calculation requests internal class MathRequestClient : BasicMathServer.Iface { private BuiltinContainerAdapter MQAdapter; public MathRequestClient(string server) { MQAdapter = new BuiltinContainerAdapter(); Configure.With(MQAdapter) .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only .MessageOwnership(o => o.FromRebusConfigurationSection()) .CreateBus().Start(); } public void SerializeThriftCall(Action action) { // Thrift protocol/transport stack var stm = new MemoryStream(); var trns = new TStreamTransport(null, stm); var prot = new TBinaryProtocol(trns); // serialize the call into a bunch of bytes var client = new BasicMathServer.Client(prot); if( action != null) action(client); else throw new ArgumentException("action must not be null"); // make sure everything is written to the MemoryStream trns.Flush(); // send the message var msg = new MathRequestCall() { rawBytes = stm.ToArray() }; MQAdapter.Bus.Send(msg); } public void Ping(long value) { SerializeThriftCall(client => { client.Ping(value); }); } public void DoTheMath( int arg1, int arg2) { SerializeThriftCall(client => { client.DoTheMath(arg1, arg2); }); } } } thrift-0.16.0/contrib/Rebus/ServiceImpl/Server.cs000066400000000000000000000105411420101504100216220ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using Rebus; using Rebus.Configuration; using Rebus.Messages; using Rebus.RabbitMQ; using System; using System.Collections.Generic; using System.IO; using Thrift.Protocol; using Thrift.Transport; /* * The server implements the BasicMathServer service . * All results are sent back to the client via the BasicMathClient service */ namespace RebusSample.Server { // handler to be registered with Rebus class MathRequestCallHandler : IHandleMessages { public void Handle(MathRequestCall message) { // Thrift protocol/transport stack var stm = new MemoryStream(message.rawBytes); var trns = new TStreamTransport(stm, null); var prot = new TBinaryProtocol(trns); // create a processor and let him handle the call var hndl = new MathRequestsHandler(); var proc = new BasicMathServer.Processor(hndl); proc.Process(prot, null); // oneway only } } // serves incoming calculation requests internal class MathRequestsHandler : BasicMathServer.Iface { public void Ping(long value) { var client = new MathResponseClient("localhost"); client.Pong(value); } public void DoTheMath(int arg1, int arg2) { var client = new MathResponseClient("localhost"); if( arg2 != 0) client.FourResults( arg1+arg2, arg1*arg2, arg1-arg2, arg1/arg2); else client.ThreeResults( arg1+arg2, arg1*arg2, arg1-arg2); } } // provides the client-side interface for calculation responses internal class MathResponseClient : BasicMathClient.Iface { private BuiltinContainerAdapter MQAdapter; public MathResponseClient(string server) { MQAdapter = new BuiltinContainerAdapter(); Configure.With(MQAdapter) .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only .MessageOwnership(o => o.FromRebusConfigurationSection()) .CreateBus().Start(); } public void SerializeThriftCall(Action action) { // Thrift protocol/transport stack var stm = new MemoryStream(); var trns = new TStreamTransport(null, stm); var prot = new TBinaryProtocol(trns); // serialize the call into a bunch of bytes var client = new BasicMathClient.Client(prot); if (action != null) action(client); else throw new ArgumentException("action must not be null"); // make sure everything is written to the MemoryStream trns.Flush(); // send the message var msg = new MathResponseCall() { rawBytes = stm.ToArray() }; MQAdapter.Bus.Send(msg); } public void Pong(long value) { SerializeThriftCall(client => { client.Pong(value); }); } public void ThreeResults(int added, int multiplied, int suctracted) { SerializeThriftCall(client => { client.ThreeResults(added, multiplied, suctracted); }); } public void FourResults(int added, int multiplied, int suctracted, int divided) { SerializeThriftCall(client => { client.FourResults(added, multiplied, suctracted, divided); }); } } } thrift-0.16.0/contrib/Rebus/sample.thrift000066400000000000000000000022311420101504100203030ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ service BasicMathServer { oneway void DoTheMath( 1: i32 arg1, 2: i32 arg2) oneway void Ping(1: i64 value) } service BasicMathClient { oneway void ThreeResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted); oneway void FourResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted, 4 : i32 divided); oneway void Pong(1: i64 value) } thrift-0.16.0/contrib/Stomp/000077500000000000000000000000001420101504100156245ustar00rootroot00000000000000thrift-0.16.0/contrib/Stomp/README.md000066400000000000000000000015631420101504100171100ustar00rootroot00000000000000Sample code for STOMP-based Thrift clients and/or servers. Although the sample Thrift STOMP Transport is written in Delphi/Pascal, it can easily serve as a starting point for similar implementations in other languages. STOMP is a protocol widely supported by many messaging systems, such as Apache ActiveMQ, RabbitMQ and many others. In particular, it can be used to communicate with Service-Bus products like Rebus or NServiceBus, when running against a STOMP-capable MQ system. A prerequisite for this sample is the Delphi STOMP Adapter written by Daniele Teti (http://www.danieleteti.it/stomp-client), currently hosted at Google Code (http://code.google.com/p/delphistompclient). At the time of writing, the STOMP adapter does not fully support binary data. Please check whether this has been fixed, otherwise you have to use the JSON protocol (or to fix it on your own). thrift-0.16.0/contrib/Stomp/Thrift.Transport.STOMP.pas000066400000000000000000000107611420101504100224720ustar00rootroot00000000000000(* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *) unit Thrift.Transport.STOMP; interface uses Classes,Windows, SysUtils, Thrift, Thrift.Transport, Thrift.Protocol, Thrift.Stream, StompClient, StompTypes; type TStompTransportImpl = class( TStreamTransportImpl) strict private FData : TStringStream; FServer : string; FOutQueue : string; FStompCli : IStompClient; protected function GetIsOpen: Boolean; override; function Peek: Boolean; override; public constructor Create( const aServerAndPort, aOutQueue : string); destructor Destroy; override; procedure Open(); override; procedure Close(); override; procedure Flush; override; end; TStompServerTransportImpl = class( TServerTransportImpl) strict private FServer : string; FInQueue : string; FClient : IStompClient; protected procedure Listen; override; procedure Close; override; function Accept( const fnAccepting: TProc): ITransport; override; public constructor Create( const aServerAndPort, aInQueue : string); destructor Destroy; override; end; const QUEUE_PREFIX = '/queue/'; TOPIC_PREFIX = '/topic/'; EXCHANGE_PREFIX = '/exchange/'; implementation constructor TStompTransportImpl.Create( const aServerAndPort, aOutQueue : string); var adapter : IThriftStream; begin FData := TStringStream.Create; FServer := aServerAndPort; FOutQueue := aOutQueue; adapter := TThriftStreamAdapterDelphi.Create( FData, FALSE); inherited Create( nil, adapter); // output only end; destructor TStompTransportImpl.Destroy; begin inherited Destroy; FreeAndNil( FData); FStompCli := nil; end; function TStompTransportImpl.GetIsOpen: Boolean; begin result := (FStompCli <> nil); end; function TStompTransportImpl.Peek: Boolean; begin result := FALSE; // output only end; procedure TStompTransportImpl.Open; begin if FStompCli <> nil then raise TTransportException.Create( TTransportException.TExceptionType.AlreadyOpen, 'already open') else FStompCli := StompUtils.NewStomp( FServer); end; procedure TStompTransportImpl.Close; begin FStompCli := nil; FData.Clear; end; procedure TStompTransportImpl.Flush; begin if FStompCli = nil then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'not open'); FStompCli.Send( FOutQueue, FData.DataString); FData.Clear; end; //--- TStompServerTransportImpl -------------------------------------------- constructor TStompServerTransportImpl.Create( const aServerAndPort, aInQueue : string); begin inherited Create; FServer := aServerAndPort; FInQueue := aInQueue; end; destructor TStompServerTransportImpl.Destroy; begin try Close; finally inherited Destroy; end; end; procedure TStompServerTransportImpl.Listen; begin FClient := StompUtils.NewStomp(FServer); FClient.Subscribe( FInQueue); end; procedure TStompServerTransportImpl.Close; begin if FClient <> nil then begin FClient.Unsubscribe( FInQueue); FClient := nil; end; end; function TStompServerTransportImpl.Accept( const fnAccepting: TProc): ITransport; var frame : IStompFrame; adapter : IThriftStream; stream : TStringStream; begin if FClient = nil then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'Not connected.'); if Assigned(fnAccepting) then fnAccepting(); try frame := FClient.Receive(MAXINT); if frame = nil then Exit(nil); stream := TStringStream.Create( frame.GetBody); adapter := TThriftStreamAdapterDelphi.Create( stream, TRUE); result := TStreamTransportImpl.Create( adapter, nil); except on E: Exception do raise TTransportException.Create( E.ToString ); end; end; end. thrift-0.16.0/contrib/Vagrantfile000066400000000000000000000076451420101504100167230ustar00rootroot00000000000000# -*- mode: ruby -*- # vi: set ft=ruby : # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # $build_and_test = < ### hello.js - Node Server var thrift = require('thrift'); var hello_svc = require('./gen-nodejs/hello_svc.js'); var hello_handler = { get_message: function(name, result) { var msg = "Hello " + name + "!"; result(null, msg); } } var hello_svc_opt = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: hello_svc, handler: hello_handler }; var server_opt = { staticFilePath: ".", services: { "/hello": hello_svc_opt } } var server = Thrift.createWebServer(server_opt); var port = 9099; server.listen(port); console.log("Http/Thrift Server running on port: " + port); TypeScript ------------------------------------ TypeScript definition files can also be generated by running: thrift --gen js:ts file.thrift # Breaking Changes ## 0.13.0 1. 64-bit integer constants are now generatd using node-int64 e.g.: var x = new Int64("7fffffffffffffff"); thrift-0.16.0/lib/js/coding_standards.md000066400000000000000000000001031420101504100200660ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/js/package-lock.json000066400000000000000000003514511420101504100174710ustar00rootroot00000000000000{ "name": "thrift", "version": "0.16.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/parser": { "version": "7.14.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.4.tgz", "integrity": "sha512-ArliyUsWDUqEGfWcmzpGUzNfLxTdTp6WU4IuP6QFSp9gGfWS6boxFCkJSJ/L4+RG8z/FnIU3WxCk6hPL9SSWeA==", "dev": true }, "JSONStream": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", "dev": true, "requires": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" } }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "acorn-node": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", "dev": true, "requires": { "acorn": "^7.0.0", "acorn-walk": "^7.0.0", "xtend": "^4.0.2" } }, "acorn-walk": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", "dev": true }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" } }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" }, "dependencies": { "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true } } }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "dev": true }, "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "assert": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, "requires": { "object-assign": "^4.1.1", "util": "0.10.3" }, "dependencies": { "inherits": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", "dev": true }, "util": { "version": "0.10.3", "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { "inherits": "2.0.1" } } } }, "async": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==", "dev": true }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" } }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, "browser-pack": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", "dev": true, "requires": { "JSONStream": "^1.0.3", "combine-source-map": "~0.8.0", "defined": "^1.0.0", "safe-buffer": "^5.1.1", "through2": "^2.0.0", "umd": "^3.0.0" } }, "browser-resolve": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", "dev": true, "requires": { "resolve": "1.1.7" } }, "browserify": { "version": "16.5.0", "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.5.0.tgz", "integrity": "sha512-6bfI3cl76YLAnCZ75AGu/XPOsqUhRyc0F/olGIJeCxtfxF2HvPKEcmjU9M8oAPxl4uBY1U7Nry33Q6koV3f2iw==", "dev": true, "requires": { "JSONStream": "^1.0.3", "assert": "^1.4.0", "browser-pack": "^6.0.1", "browser-resolve": "^1.11.0", "browserify-zlib": "~0.2.0", "buffer": "^5.0.2", "cached-path-relative": "^1.0.0", "concat-stream": "^1.6.0", "console-browserify": "^1.1.0", "constants-browserify": "~1.0.0", "crypto-browserify": "^3.0.0", "defined": "^1.0.0", "deps-sort": "^2.0.0", "domain-browser": "^1.2.0", "duplexer2": "~0.1.2", "events": "^2.0.0", "glob": "^7.1.0", "has": "^1.0.0", "htmlescape": "^1.1.0", "https-browserify": "^1.0.0", "inherits": "~2.0.1", "insert-module-globals": "^7.0.0", "labeled-stream-splicer": "^2.0.0", "mkdirp": "^0.5.0", "module-deps": "^6.0.0", "os-browserify": "~0.3.0", "parents": "^1.0.1", "path-browserify": "~0.0.0", "process": "~0.11.0", "punycode": "^1.3.2", "querystring-es3": "~0.2.0", "read-only-stream": "^2.0.0", "readable-stream": "^2.0.2", "resolve": "^1.1.4", "shasum": "^1.0.0", "shell-quote": "^1.6.1", "stream-browserify": "^2.0.0", "stream-http": "^3.0.0", "string_decoder": "^1.1.1", "subarg": "^1.0.0", "syntax-error": "^1.1.1", "through2": "^2.0.0", "timers-browserify": "^1.0.1", "tty-browserify": "0.0.1", "url": "~0.11.0", "util": "~0.10.1", "vm-browserify": "^1.0.0", "xtend": "^4.0.0" }, "dependencies": { "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" }, "dependencies": { "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { "safe-buffer": "~5.2.0" }, "dependencies": { "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", "dev": true } } } } }, "browserify-aes": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.3", "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "browserify-cipher": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", "evp_bytestokey": "^1.0.0" } }, "browserify-des": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, "browserify-rsa": { "version": "4.0.1", "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" } }, "browserify-sign": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { "bn.js": "^4.1.1", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "create-hmac": "^1.1.2", "elliptic": "^6.0.0", "inherits": "^2.0.1", "parse-asn1": "^5.0.0" } }, "browserify-zlib": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { "pako": "~1.0.5" } }, "buffer": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "buffer-shims": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", "dev": true }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, "cached-path-relative": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==", "dev": true }, "catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", "dev": true, "requires": { "lodash": "^4.17.15" }, "dependencies": { "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true } } }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", "dev": true, "requires": { "exit": "0.1.2", "glob": "^7.1.1" }, "dependencies": { "glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } } } }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { "color-name": "1.1.3" } }, "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, "combine-source-map": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", "dev": true, "requires": { "convert-source-map": "~1.1.0", "inline-source-map": "~0.6.0", "lodash.memoize": "~3.0.3", "source-map": "~0.5.3" } }, "commander": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" }, "dependencies": { "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, "requires": { "date-now": "^0.1.4" } }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", "dev": true }, "convert-source-map": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", "dev": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" } }, "create-hash": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", "md5.js": "^1.3.4", "ripemd160": "^2.0.1", "sha.js": "^2.4.0" } }, "create-hmac": { "version": "1.1.7", "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", "inherits": "^2.0.1", "ripemd160": "^2.0.0", "safe-buffer": "^5.0.1", "sha.js": "^2.4.8" } }, "cross-spawn": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "dependencies": { "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } } } }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", "create-ecdh": "^4.0.0", "create-hash": "^1.1.0", "create-hmac": "^1.1.0", "diffie-hellman": "^5.0.0", "inherits": "^2.0.1", "pbkdf2": "^3.0.3", "public-encrypt": "^4.0.0", "randombytes": "^2.0.0", "randomfill": "^1.0.3" } }, "dash-ast": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", "dev": true }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", "dev": true }, "deps-sort": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", "dev": true, "requires": { "JSONStream": "^1.0.3", "shasum-object": "^1.0.0", "subarg": "^1.0.0", "through2": "^2.0.0" } }, "des.js": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dev": true, "requires": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, "detective": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", "dev": true, "requires": { "acorn-node": "^1.6.1", "defined": "^1.0.0", "minimist": "^1.1.1" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "diffie-hellman": { "version": "5.0.3", "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" } }, "dom-serializer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "dev": true, "requires": { "domelementtype": "^1.3.0", "entities": "^1.1.1" }, "dependencies": { "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true } } }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, "domhandler": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", "dev": true, "requires": { "domelementtype": "1" } }, "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { "dom-serializer": "0", "domelementtype": "1" } }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "requires": { "readable-stream": "^2.0.2" }, "dependencies": { "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "elliptic": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dev": true, "requires": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" }, "dependencies": { "bn.js": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true } } }, "entities": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", "dev": true }, "es6-promise": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", "dev": true }, "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { "es6-promise": "^4.0.3" } }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "eventemitter2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", "dev": true }, "events": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", "dev": true }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" } }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, "extract-zip": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", "dev": true, "requires": { "concat-stream": "^1.6.2", "debug": "^2.6.9", "mkdirp": "^0.5.4", "yauzl": "^2.10.0" } }, "fast-safe-stringify": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", "dev": true }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, "requires": { "pend": "~1.2.0" } }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { "escape-string-regexp": "^1.0.5", "object-assign": "^4.1.0" } }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, "findup-sync": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", "dev": true, "requires": { "glob": "~5.0.0" }, "dependencies": { "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { "inflight": "^1.0.4", "inherits": "2", "minimatch": "2 || 3", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } } } }, "fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, "requires": { "expand-tilde": "^2.0.2", "is-plain-object": "^2.0.3", "object.defaults": "^1.1.0", "object.pick": "^1.2.0", "parse-filepath": "^1.0.1" } }, "flagged-respawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, "for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { "for-in": "^1.0.1" } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "get-assigned-identifiers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", "dev": true }, "getobject": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", "dev": true }, "glob": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.2", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { "global-prefix": "^1.0.1", "is-windows": "^1.0.1", "resolve-dir": "^1.0.0" } }, "global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { "expand-tilde": "^2.0.2", "homedir-polyfill": "^1.0.1", "ini": "^1.3.4", "is-windows": "^1.0.1", "which": "^1.2.14" } }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "grunt": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.4.1.tgz", "integrity": "sha512-ZXIYXTsAVrA7sM+jZxjQdrBOAg7DyMUplOMhTaspMRExei+fD0BTwdWXnn0W5SXqhb/Q/nlkzXclSi3IH55PIA==", "dev": true, "requires": { "dateformat": "~3.0.3", "eventemitter2": "~0.4.13", "exit": "~0.1.2", "findup-sync": "~0.3.0", "glob": "~7.1.6", "grunt-cli": "~1.4.2", "grunt-known-options": "~2.0.0", "grunt-legacy-log": "~3.0.0", "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.4.13", "js-yaml": "~3.14.0", "minimatch": "~3.0.4", "mkdirp": "~1.0.4", "nopt": "~3.0.6", "rimraf": "~3.0.2" }, "dependencies": { "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { "abbrev": "1" } }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } } } }, "grunt-cli": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, "requires": { "grunt-known-options": "~2.0.0", "interpret": "~1.1.0", "liftup": "~3.0.1", "nopt": "~4.0.1", "v8flags": "~3.2.0" } }, "grunt-contrib-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz", "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=", "dev": true, "requires": { "chalk": "^1.0.0", "source-map": "^0.5.3" }, "dependencies": { "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } } }, "grunt-contrib-jshint": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-2.1.0.tgz", "integrity": "sha512-65S2/C/6RfjY/umTxfwXXn+wVvaYmykHkHSsW6Q6rhkbv3oudTEgqnFFZvWzWCoHUb+3GMZLbP3oSrNyvshmIQ==", "dev": true, "requires": { "chalk": "^2.4.2", "hooker": "^0.2.3", "jshint": "~2.10.2" }, "dependencies": { "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } } } }, "grunt-contrib-qunit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/grunt-contrib-qunit/-/grunt-contrib-qunit-3.1.0.tgz", "integrity": "sha512-mdk8UltH6mxCD63E0hTXMAts42DOi4z4bBBrY7qnuHiShflMF7IueSMYe0zWaZ2dO8mgujh57Zfny2EbigJhRg==", "dev": true, "requires": { "eventemitter2": "^5.0.1", "p-each-series": "^1.0.0", "puppeteer": "^1.11.0" }, "dependencies": { "eventemitter2": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=", "dev": true } } }, "grunt-contrib-uglify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-4.0.1.tgz", "integrity": "sha512-dwf8/+4uW1+7pH72WButOEnzErPGmtUvc8p08B0eQS/6ON0WdeQu0+WFeafaPTbbY1GqtS25lsHWaDeiTQNWPg==", "dev": true, "requires": { "chalk": "^2.4.1", "maxmin": "^2.1.0", "uglify-js": "^3.5.0", "uri-path": "^1.0.0" } }, "grunt-jsdoc": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/grunt-jsdoc/-/grunt-jsdoc-2.4.1.tgz", "integrity": "sha512-S0zxU0wDewRu7z+vijEItOWe/UttxWVmvz0qz2ZVcAYR2GpXjsiski2CAVN0b18t2qeVLdmxZkJaEWCOsKzcAw==", "dev": true, "requires": { "cross-spawn": "^7.0.1", "jsdoc": "^3.6.3" } }, "grunt-known-options": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true }, "grunt-legacy-log": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", "dev": true, "requires": { "colors": "~1.1.2", "grunt-legacy-log-utils": "~2.1.0", "hooker": "~0.2.3", "lodash": "~4.17.19" }, "dependencies": { "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true } } }, "grunt-legacy-log-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", "dev": true, "requires": { "chalk": "~4.1.0", "lodash": "~4.17.19" }, "dependencies": { "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { "color-convert": "^2.0.1" } }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" } } } }, "grunt-legacy-util": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", "dev": true, "requires": { "async": "~3.2.0", "exit": "~0.1.2", "getobject": "~1.0.0", "hooker": "~0.2.3", "lodash": "~4.17.21", "underscore.string": "~3.3.5", "which": "~2.0.2" }, "dependencies": { "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } } } }, "grunt-shell-spawn": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/grunt-shell-spawn/-/grunt-shell-spawn-0.4.0.tgz", "integrity": "sha512-lfYvEQjbO1Wv+1Fk3d3XlcEpuQjyXiErZMkiz/i/tDQeMHHGF1LziqA4ZcietBAo/bM2RHdEEUJfnNWt1VRMwQ==", "dev": true, "requires": { "grunt": ">=0.4.x" } }, "gzip-size": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", "dev": true, "requires": { "duplexer": "^0.1.1" } }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { "function-bind": "^1.1.1" } }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "hash-base": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { "parse-passwd": "^1.0.0" } }, "hooker": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", "dev": true }, "htmlescape": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", "dev": true }, "htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", "dev": true, "requires": { "domelementtype": "1", "domhandler": "2.3", "domutils": "1.5", "entities": "1.0", "readable-stream": "1.1" } }, "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, "https-proxy-agent": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" }, "dependencies": { "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "requires": { "es6-promisify": "^5.0.0" } }, "debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" } }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "inline-source-map": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", "dev": true, "requires": { "source-map": "~0.5.3" } }, "insert-module-globals": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", "dev": true, "requires": { "JSONStream": "^1.0.3", "acorn-node": "^1.5.2", "combine-source-map": "^0.8.0", "concat-stream": "^1.6.1", "is-buffer": "^1.1.0", "path-is-absolute": "^1.0.1", "process": "~0.11.0", "through2": "^2.0.0", "undeclared-identifiers": "^1.1.2", "xtend": "^4.0.0" } }, "interpret": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", "dev": true }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { "is-relative": "^1.0.0", "is-windows": "^1.0.1" } }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-core-module": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dev": true, "requires": { "has": "^1.0.3" } }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "^3.0.1" } }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" } }, "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" } }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" } }, "js2xmlparser": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", "dev": true, "requires": { "xmlcreate": "^2.0.3" } }, "jsdoc": { "version": "3.6.7", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", "dev": true, "requires": { "@babel/parser": "^7.9.4", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.1", "klaw": "^3.0.0", "markdown-it": "^10.0.0", "markdown-it-anchor": "^5.2.7", "marked": "^2.0.3", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", "underscore": "~1.13.1" }, "dependencies": { "escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true } } }, "jshint": { "version": "2.10.2", "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", "lodash": "~4.17.11", "minimatch": "~3.0.2", "shelljs": "0.3.x", "strip-json-comments": "1.0.x" }, "dependencies": { "strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", "dev": true } } }, "jslint": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/jslint/-/jslint-0.12.1.tgz", "integrity": "sha512-q5iHswjOmJffbsGVq/1umGh4YBxb5pCArNHCZeHpkuVDDKM6IldqUn4hLehKSwQr7Bn07VXjD34Lx3nw+6j8eA==", "dev": true, "requires": { "exit": "~0.1.2", "glob": "~7.1.3", "nopt": "~4.0.1", "readable-stream": "~2.1.5" }, "dependencies": { "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, "readable-stream": { "version": "2.1.5", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", "dev": true, "requires": { "buffer-shims": "^1.0.0", "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "~1.0.0", "process-nextick-args": "~1.0.6", "string_decoder": "~0.10.x", "util-deprecate": "~1.0.1" } } } }, "json-int64": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-int64/-/json-int64-1.0.2.tgz", "integrity": "sha512-uGrIXtRehbksM17S2lJRLPljufK52KL2ewbJi0xgcRPONoRLXa4yAUIKAUxF69dbnqIoBu33fB28MAWSxupB8Q==", "dev": true, "requires": { "node-int64": "0.4.0" } }, "json-stable-stringify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", "dev": true, "requires": { "jsonify": "~0.0.0" } }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, "klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", "dev": true, "requires": { "graceful-fs": "^4.1.9" } }, "labeled-stream-splicer": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", "dev": true, "requires": { "inherits": "^2.0.1", "stream-splicer": "^2.0.0" } }, "liftup": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", "dev": true, "requires": { "extend": "^3.0.2", "findup-sync": "^4.0.0", "fined": "^1.2.0", "flagged-respawn": "^1.0.1", "is-plain-object": "^2.0.4", "object.map": "^1.0.1", "rechoir": "^0.7.0", "resolve": "^1.19.0" }, "dependencies": { "findup-sync": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "dev": true, "requires": { "detect-file": "^1.0.0", "is-glob": "^4.0.0", "micromatch": "^4.0.2", "resolve-dir": "^1.0.1" } }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } } } }, "linkify-it": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "dev": true, "requires": { "uc.micro": "^1.0.1" } }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash.memoize": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", "dev": true }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { "kind-of": "^6.0.2" } }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, "markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "dev": true, "requires": { "argparse": "^1.0.7", "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, "dependencies": { "entities": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", "dev": true } } }, "markdown-it-anchor": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", "dev": true }, "marked": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.7.tgz", "integrity": "sha512-BJXxkuIfJchcXOJWTT2DOL+yFWifFv2yGYOUzvXg8Qz610QKw+sHCvTMYwA+qWGhlA2uivBezChZ/pBy1tWdkQ==", "dev": true }, "maxmin": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=", "dev": true, "requires": { "chalk": "^1.0.0", "figures": "^1.0.1", "gzip-size": "^3.0.0", "pretty-bytes": "^3.0.0" }, "dependencies": { "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } } }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", "dev": true }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" } }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" } }, "mime": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", "dev": true }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { "minimist": "^1.2.5" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "module-deps": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.2.tgz", "integrity": "sha512-a9y6yDv5u5I4A+IPHTnqFxcaKr4p50/zxTjcQJaX2ws9tN/W6J6YXnEKhqRyPhl494dkcxx951onSKVezmI+3w==", "dev": true, "requires": { "JSONStream": "^1.0.3", "browser-resolve": "^1.7.0", "cached-path-relative": "^1.0.2", "concat-stream": "~1.6.0", "defined": "^1.0.0", "detective": "^5.2.0", "duplexer2": "^0.1.2", "inherits": "^2.0.1", "parents": "^1.0.0", "readable-stream": "^2.0.2", "resolve": "^1.4.0", "stream-combiner2": "^1.1.1", "subarg": "^1.0.0", "through2": "^2.0.0", "xtend": "^4.0.0" }, "dependencies": { "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "resolve": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, "nopt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "requires": { "array-each": "^1.0.1", "array-slice": "^1.0.0", "for-own": "^1.0.0", "isobject": "^3.0.0" } }, "object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", "dev": true, "requires": { "for-own": "^1.0.0", "make-iterator": "^1.0.0" } }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { "isobject": "^3.0.1" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" } }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, "p-each-series": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", "dev": true, "requires": { "p-reduce": "^1.0.0" } }, "p-reduce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", "dev": true }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, "parents": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", "dev": true, "requires": { "path-platform": "~0.11.15" } }, "parse-asn1": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", "dev": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", "pbkdf2": "^3.0.3", "safe-buffer": "^5.1.1" } }, "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "requires": { "is-absolute": "^1.0.0", "map-cache": "^0.2.0", "path-root": "^0.1.1" } }, "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, "path-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-platform": { "version": "0.11.15", "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", "dev": true }, "path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { "path-root-regex": "^0.1.0" } }, "path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", "dev": true }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "dev": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", "ripemd160": "^2.0.1", "safe-buffer": "^5.0.1", "sha.js": "^2.4.8" } }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pretty-bytes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", "dev": true }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", "dev": true }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" } }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, "puppeteer": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz", "integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==", "dev": true, "requires": { "debug": "^4.1.0", "extract-zip": "^1.6.6", "https-proxy-agent": "^2.2.1", "mime": "^2.0.3", "progress": "^2.0.1", "proxy-from-env": "^1.0.0", "rimraf": "^2.6.1", "ws": "^6.1.0" }, "dependencies": { "debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" } }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", "dev": true }, "querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { "safe-buffer": "^5.1.0" } }, "randomfill": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "requires": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", "dev": true, "requires": { "readable-stream": "^2.0.2" }, "dependencies": { "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" }, "dependencies": { "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true } } }, "rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { "resolve": "^1.9.0" }, "dependencies": { "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } } } }, "requizzle": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", "dev": true, "requires": { "lodash": "^4.17.14" }, "dependencies": { "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true } } }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "requires": { "expand-tilde": "^2.0.0", "global-modules": "^1.0.0" } }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { "glob": "^7.0.5" } }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "sha.js": { "version": "2.4.11", "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "shasum": { "version": "1.0.2", "resolved": "http://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", "dev": true, "requires": { "json-stable-stringify": "~0.0.0", "sha.js": "~2.4.4" } }, "shasum-object": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", "dev": true, "requires": { "fast-safe-stringify": "^2.0.7" } }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "shell-quote": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", "dev": true }, "shelljs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", "dev": true }, "simple-concat": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", "dev": true }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, "sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", "dev": true }, "stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" }, "dependencies": { "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "stream-combiner2": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", "dev": true, "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" }, "dependencies": { "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "stream-http": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.0.tgz", "integrity": "sha512-cuB6RgO7BqC4FBYzmnvhob5Do3wIdIsXAgGycHJnW+981gHqoYcYz9lqjJrk8WXRddbwPuqPYRl+bag6mYv4lw==", "dev": true, "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", "readable-stream": "^3.0.6", "xtend": "^4.0.0" }, "dependencies": { "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", "dev": true }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { "safe-buffer": "~5.2.0" } } } }, "stream-splicer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.2" }, "dependencies": { "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, "strip-ansi": { "version": "3.0.1", "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", "dev": true, "requires": { "minimist": "^1.1.0" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } }, "syntax-error": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", "dev": true, "requires": { "acorn-node": "^1.2.0" } }, "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", "dev": true }, "through": { "version": "2.3.8", "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" }, "dependencies": { "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "timers-browserify": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", "dev": true, "requires": { "process": "~0.11.0" } }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" } }, "tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", "dev": true }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, "uglify-js": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "requires": { "commander": "~2.20.0", "source-map": "~0.6.1" }, "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "umd": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", "dev": true }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, "undeclared-identifiers": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", "dev": true, "requires": { "acorn-node": "^1.3.0", "dash-ast": "^1.0.0", "get-assigned-identifiers": "^1.2.0", "simple-concat": "^1.0.0", "xtend": "^4.0.1" } }, "underscore": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "underscore.string": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", "dev": true, "requires": { "sprintf-js": "^1.0.3", "util-deprecate": "^1.0.2" } }, "uri-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", "dev": true }, "url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "dev": true, "requires": { "punycode": "1.3.2", "querystring": "0.2.0" }, "dependencies": { "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", "dev": true } } }, "util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "dev": true, "requires": { "inherits": "2.0.3" } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, "v8flags": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" } }, "vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "dev": true }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "ws": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "dev": true, "requires": { "async-limiter": "~1.0.0" } }, "xmlcreate": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", "dev": true }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } } } } thrift-0.16.0/lib/js/package.json000066400000000000000000000015711420101504100165360ustar00rootroot00000000000000{ "name": "thrift", "version": "0.16.0", "description": "Thrift is a software framework for scalable cross-language services development.", "main": "./src/thrift", "author": { "name": "Apache Thrift Developers", "email": "dev@thrift.apache.org" }, "bugs": "https://issues.apache.org/jira/projects/THRIFT/summary", "homepage": "http://thrift.apache.org", "repository": "https://github.com/apache/thrift", "license": "Apache-2.0", "devDependencies": { "browserify": "~16.5", "grunt": "^1.4.1", "grunt-cli": "^1.4.3", "grunt-contrib-concat": "~1.0", "grunt-contrib-jshint": "~2.1", "grunt-contrib-qunit": "~3.1", "grunt-contrib-uglify": "~4.0", "grunt-jsdoc": "~2.4", "grunt-shell-spawn": "~0.4", "jsdoc": "^3.6.7", "jslint": "~0.12.1", "json-int64": "~1.0.2", "node-int64": "~0.4.0", "nopt": "~4.0" } } thrift-0.16.0/lib/js/src/000077500000000000000000000000001420101504100150335ustar00rootroot00000000000000thrift-0.16.0/lib/js/src/thrift.js000066400000000000000000001401261420101504100166750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /*jshint evil:true*/ /** * The Thrift namespace houses the Apache Thrift JavaScript library * elements providing JavaScript bindings for the Apache Thrift RPC * system. End users will typically only directly make use of the * Transport (TXHRTransport/TWebSocketTransport) and Protocol * (TJSONPRotocol/TBinaryProtocol) constructors. * * Object methods beginning with a __ (e.g. __onOpen()) are internal * and should not be called outside of the object's own methods. * * This library creates one global object: Thrift * Code in this library must never create additional global identifiers, * all features must be scoped within the Thrift namespace. * @namespace * @example * var transport = new Thrift.Transport('http://localhost:8585'); * var protocol = new Thrift.Protocol(transport); * var client = new MyThriftSvcClient(protocol); * var result = client.MyMethod(); */ var Thrift = { /** * Thrift JavaScript library version. * @readonly * @const {string} Version * @memberof Thrift */ Version: '0.16.0', /** * Thrift IDL type string to Id mapping. * @readonly * @property {number} STOP - End of a set of fields. * @property {number} VOID - No value (only legal for return types). * @property {number} BOOL - True/False integer. * @property {number} BYTE - Signed 8 bit integer. * @property {number} I08 - Signed 8 bit integer. * @property {number} DOUBLE - 64 bit IEEE 854 floating point. * @property {number} I16 - Signed 16 bit integer. * @property {number} I32 - Signed 32 bit integer. * @property {number} I64 - Signed 64 bit integer. * @property {number} STRING - Array of bytes representing a string of characters. * @property {number} UTF7 - Array of bytes representing a string of UTF7 encoded characters. * @property {number} STRUCT - A multifield type. * @property {number} MAP - A collection type (map/associative-array/dictionary). * @property {number} SET - A collection type (unordered and without repeated values). * @property {number} LIST - A collection type (unordered). * @property {number} UTF8 - Array of bytes representing a string of UTF8 encoded characters. * @property {number} UTF16 - Array of bytes representing a string of UTF16 encoded characters. */ Type: { STOP: 0, VOID: 1, BOOL: 2, BYTE: 3, I08: 3, DOUBLE: 4, I16: 6, I32: 8, I64: 10, STRING: 11, UTF7: 11, STRUCT: 12, MAP: 13, SET: 14, LIST: 15, UTF8: 16, UTF16: 17 }, /** * Thrift RPC message type string to Id mapping. * @readonly * @property {number} CALL - RPC call sent from client to server. * @property {number} REPLY - RPC call normal response from server to client. * @property {number} EXCEPTION - RPC call exception response from server to client. * @property {number} ONEWAY - Oneway RPC call from client to server with no response. */ MessageType: { CALL: 1, REPLY: 2, EXCEPTION: 3, ONEWAY: 4 }, /** * Utility function returning the count of an object's own properties. * @param {object} obj - Object to test. * @returns {number} number of object's own properties */ objectLength: function(obj) { var length = 0; for (var k in obj) { if (obj.hasOwnProperty(k)) { length++; } } return length; }, /** * Utility function to establish prototype inheritance. * @see {@link http://javascript.crockford.com/prototypal.html|Prototypal Inheritance} * @param {function} constructor - Contstructor function to set as derived. * @param {function} superConstructor - Contstructor function to set as base. * @param {string} [name] - Type name to set as name property in derived prototype. */ inherits: function(constructor, superConstructor, name) { function F() {} F.prototype = superConstructor.prototype; constructor.prototype = new F(); constructor.prototype.name = name || ''; } }; /** * Initializes a Thrift TException instance. * @constructor * @augments Error * @param {string} message - The TException message (distinct from the Error message). * @classdesc TException is the base class for all Thrift exceptions types. */ Thrift.TException = function(message) { this.message = message; }; Thrift.inherits(Thrift.TException, Error, 'TException'); /** * Returns the message set on the exception. * @readonly * @returns {string} exception message */ Thrift.TException.prototype.getMessage = function() { return this.message; }; /** * Thrift Application Exception type string to Id mapping. * @readonly * @property {number} UNKNOWN - Unknown/undefined. * @property {number} UNKNOWN_METHOD - Client attempted to call a method unknown to the server. * @property {number} INVALID_MESSAGE_TYPE - Client passed an unknown/unsupported MessageType. * @property {number} WRONG_METHOD_NAME - Unused. * @property {number} BAD_SEQUENCE_ID - Unused in Thrift RPC, used to flag proprietary sequence number errors. * @property {number} MISSING_RESULT - Raised by a server processor if a handler fails to supply the required return result. * @property {number} INTERNAL_ERROR - Something bad happened. * @property {number} PROTOCOL_ERROR - The protocol layer failed to serialize or deserialize data. * @property {number} INVALID_TRANSFORM - Unused. * @property {number} INVALID_PROTOCOL - The protocol (or version) is not supported. * @property {number} UNSUPPORTED_CLIENT_TYPE - Unused. */ Thrift.TApplicationExceptionType = { UNKNOWN: 0, UNKNOWN_METHOD: 1, INVALID_MESSAGE_TYPE: 2, WRONG_METHOD_NAME: 3, BAD_SEQUENCE_ID: 4, MISSING_RESULT: 5, INTERNAL_ERROR: 6, PROTOCOL_ERROR: 7, INVALID_TRANSFORM: 8, INVALID_PROTOCOL: 9, UNSUPPORTED_CLIENT_TYPE: 10 }; /** * Initializes a Thrift TApplicationException instance. * @constructor * @augments Thrift.TException * @param {string} message - The TApplicationException message (distinct from the Error message). * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code. * @classdesc TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client. */ Thrift.TApplicationException = function(message, code) { this.message = message; this.code = typeof code === 'number' ? code : 0; }; Thrift.inherits(Thrift.TApplicationException, Thrift.TException, 'TApplicationException'); /** * Read a TApplicationException from the supplied protocol. * @param {object} input - The input protocol to read from. */ Thrift.TApplicationException.prototype.read = function(input) { while (1) { var ret = input.readFieldBegin(); if (ret.ftype == Thrift.Type.STOP) { break; } var fid = ret.fid; switch (fid) { case 1: if (ret.ftype == Thrift.Type.STRING) { ret = input.readString(); this.message = ret.value; } else { ret = input.skip(ret.ftype); } break; case 2: if (ret.ftype == Thrift.Type.I32) { ret = input.readI32(); this.code = ret.value; } else { ret = input.skip(ret.ftype); } break; default: ret = input.skip(ret.ftype); break; } input.readFieldEnd(); } input.readStructEnd(); }; /** * Wite a TApplicationException to the supplied protocol. * @param {object} output - The output protocol to write to. */ Thrift.TApplicationException.prototype.write = function(output) { output.writeStructBegin('TApplicationException'); if (this.message) { output.writeFieldBegin('message', Thrift.Type.STRING, 1); output.writeString(this.getMessage()); output.writeFieldEnd(); } if (this.code) { output.writeFieldBegin('type', Thrift.Type.I32, 2); output.writeI32(this.code); output.writeFieldEnd(); } output.writeFieldStop(); output.writeStructEnd(); }; /** * Returns the application exception code set on the exception. * @readonly * @returns {Thrift.TApplicationExceptionType} exception code */ Thrift.TApplicationException.prototype.getCode = function() { return this.code; }; Thrift.TProtocolExceptionType = { UNKNOWN: 0, INVALID_DATA: 1, NEGATIVE_SIZE: 2, SIZE_LIMIT: 3, BAD_VERSION: 4, NOT_IMPLEMENTED: 5, DEPTH_LIMIT: 6 }; Thrift.TProtocolException = function TProtocolException(type, message) { Error.call(this); if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, this.constructor); } this.name = this.constructor.name; this.type = type; this.message = message; }; Thrift.inherits(Thrift.TProtocolException, Thrift.TException, 'TProtocolException'); /** * Constructor Function for the XHR transport. * If you do not specify a url then you must handle XHR operations on * your own. This type can also be constructed using the Transport alias * for backward compatibility. * @constructor * @param {string} [url] - The URL to connect to. * @classdesc The Apache Thrift Transport layer performs byte level I/O * between RPC clients and servers. The JavaScript TXHRTransport object * uses Http[s]/XHR. Target servers must implement the http[s] transport * (see: node.js example server_http.js). * @example * var transport = new Thrift.TXHRTransport("http://localhost:8585"); */ Thrift.Transport = Thrift.TXHRTransport = function(url, options) { this.url = url; this.wpos = 0; this.rpos = 0; this.useCORS = (options && options.useCORS); this.customHeaders = options ? (options.customHeaders ? options.customHeaders : {}): {}; this.send_buf = ''; this.recv_buf = ''; }; Thrift.TXHRTransport.prototype = { /** * Gets the browser specific XmlHttpRequest Object. * @returns {object} the browser XHR interface object */ getXmlHttpRequestObject: function() { try { return new XMLHttpRequest(); } catch (e1) { } try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { } try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { } throw "Your browser doesn't support XHR."; }, /** * Sends the current XRH request if the transport was created with a URL * and the async parameter is false. If the transport was not created with * a URL, or the async parameter is True and no callback is provided, or * the URL is an empty string, the current send buffer is returned. * @param {object} async - If true the current send buffer is returned. * @param {object} callback - Optional async completion callback * @returns {undefined|string} Nothing or the current send buffer. * @throws {string} If XHR fails. */ flush: function(async, callback) { var self = this; if ((async && !callback) || this.url === undefined || this.url === '') { return this.send_buf; } var xreq = this.getXmlHttpRequestObject(); if (xreq.overrideMimeType) { xreq.overrideMimeType('application/vnd.apache.thrift.json; charset=utf-8'); } if (callback) { //Ignore XHR callbacks until the data arrives, then call the // client's callback xreq.onreadystatechange = (function() { var clientCallback = callback; return function() { if (this.readyState == 4 && this.status == 200) { self.setRecvBuffer(this.responseText); clientCallback(); } }; }()); // detect net::ERR_CONNECTION_REFUSED and call the callback. xreq.onerror = (function() { var clientCallback = callback; return function() { clientCallback(); }; }()); } xreq.open('POST', this.url, !!async); // add custom headers Object.keys(self.customHeaders).forEach(function(prop) { xreq.setRequestHeader(prop, self.customHeaders[prop]); }); if (xreq.setRequestHeader) { xreq.setRequestHeader('Accept', 'application/vnd.apache.thrift.json; charset=utf-8'); xreq.setRequestHeader('Content-Type', 'application/vnd.apache.thrift.json; charset=utf-8'); } xreq.send(this.send_buf); if (async && callback) { return; } if (xreq.readyState != 4) { throw 'encountered an unknown ajax ready state: ' + xreq.readyState; } if (xreq.status != 200) { throw 'encountered a unknown request status: ' + xreq.status; } this.recv_buf = xreq.responseText; this.recv_buf_sz = this.recv_buf.length; this.wpos = this.recv_buf.length; this.rpos = 0; }, /** * Creates a jQuery XHR object to be used for a Thrift server call. * @param {object} client - The Thrift Service client object generated by the IDL compiler. * @param {object} postData - The message to send to the server. * @param {function} args - The original call arguments with the success call back at the end. * @param {function} recv_method - The Thrift Service Client receive method for the call. * @returns {object} A new jQuery XHR object. * @throws {string} If the jQuery version is prior to 1.5 or if jQuery is not found. */ jqRequest: function(client, postData, args, recv_method) { if (typeof jQuery === 'undefined' || typeof jQuery.Deferred === 'undefined') { throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests'; } var thriftTransport = this; var jqXHR = jQuery.ajax({ url: this.url, data: postData, type: 'POST', cache: false, contentType: 'application/vnd.apache.thrift.json; charset=utf-8', dataType: 'text thrift', converters: { 'text thrift' : function(responseData) { thriftTransport.setRecvBuffer(responseData); var value = recv_method.call(client); return value; } }, context: client, success: jQuery.makeArray(args).pop(), beforeSend: function (xreq) { Object.keys(thriftTransport.customHeaders).forEach(function (prop) { xreq.setRequestHeader(prop, thriftTransport.customHeaders[prop]); }); } }); return jqXHR; }, /** * Sets the buffer to provide the protocol when deserializing. * @param {string} buf - The buffer to supply the protocol. */ setRecvBuffer: function(buf) { this.recv_buf = buf; this.recv_buf_sz = this.recv_buf.length; this.wpos = this.recv_buf.length; this.rpos = 0; }, /** * Returns true if the transport is open, XHR always returns true. * @readonly * @returns {boolean} Always True. */ isOpen: function() { return true; }, /** * Opens the transport connection, with XHR this is a nop. */ open: function() {}, /** * Closes the transport connection, with XHR this is a nop. */ close: function() {}, /** * Returns the specified number of characters from the response * buffer. * @param {number} len - The number of characters to return. * @returns {string} Characters sent by the server. */ read: function(len) { var avail = this.wpos - this.rpos; if (avail === 0) { return ''; } var give = len; if (avail < len) { give = avail; } var ret = this.read_buf.substr(this.rpos, give); this.rpos += give; //clear buf when complete? return ret; }, /** * Returns the entire response buffer. * @returns {string} Characters sent by the server. */ readAll: function() { return this.recv_buf; }, /** * Sets the send buffer to buf. * @param {string} buf - The buffer to send. */ write: function(buf) { this.send_buf = buf; }, /** * Returns the send buffer. * @readonly * @returns {string} The send buffer. */ getSendBuffer: function() { return this.send_buf; } }; /** * Constructor Function for the WebSocket transport. * @constructor * @param {string} [url] - The URL to connect to. * @classdesc The Apache Thrift Transport layer performs byte level I/O * between RPC clients and servers. The JavaScript TWebSocketTransport object * uses the WebSocket protocol. Target servers must implement WebSocket. * (see: node.js example server_http.js). * @example * var transport = new Thrift.TWebSocketTransport("http://localhost:8585"); */ Thrift.TWebSocketTransport = function(url) { this.__reset(url); }; Thrift.TWebSocketTransport.prototype = { __reset: function(url) { this.url = url; //Where to connect this.socket = null; //The web socket this.callbacks = []; //Pending callbacks this.send_pending = []; //Buffers/Callback pairs waiting to be sent this.send_buf = ''; //Outbound data, immutable until sent this.recv_buf = ''; //Inbound data this.rb_wpos = 0; //Network write position in receive buffer this.rb_rpos = 0; //Client read position in receive buffer }, /** * Sends the current WS request and registers callback. The async * parameter is ignored (WS flush is always async) and the callback * function parameter is required. * @param {object} async - Ignored. * @param {object} callback - The client completion callback. * @returns {undefined|string} Nothing (undefined) */ flush: function(async, callback) { var self = this; if (this.isOpen()) { //Send data and register a callback to invoke the client callback this.socket.send(this.send_buf); this.callbacks.push((function() { var clientCallback = callback; return function(msg) { self.setRecvBuffer(msg); if (clientCallback) { clientCallback(); } }; }())); } else { //Queue the send to go out __onOpen this.send_pending.push({ buf: this.send_buf, cb: callback }); } }, __onOpen: function() { var self = this; if (this.send_pending.length > 0) { //If the user made calls before the connection was fully //open, send them now this.send_pending.forEach(function(elem) { self.socket.send(elem.buf); self.callbacks.push((function() { var clientCallback = elem.cb; return function(msg) { self.setRecvBuffer(msg); clientCallback(); }; }())); }); this.send_pending = []; } }, __onClose: function(evt) { this.__reset(this.url); }, __onMessage: function(evt) { if (this.callbacks.length) { this.callbacks.shift()(evt.data); } }, __onError: function(evt) { console.log('Thrift WebSocket Error: ' + evt.toString()); this.socket.close(); }, /** * Sets the buffer to use when receiving server responses. * @param {string} buf - The buffer to receive server responses. */ setRecvBuffer: function(buf) { this.recv_buf = buf; this.recv_buf_sz = this.recv_buf.length; this.wpos = this.recv_buf.length; this.rpos = 0; }, /** * Returns true if the transport is open * @readonly * @returns {boolean} */ isOpen: function() { return this.socket && this.socket.readyState == this.socket.OPEN; }, /** * Opens the transport connection */ open: function() { //If OPEN/CONNECTING/CLOSING ignore additional opens if (this.socket && this.socket.readyState != this.socket.CLOSED) { return; } //If there is no socket or the socket is closed: this.socket = new WebSocket(this.url); this.socket.onopen = this.__onOpen.bind(this); this.socket.onmessage = this.__onMessage.bind(this); this.socket.onerror = this.__onError.bind(this); this.socket.onclose = this.__onClose.bind(this); }, /** * Closes the transport connection */ close: function() { this.socket.close(); }, /** * Returns the specified number of characters from the response * buffer. * @param {number} len - The number of characters to return. * @returns {string} Characters sent by the server. */ read: function(len) { var avail = this.wpos - this.rpos; if (avail === 0) { return ''; } var give = len; if (avail < len) { give = avail; } var ret = this.read_buf.substr(this.rpos, give); this.rpos += give; //clear buf when complete? return ret; }, /** * Returns the entire response buffer. * @returns {string} Characters sent by the server. */ readAll: function() { return this.recv_buf; }, /** * Sets the send buffer to buf. * @param {string} buf - The buffer to send. */ write: function(buf) { this.send_buf = buf; }, /** * Returns the send buffer. * @readonly * @returns {string} The send buffer. */ getSendBuffer: function() { return this.send_buf; } }; /** * Initializes a Thrift JSON protocol instance. * @constructor * @param {Thrift.Transport} transport - The transport to serialize to/from. * @classdesc Apache Thrift Protocols perform serialization which enables cross * language RPC. The Protocol type is the JavaScript browser implementation * of the Apache Thrift TJSONProtocol. * @example * var protocol = new Thrift.Protocol(transport); */ Thrift.TJSONProtocol = Thrift.Protocol = function(transport) { this.tstack = []; this.tpos = []; this.transport = transport; }; /** * Thrift IDL type Id to string mapping. * @readonly * @see {@link Thrift.Type} */ Thrift.Protocol.Type = {}; Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"'; Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"'; Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"'; Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"'; Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"'; Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"'; Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"'; Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"'; Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"'; Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"'; Thrift.Protocol.Type[Thrift.Type.SET] = '"set"'; /** * Thrift IDL type string to Id mapping. * @readonly * @see {@link Thrift.Type} */ Thrift.Protocol.RType = {}; Thrift.Protocol.RType.tf = Thrift.Type.BOOL; Thrift.Protocol.RType.i8 = Thrift.Type.BYTE; Thrift.Protocol.RType.i16 = Thrift.Type.I16; Thrift.Protocol.RType.i32 = Thrift.Type.I32; Thrift.Protocol.RType.i64 = Thrift.Type.I64; Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE; Thrift.Protocol.RType.rec = Thrift.Type.STRUCT; Thrift.Protocol.RType.str = Thrift.Type.STRING; Thrift.Protocol.RType.map = Thrift.Type.MAP; Thrift.Protocol.RType.lst = Thrift.Type.LIST; Thrift.Protocol.RType.set = Thrift.Type.SET; /** * The TJSONProtocol version number. * @readonly * @const {number} Version * @memberof Thrift.Protocol */ Thrift.Protocol.Version = 1; Thrift.Protocol.prototype = { /** * Returns the underlying transport. * @readonly * @returns {Thrift.Transport} The underlying transport. */ getTransport: function() { return this.transport; }, /** * Serializes the beginning of a Thrift RPC message. * @param {string} name - The service method to call. * @param {Thrift.MessageType} messageType - The type of method call. * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). */ writeMessageBegin: function(name, messageType, seqid) { this.tstack = []; this.tpos = []; this.tstack.push([Thrift.Protocol.Version, '"' + name + '"', messageType, seqid]); }, /** * Serializes the end of a Thrift RPC message. */ writeMessageEnd: function() { var obj = this.tstack.pop(); this.wobj = this.tstack.pop(); this.wobj.push(obj); this.wbuf = '[' + this.wobj.join(',') + ']'; this.transport.write(this.wbuf); }, /** * Serializes the beginning of a struct. * @param {string} name - The name of the struct. */ writeStructBegin: function(name) { this.tpos.push(this.tstack.length); this.tstack.push({}); }, /** * Serializes the end of a struct. */ writeStructEnd: function() { var p = this.tpos.pop(); var struct = this.tstack[p]; var str = '{'; var first = true; for (var key in struct) { if (first) { first = false; } else { str += ','; } str += key + ':' + struct[key]; } str += '}'; this.tstack[p] = str; }, /** * Serializes the beginning of a struct field. * @param {string} name - The name of the field. * @param {Thrift.Protocol.Type} fieldType - The data type of the field. * @param {number} fieldId - The field's unique identifier. */ writeFieldBegin: function(name, fieldType, fieldId) { this.tpos.push(this.tstack.length); this.tstack.push({ 'fieldId': '"' + fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType] }); }, /** * Serializes the end of a field. */ writeFieldEnd: function() { var value = this.tstack.pop(); var fieldInfo = this.tstack.pop(); this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + fieldInfo.fieldType + ':' + value + '}'; this.tpos.pop(); }, /** * Serializes the end of the set of fields for a struct. */ writeFieldStop: function() { //na }, /** * Serializes the beginning of a map collection. * @param {Thrift.Type} keyType - The data type of the key. * @param {Thrift.Type} valType - The data type of the value. * @param {number} [size] - The number of elements in the map (ignored). */ writeMapBegin: function(keyType, valType, size) { this.tpos.push(this.tstack.length); this.tstack.push([Thrift.Protocol.Type[keyType], Thrift.Protocol.Type[valType], 0]); }, /** * Serializes the end of a map. */ writeMapEnd: function() { var p = this.tpos.pop(); if (p == this.tstack.length) { return; } if ((this.tstack.length - p - 1) % 2 !== 0) { this.tstack.push(''); } var size = (this.tstack.length - p - 1) / 2; this.tstack[p][this.tstack[p].length - 1] = size; var map = '}'; var first = true; while (this.tstack.length > p + 1) { var v = this.tstack.pop(); var k = this.tstack.pop(); if (first) { first = false; } else { map = ',' + map; } if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings map = k + ':' + v + map; } map = '{' + map; this.tstack[p].push(map); this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; }, /** * Serializes the beginning of a list collection. * @param {Thrift.Type} elemType - The data type of the elements. * @param {number} size - The number of elements in the list. */ writeListBegin: function(elemType, size) { this.tpos.push(this.tstack.length); this.tstack.push([Thrift.Protocol.Type[elemType], size]); }, /** * Serializes the end of a list. */ writeListEnd: function() { var p = this.tpos.pop(); while (this.tstack.length > p + 1) { var tmpVal = this.tstack[p + 1]; this.tstack.splice(p + 1, 1); this.tstack[p].push(tmpVal); } this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; }, /** * Serializes the beginning of a set collection. * @param {Thrift.Type} elemType - The data type of the elements. * @param {number} size - The number of elements in the list. */ writeSetBegin: function(elemType, size) { this.tpos.push(this.tstack.length); this.tstack.push([Thrift.Protocol.Type[elemType], size]); }, /** * Serializes the end of a set. */ writeSetEnd: function() { var p = this.tpos.pop(); while (this.tstack.length > p + 1) { var tmpVal = this.tstack[p + 1]; this.tstack.splice(p + 1, 1); this.tstack[p].push(tmpVal); } this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; }, /** Serializes a boolean */ writeBool: function(value) { this.tstack.push(value ? 1 : 0); }, /** Serializes a number */ writeByte: function(i8) { this.tstack.push(i8); }, /** Serializes a number */ writeI16: function(i16) { this.tstack.push(i16); }, /** Serializes a number */ writeI32: function(i32) { this.tstack.push(i32); }, /** Serializes a number */ writeI64: function(i64) { if (typeof i64 === 'number') { this.tstack.push(i64); } else { this.tstack.push(Int64Util.toDecimalString(i64)); } }, /** Serializes a number */ writeDouble: function(dbl) { this.tstack.push(dbl); }, /** Serializes a string */ writeString: function(str) { // We do not encode uri components for wire transfer: if (str === null) { this.tstack.push(null); } else { // concat may be slower than building a byte buffer var escapedString = ''; for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); // a single double quote: " if (ch === '\"') { escapedString += '\\\"'; // write out as: \" } else if (ch === '\\') { // a single backslash escapedString += '\\\\'; // write out as double backslash } else if (ch === '\b') { // a single backspace: invisible escapedString += '\\b'; // write out as: \b" } else if (ch === '\f') { // a single formfeed: invisible escapedString += '\\f'; // write out as: \f" } else if (ch === '\n') { // a single newline: invisible escapedString += '\\n'; // write out as: \n" } else if (ch === '\r') { // a single return: invisible escapedString += '\\r'; // write out as: \r" } else if (ch === '\t') { // a single tab: invisible escapedString += '\\t'; // write out as: \t" } else { escapedString += ch; // Else it need not be escaped } } this.tstack.push('"' + escapedString + '"'); } }, /** Serializes a string */ writeBinary: function(binary) { var str = ''; if (typeof binary == 'string') { str = binary; } else if (binary instanceof Uint8Array) { var arr = binary; for (var i = 0; i < arr.length; ++i) { str += String.fromCharCode(arr[i]); } } else { throw new TypeError('writeBinary only accepts String or Uint8Array.'); } this.tstack.push('"' + btoa(str) + '"'); }, /** @class @name AnonReadMessageBeginReturn @property {string} fname - The name of the service method. @property {Thrift.MessageType} mtype - The type of message call. @property {number} rseqid - The sequence number of the message (0 in Thrift RPC). */ /** * Deserializes the beginning of a message. * @returns {AnonReadMessageBeginReturn} */ readMessageBegin: function() { this.rstack = []; this.rpos = []; received = this.transport.readAll(); if (typeof JSONInt64 !== 'undefined' && typeof JSONInt64.parse === 'function') { this.robj = JSONInt64.parse(received); } else if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') { this.robj = JSON.parse(received); } else if (typeof jQuery !== 'undefined') { this.robj = jQuery.parseJSON(received); } else { this.robj = eval(received); } var r = {}; var version = this.robj.shift(); if (version != Thrift.Protocol.Version) { throw 'Wrong thrift protocol version: ' + version; } r.fname = this.robj.shift(); r.mtype = this.robj.shift(); r.rseqid = this.robj.shift(); //get to the main obj this.rstack.push(this.robj.shift()); return r; }, /** Deserializes the end of a message. */ readMessageEnd: function() { }, /** * Deserializes the beginning of a struct. * @param {string} [name] - The name of the struct (ignored) * @returns {object} - An object with an empty string fname property */ readStructBegin: function(name) { var r = {}; r.fname = ''; //incase this is an array of structs if (this.rstack[this.rstack.length - 1] instanceof Array) { this.rstack.push(this.rstack[this.rstack.length - 1].shift()); } return r; }, /** Deserializes the end of a struct. */ readStructEnd: function() { if (this.rstack[this.rstack.length - 2] instanceof Array) { this.rstack.pop(); } }, /** @class @name AnonReadFieldBeginReturn @property {string} fname - The name of the field (always ''). @property {Thrift.Type} ftype - The data type of the field. @property {number} fid - The unique identifier of the field. */ /** * Deserializes the beginning of a field. * @returns {AnonReadFieldBeginReturn} */ readFieldBegin: function() { var r = {}; var fid = -1; var ftype = Thrift.Type.STOP; //get a fieldId for (var f in (this.rstack[this.rstack.length - 1])) { if (f === null) { continue; } fid = parseInt(f, 10); this.rpos.push(this.rstack.length); var field = this.rstack[this.rstack.length - 1][fid]; //remove so we don't see it again delete this.rstack[this.rstack.length - 1][fid]; this.rstack.push(field); break; } if (fid != -1) { //should only be 1 of these but this is the only //way to match a key for (var i in (this.rstack[this.rstack.length - 1])) { if (Thrift.Protocol.RType[i] === null) { continue; } ftype = Thrift.Protocol.RType[i]; this.rstack[this.rstack.length - 1] = this.rstack[this.rstack.length - 1][i]; } } r.fname = ''; r.ftype = ftype; r.fid = fid; return r; }, /** Deserializes the end of a field. */ readFieldEnd: function() { var pos = this.rpos.pop(); //get back to the right place in the stack while (this.rstack.length > pos) { this.rstack.pop(); } }, /** @class @name AnonReadMapBeginReturn @property {Thrift.Type} ktype - The data type of the key. @property {Thrift.Type} vtype - The data type of the value. @property {number} size - The number of elements in the map. */ /** * Deserializes the beginning of a map. * @returns {AnonReadMapBeginReturn} */ readMapBegin: function() { var map = this.rstack.pop(); var first = map.shift(); if (first instanceof Array) { this.rstack.push(map); map = first; first = map.shift(); } var r = {}; r.ktype = Thrift.Protocol.RType[first]; r.vtype = Thrift.Protocol.RType[map.shift()]; r.size = map.shift(); this.rpos.push(this.rstack.length); this.rstack.push(map.shift()); return r; }, /** Deserializes the end of a map. */ readMapEnd: function() { this.readFieldEnd(); }, /** @class @name AnonReadColBeginReturn @property {Thrift.Type} etype - The data type of the element. @property {number} size - The number of elements in the collection. */ /** * Deserializes the beginning of a list. * @returns {AnonReadColBeginReturn} */ readListBegin: function() { var list = this.rstack[this.rstack.length - 1]; var r = {}; r.etype = Thrift.Protocol.RType[list.shift()]; r.size = list.shift(); this.rpos.push(this.rstack.length); this.rstack.push(list.shift()); return r; }, /** Deserializes the end of a list. */ readListEnd: function() { var pos = this.rpos.pop() - 2; var st = this.rstack; st.pop(); if (st instanceof Array && st.length > pos && st[pos].length > 0) { st.push(st[pos].shift()); } }, /** * Deserializes the beginning of a set. * @returns {AnonReadColBeginReturn} */ readSetBegin: function(elemType, size) { return this.readListBegin(elemType, size); }, /** Deserializes the end of a set. */ readSetEnd: function() { return this.readListEnd(); }, /** Returns an object with a value property set to * False unless the next number in the protocol buffer * is 1, in which case the value property is True */ readBool: function() { var r = this.readI32(); if (r !== null && r.value == '1') { r.value = true; } else { r.value = false; } return r; }, /** Returns the an object with a value property set to the next value found in the protocol buffer */ readByte: function() { return this.readI32(); }, /** Returns the an object with a value property set to the next value found in the protocol buffer */ readI16: function() { return this.readI32(); }, /** Returns the an object with a value property set to the next value found in the protocol buffer */ readI32: function(f) { if (f === undefined) { f = this.rstack[this.rstack.length - 1]; } var r = {}; if (f instanceof Array) { if (f.length === 0) { r.value = undefined; } else { if (!f.isReversed) { f.reverse(); f.isReversed = true; } r.value = f.pop(); } } else if (f instanceof Object) { for (var i in f) { if (i === null) { continue; } this.rstack.push(f[i]); delete f[i]; r.value = i; break; } } else { r.value = f; this.rstack.pop(); } return r; }, /** Returns the an object with a value property set to the next value found in the protocol buffer */ readI64: function(f) { if (f === undefined) { f = this.rstack[this.rstack.length - 1]; } var r = {}; if (f instanceof Array) { if (f.length === 0) { r.value = undefined; } else { if (!f.isReversed) { f.reverse(); f.isReversed = true; } r.value = f.pop(); } } else if (f instanceof Object) { var int64Object = true; var objectKeys = Object.keys(f).sort(); var int64Keys = ['buffer', 'offset']; if (objectKeys.length !== int64Keys.length) { int64Object = false; } for (var it=0; int64Object && it < objectKeys.length; ++it) { if (objectKeys[it] !== int64Keys[it]) { int64Object = false; } } if (int64Object) { r.value = f; } else { for (var i in f) { if (i === null) { continue; } this.rstack.push(f[i]); delete f[i]; r.value = i; break; } } } else { r.value = f; this.rstack.pop(); } return r; }, /** Returns the an object with a value property set to the next value found in the protocol buffer */ readDouble: function() { return this.readI32(); }, /** Returns the an object with a value property set to the next value found in the protocol buffer */ readString: function() { var r = this.readI32(); return r; }, /** Returns the an object with a value property set to the next value found in the protocol buffer */ readBinary: function() { var r = this.readI32(); r.value = atob(r.value); return r; }, /** * Method to arbitrarily skip over data */ skip: function(type) { var ret, i; switch (type) { case Thrift.Type.BOOL: return this.readBool(); case Thrift.Type.BYTE: return this.readByte(); case Thrift.Type.I16: return this.readI16(); case Thrift.Type.I32: return this.readI32(); case Thrift.Type.I64: return this.readI64(); case Thrift.Type.DOUBLE: return this.readDouble(); case Thrift.Type.STRING: return this.readString(); case Thrift.Type.STRUCT: this.readStructBegin(); while (true) { ret = this.readFieldBegin(); if (ret.ftype == Thrift.Type.STOP) { break; } this.skip(ret.ftype); this.readFieldEnd(); } this.readStructEnd(); return null; case Thrift.Type.MAP: ret = this.readMapBegin(); for (i = 0; i < ret.size; i++) { if (i > 0) { if (this.rstack.length > this.rpos[this.rpos.length - 1] + 1) { this.rstack.pop(); } } this.skip(ret.ktype); this.skip(ret.vtype); } this.readMapEnd(); return null; case Thrift.Type.SET: ret = this.readSetBegin(); for (i = 0; i < ret.size; i++) { this.skip(ret.etype); } this.readSetEnd(); return null; case Thrift.Type.LIST: ret = this.readListBegin(); for (i = 0; i < ret.size; i++) { this.skip(ret.etype); } this.readListEnd(); return null; default: throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA); } } }; /** * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol * @constructor */ Thrift.MultiplexProtocol = function(srvName, trans, strictRead, strictWrite) { Thrift.Protocol.call(this, trans, strictRead, strictWrite); this.serviceName = srvName; }; Thrift.inherits(Thrift.MultiplexProtocol, Thrift.Protocol, 'multiplexProtocol'); /** Override writeMessageBegin method of prototype*/ Thrift.MultiplexProtocol.prototype.writeMessageBegin = function(name, type, seqid) { if (type === Thrift.MessageType.CALL || type === Thrift.MessageType.ONEWAY) { Thrift.Protocol.prototype.writeMessageBegin.call(this, this.serviceName + ':' + name, type, seqid); } else { Thrift.Protocol.prototype.writeMessageBegin.call(this, name, type, seqid); } }; Thrift.Multiplexer = function() { this.seqid = 0; }; /** Instantiates a multiplexed client for a specific service * @constructor * @param {String} serviceName - The transport to serialize to/from. * @param {Thrift.ServiceClient} SCl - The Service Client Class * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port * @example * var mp = new Thrift.Multiplexer(); * var transport = new Thrift.Transport("http://localhost:9090/foo.thrift"); * var protocol = new Thrift.Protocol(transport); * var client = mp.createClient('AuthService', AuthServiceClient, transport); */ Thrift.Multiplexer.prototype.createClient = function(serviceName, SCl, transport) { if (SCl.Client) { SCl = SCl.Client; } var self = this; SCl.prototype.new_seqid = function() { self.seqid += 1; return self.seqid; }; var client = new SCl(new Thrift.MultiplexProtocol(serviceName, transport)); return client; }; var copyList, copyMap; copyList = function(lst, types) { if (!lst) {return lst; } var type; if (types.shift === undefined) { type = types; } else { type = types[0]; } var Type = type; var len = lst.length, result = [], i, val; for (i = 0; i < len; i++) { val = lst[i]; if (type === null) { result.push(val); } else if (type === copyMap || type === copyList) { result.push(type(val, types.slice(1))); } else { result.push(new Type(val)); } } return result; }; copyMap = function(obj, types) { if (!obj) {return obj; } var type; if (types.shift === undefined) { type = types; } else { type = types[0]; } var Type = type; var result = {}, val; for (var prop in obj) { if (obj.hasOwnProperty(prop)) { val = obj[prop]; if (type === null) { result[prop] = val; } else if (type === copyMap || type === copyList) { result[prop] = type(val, types.slice(1)); } else { result[prop] = new Type(val); } } } return result; }; Thrift.copyMap = copyMap; Thrift.copyList = copyList; thrift-0.16.0/lib/js/test/000077500000000000000000000000001420101504100152235ustar00rootroot00000000000000thrift-0.16.0/lib/js/test/Makefile.am000077500000000000000000000017471420101504100172730ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # export CLASSPATH # Make sure this doesn't fail if ant is not configured. clean-local: ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ $$ANT $(ANT_FLAGS) clean check-local: all $(ANT) $(ANT_FLAGS) test thrift-0.16.0/lib/js/test/README.md000066400000000000000000000053271420101504100165110ustar00rootroot00000000000000Thrift Javascript Library ========================= This browser based Apache Thrift implementation supports RPC clients using the JSON protocol over Http[s] with XHR and WebSocket. License ------- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Test Servers ------------ drwxr-xr-x 2 randy randy 4096 Feb 8 15:44 sec -rw-r--r-- 1 randy randy 2183 Feb 9 04:01 server_http.js -rw-r--r-- 1 randy randy 2386 Feb 9 05:39 server_https.js server_http.js is a Node.js web server which support the standard Apache Thrift test suite (thrift/test/ThriftTest.thrift). The server supports Apache Thrift XHR and WebSocket clients. server_https.js is the same but uses SSL/TLS. The server key and cert are pulled from the thrift/test/keys folder. Both of these servers support WebSocket (the http: supports ws:, and the https: support wss:). To run the client test with the Java test server use: $ make check (requires the Apache Thrift Java branch and make check must have been run in thrift/lib/java previously). To run the client tests with the Node servers run the grunt build in the parent js directory (see README there). Test Clients ------------ -rw-r--r-- 1 randy randy 13558 Feb 9 07:18 test-async.js -rw-r--r-- 1 randy randy 5724 Feb 9 03:45 test_handler.js -rwxr-xr-x 1 randy randy 2719 Feb 9 06:04 test.html -rw-r--r-- 1 randy randy 4611 Feb 9 06:05 test-jq.js -rwxr-xr-x 1 randy randy 12153 Feb 9 06:04 test.js -rw-r--r-- 1 randy randy 2593 Feb 9 06:16 test-nojq.html -rw-r--r-- 1 randy randy 1450 Feb 9 06:14 test-nojq.js -rw-r--r-- 1 randy randy 2847 Feb 9 06:31 testws.html There are three html test driver files, all of which are QUnit based. test.html tests the Apache Thrift jQuery generated code (thrift -gen js:jquery). The test-nojq.html runs almost identical tests against normal JavaScript builds (thrift -gen js). Both of the previous tests use the XHR transport. The testws.html runs similar tests using the WebSocket transport. The test*.js files are loaded by the html drivers and contain the actual Apache Thrift tests. thrift-0.16.0/lib/js/test/build.properties000066400000000000000000000003641420101504100204430ustar00rootroot00000000000000# Maven Ant tasks Jar details mvn.ant.task.version=2.1.3 mvn.repo=https://repo1.maven.org/maven2 mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version} mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar thrift-0.16.0/lib/js/test/build.xml000077500000000000000000000231221420101504100170470ustar00rootroot00000000000000 Java Script Test based on Thrift Java Library You need libthrift*.jar and libthrift*test.jar located at ${thrift.java.dir}/build/libs Did you compile Thrift Java library and its test suite by "make check"? Thrift compiler is missing ! check if Xvfb is available: check if phantomjs is available: Running Unit Tests with headless browser! check if gjslint is available: thrift-0.16.0/lib/js/test/deep-constructor.test.js000066400000000000000000000124231420101504100220410ustar00rootroot00000000000000function serialize(data) { const transport = new Thrift.Transport('/service'); const protocol = new Thrift.Protocol(transport); protocol.writeMessageBegin('', 0, 0); data.write(protocol); protocol.writeMessageEnd(); return transport.send_buf; } function deserialize(serialized, type) { const transport = new Thrift.Transport('/service'); transport.setRecvBuffer(serialized); const protocol = new Thrift.Protocol(transport); protocol.readMessageBegin(); const data = new type(); data.read(protocol); protocol.readMessageEnd(); return data; } function createThriftObj() { return new Complex({ struct_field: new Simple({value: 'a'}), struct_list_field: [ new Simple({value: 'b'}), new Simple({value: 'c'}) ], struct_set_field: [ new Simple({value: 'd'}), new Simple({value: 'e'}) ], struct_map_field: { A: new Simple({value: 'f'}), B: new Simple({value: 'g'}) }, struct_nested_containers_field: [ [ { C: [ new Simple({value: 'h'}), new Simple({value: 'i'}) ] } ] ], struct_nested_containers_field2: { D: [ { DA: new Simple({value: 'j'}) }, { DB: new Simple({value: 'k'}) } ] }, list_of_list_field: [ ['one', 'two'], ['three', 'four'], ['five', 'six'] ] } ); } function createJsObj() { return { struct_field: {value: 'a'}, struct_list_field: [ {value: 'b'}, {value: 'c'} ], struct_set_field: [ {value: 'd'}, {value: 'e'} ], struct_map_field: { A: {value: 'f'}, B: {value: 'g'} }, struct_nested_containers_field: [ [ { C: [ {value: 'h'}, {value: 'i'} ] } ] ], struct_nested_containers_field2: { D: [ { DA: {value: 'j'} }, { DB: {value: 'k'} } ] }, list_of_list_field: [ ['one', 'two'], ['three', 'four'], ['five', 'six'] ] }; } function assertValues(obj, assert) { assert.equal(obj.struct_field.value, 'a'); assert.equal(obj.struct_list_field[0].value, 'b'); assert.equal(obj.struct_list_field[1].value, 'c'); assert.equal(obj.struct_set_field[0].value, 'd'); assert.equal(obj.struct_set_field[1].value, 'e'); assert.equal(obj.struct_map_field.A.value, 'f'); assert.equal(obj.struct_map_field.B.value, 'g'); assert.equal(obj.struct_nested_containers_field[0][0].C[0].value, 'h'); assert.equal(obj.struct_nested_containers_field[0][0].C[1].value, 'i'); assert.equal(obj.struct_nested_containers_field2.D[0].DA.value, 'j'); assert.equal(obj.struct_nested_containers_field2.D[1].DB.value, 'k'); assert.equal(obj.list_of_list_field[0][0], 'one'); assert.equal(obj.list_of_list_field[0][1], 'two'); assert.equal(obj.list_of_list_field[1][0], 'three'); assert.equal(obj.list_of_list_field[1][1], 'four'); assert.equal(obj.list_of_list_field[2][0], 'five'); assert.equal(obj.list_of_list_field[2][1], 'six'); } const cases = { 'Serialize/deserialize simple struct should return equal object': function(assert) { const tObj = new Simple({value: 'a'}); const received = deserialize(serialize(tObj), Simple); assert.ok(tObj !== received); assert.deepEqual(received, tObj); }, 'Serialize/deserialize should return equal object': function(assert) { const tObj = createThriftObj(); const received = deserialize(serialize(tObj), Complex); assert.ok(tObj !== received); assert.deepEqual(received, tObj); }, 'Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects': function(assert) { const tObj1 = createThriftObj(); const tObj2 = new Complex(createJsObj()); assertValues(tObj2, assert); assert.equal(serialize(tObj2), serialize(tObj1)); }, 'Modifications to args object should not affect constructed Thrift object': function(assert) { const args = createJsObj(); assertValues(args, assert); const tObj = new Complex(args); assertValues(tObj, assert); args.struct_field.value = 'ZZZ'; args.struct_list_field[0].value = 'ZZZ'; args.struct_list_field[1].value = 'ZZZ'; args.struct_set_field[0].value = 'ZZZ'; args.struct_set_field[1].value = 'ZZZ'; args.struct_map_field.A.value = 'ZZZ'; args.struct_map_field.B.value = 'ZZZ'; args.struct_nested_containers_field[0][0].C[0] = 'ZZZ'; args.struct_nested_containers_field[0][0].C[1] = 'ZZZ'; args.struct_nested_containers_field2.D[0].DA = 'ZZZ'; args.struct_nested_containers_field2.D[0].DB = 'ZZZ'; assertValues(tObj, assert); }, 'nulls are ok': function(assert) { const tObj = new Complex({ struct_field: null, struct_list_field: null, struct_set_field: null, struct_map_field: null, struct_nested_containers_field: null, struct_nested_containers_field2: null }); const received = deserialize(serialize(tObj), Complex); assert.ok(tObj !== received); assert.deepEqual(tObj, received); } }; Object.keys(cases).forEach(function(caseName) { QUnit.test(caseName, cases[caseName]); }); thrift-0.16.0/lib/js/test/jsTestDriver.conf000077500000000000000000000006351420101504100205310ustar00rootroot00000000000000server: http://localhost:9876 load: # Qunit adapter - build/js/lib/equiv.js - build/js/lib/QUnitAdapter.js # dependencies - build/js/lib/jquery.js - build/js/thrift.js - gen-js/DoubleConstantsTest_constants.js - gen-js/ThriftTest_types.js - gen-js/ThriftTest.js # the test suite - test.js # redirect to the Java based Thrift testserver proxy: - {matcher: "*", server: " http://localhost:8088"} thrift-0.16.0/lib/js/test/phantom-client.js000066400000000000000000000327021420101504100205070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ (function() { 'use strict'; // Rudimentary test helper functions // TODO: Return error code based on kind of errors rather than throw var ok = function(t, msg) { if (!t) { console.log('*** FAILED ***'); throw new Error(msg); } }; var equal = function(a, b) { if (a !== b) { console.log('*** FAILED ***'); throw new Error(); } }; var test = function(name, f) { console.log('TEST : ' + name); f(); console.log('OK\n'); }; var parseArgs = function(args) { var skips = [ '--transport=http', '--protocol=json' ]; var opts = { port: '9090' // protocol: 'json', }; var keys = {}; for (var key in opts) { keys['--' + key + '='] = key; } for (var i in args) { var arg = args[i]; if (skips.indexOf(arg) != -1) { continue; } var hit = false; for (var k in keys) { if (arg.slice(0, k.length) === k) { opts[keys[k]] = arg.slice(k.length); hit = true; break; } } if (!hit) { throw new Error('Unknown argument: ' + arg); } } opts.port = parseInt(opts.port, 10); if (!opts.port || opts.port < 1 || opts.port > 65535) { throw new Error('Invalid port number'); } return opts; }; var execute = function() { console.log('### Apache Thrift Javascript standalone test client'); console.log('------------------------------------------------------------'); phantom.page.injectJs('src/thrift.js'); phantom.page.injectJs('test/gen-js/ThriftTest_types.js'); phantom.page.injectJs('test/gen-js/ThriftTest.js'); var system = require('system'); var opts = parseArgs(system.args.slice(1)); var port = opts.port; var transport = new Thrift.Transport('http://localhost:' + port + '/service'); var protocol = new Thrift.Protocol(transport); var client = new ThriftTest.ThriftTestClient(protocol); // TODO: Remove duplicate code with test.js. // all Languages in UTF-8 var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; function checkRecursively(map1, map2) { if (typeof map1 !== 'function' && typeof map2 !== 'function') { if (!map1 || typeof map1 !== 'object') { equal(map1, map2); } else { for (var key in map1) { checkRecursively(map1[key], map2[key]); } } } } test('Void', function() { equal(client.testVoid(), undefined); }); test('Binary (String)', function() { var binary = ''; for (var v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } equal(client.testBinary(binary), binary); }); test('Binary (Uint8Array)', function() { var binary = ''; for (var v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } var arr = new Uint8Array(binary.length); for (var i = 0; i < binary.length; ++i) { arr[i] = binary[i].charCodeAt(); } equal(client.testBinary(arr), binary); }); test('String', function() { equal(client.testString(''), ''); equal(client.testString(stringTest), stringTest); var specialCharacters = 'quote: \" backslash:' + ' forwardslash-escaped: \/ ' + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + ' now-all-of-them-together: "\\\/\b\n\r\t' + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; equal(client.testString(specialCharacters), specialCharacters); }); test('Double', function() { equal(client.testDouble(0), 0); equal(client.testDouble(-1), -1); equal(client.testDouble(3.14), 3.14); equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60)); }); test('Bool', function() { equal(client.testBool(true), true); equal(client.testBool(false), false); }); test('I8', function() { equal(client.testByte(0), 0); equal(client.testByte(0x01), 0x01); }); test('I32', function() { equal(client.testI32(0), 0); equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30)); equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30)); }); test('I64', function() { equal(client.testI64(0), 0); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately equal(client.testI64(Math.pow(2, 52)), Math.pow(2, 52)); equal(client.testI64(-Math.pow(2, 52)), -Math.pow(2, 52)); }); test('Struct', function() { var structTestInput = new ThriftTest.Xtruct(); structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately structTestInput.i64_thing = Math.pow(2, 52); var structTestOutput = client.testStruct(structTestInput); equal(structTestOutput.string_thing, structTestInput.string_thing); equal(structTestOutput.byte_thing, structTestInput.byte_thing); equal(structTestOutput.i32_thing, structTestInput.i32_thing); equal(structTestOutput.i64_thing, structTestInput.i64_thing); equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput)); }); test('Nest', function() { var xtrTestInput = new ThriftTest.Xtruct(); xtrTestInput.string_thing = 'worked'; xtrTestInput.byte_thing = 0x01; xtrTestInput.i32_thing = Math.pow(2, 30); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately xtrTestInput.i64_thing = Math.pow(2, 52); var nestTestInput = new ThriftTest.Xtruct2(); nestTestInput.byte_thing = 0x02; nestTestInput.struct_thing = xtrTestInput; nestTestInput.i32_thing = Math.pow(2, 15); var nestTestOutput = client.testNest(nestTestInput); equal(nestTestOutput.byte_thing, nestTestInput.byte_thing); equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); equal(nestTestOutput.i32_thing, nestTestInput.i32_thing); equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput)); }); test('Map', function() { var mapTestInput = {7: 77, 8: 88, 9: 99}; var mapTestOutput = client.testMap(mapTestInput); for (var key in mapTestOutput) { equal(mapTestOutput[key], mapTestInput[key]); } }); test('StringMap', function() { var mapTestInput = { 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', 'longValue': stringTest, stringTest: 'long key' }; var mapTestOutput = client.testStringMap(mapTestInput); for (var key in mapTestOutput) { equal(mapTestOutput[key], mapTestInput[key]); } }); test('Set', function() { var setTestInput = [1, 2, 3]; ok(client.testSet(setTestInput), setTestInput); }); test('List', function() { var listTestInput = [1, 2, 3]; ok(client.testList(listTestInput), listTestInput); }); test('Enum', function() { equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE); }); test('TypeDef', function() { equal(client.testTypedef(69), 69); }); test('Skip', function() { var structTestInput = new ThriftTest.Xtruct(); var modifiedClient = new ThriftTest.ThriftTestClient(protocol); modifiedClient.recv_testStruct = function() { var input = modifiedClient.input; var xtruct3 = new ThriftTest.Xtruct3(); input.readMessageBegin(); input.readStructBegin(); // read Xtruct data with Xtruct3 input.readFieldBegin(); xtruct3.read(input); input.readFieldEnd(); // read Thrift.Type.STOP message input.readFieldBegin(); input.readFieldEnd(); input.readStructEnd(); input.readMessageEnd(); return xtruct3; }; structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); structTestInput.i64_thing = Math.pow(2, 52); var structTestOutput = modifiedClient.testStruct(structTestInput); equal(structTestOutput instanceof ThriftTest.Xtruct3, true); equal(structTestOutput.string_thing, structTestInput.string_thing); equal(structTestOutput.changed, null); equal(structTestOutput.i32_thing, structTestInput.i32_thing); equal(structTestOutput.i64_thing, structTestInput.i64_thing); }); test('MapMap', function() { var mapMapTestExpectedResult = { '4': {'1': 1, '2': 2, '3': 3, '4': 4}, '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} }; var mapMapTestOutput = client.testMapMap(1); for (var key in mapMapTestOutput) { for (var key2 in mapMapTestOutput[key]) { equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]); } } checkRecursively(mapMapTestOutput, mapMapTestExpectedResult); }); test('Xception', function() { try { client.testException('Xception'); ok(false); } catch (e) { equal(e.errorCode, 1001); equal(e.message, 'Xception'); } }); test('no Exception', function() { try { client.testException('no Exception'); } catch (e) { ok(false); } }); test('TException', function() { try { client.testException('TException'); ok(false); } catch (e) { ok(ok); } }); var crazy = { 'userMap': { '5': 5, '8': 8 }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': 4 }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': 2 }] }; test('Insanity', function() { var insanity = { '1': { '2': crazy, '3': crazy }, '2': { '6': { 'userMap': null, 'xtructs': null } } }; var res = client.testInsanity(new ThriftTest.Insanity(crazy)); ok(res, JSON.stringify(res)); ok(insanity, JSON.stringify(insanity)); checkRecursively(res, insanity); }); console.log('------------------------------------------------------------'); console.log('### All tests succeeded.'); return 0; }; try { var ret = execute(); phantom.exit(ret); } catch (err) { // Catch all and exit to avoid hang. console.error(err); phantom.exit(1); } })(); thrift-0.16.0/lib/js/test/phantomjs-qunit.js000077500000000000000000000070021420101504100207240ustar00rootroot00000000000000/*jshint evil:true*/ /* This file is only used by the test suite. * * Origin: https://github.com/ariya/phantomjs/blob/master/examples/run-qunit.js * License: https://github.com/ariya/phantomjs/blob/master/LICENSE.BSD * * Inclusion into Apache products is allowed according to http://www.apache.org/legal/3party.html */ var system = require('system'); /** * Wait until the test condition is true or a timeout occurs. Useful for waiting * on a server response or for a ui change (fadeIn, etc.) to occur. * * @param testFx javascript condition that evaluates to a boolean, * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or * as a callback function. * @param onReady what to do when testFx condition is fulfilled, * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or * as a callback function. * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. */ function waitFor(testFx, onReady, timeOutMillis) { var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timout is 3s start = new Date().getTime(), condition = false, interval = setInterval(function() { if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) { // If not time-out yet and condition not yet fulfilled condition = (typeof(testFx) === 'string' ? eval(testFx) : testFx()); //< defensive code } else { if (!condition) { // If condition still not fulfilled (timeout but condition is 'false') console.log("'waitFor()' timeout"); phantom.exit(1); } else { // Condition fulfilled (timeout and/or condition is 'true') console.log("'waitFor()' finished in " + (new Date().getTime() - start) + 'ms.'); if (typeof(onReady) === 'string') { eval(onReady); } else { onReady(); //< Do what it's supposed to do once the condition is fulfilled } clearInterval(interval); //< Stop this interval } } }, 100); //< repeat check every 250ms } if (system.args.length === 1 || system.args.length > 3) { console.log('Usage: phantomjs phantomjs-qunit.js URL'); phantom.exit(1); } var page = new WebPage(); // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") page.onConsoleMessage = function(msg) { console.log(msg); }; page.open(system.args[1], function(status) { if (status !== 'success') { console.log('Unable to access network'); phantom.exit(1); } else { waitFor(function() { return page.evaluate(function() { var el = document.getElementById('qunit-testresult'); if (el && el.innerText.match('completed')) { return true; } return false; }); }, function() { var failedNum = page.evaluate(function() { var el = document.getElementById('qunit-testresult'); console.log(el.innerText); try { return el.getElementsByClassName('failed')[0].innerHTML; } catch (e) { } return 10000; }); phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0); }); } }); thrift-0.16.0/lib/js/test/server_http.js000066400000000000000000000041241420101504100201270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // This HTTP server is designed to serve the test.html browser // based JavaScript test page (which must be in the current directory). // This server also supplies the Thrift based test service, which depends // on the standard ThriftTest.thrift IDL service (which must be compiled // for Node and browser based JavaScript in ./gen-nodejs and ./gen-js // respectively). // // Using the command flag --es6, this server can be run using nodejs code built // for the es6 environment or for pre-es6 environment. // const thrift = require('../../nodejs/lib/thrift'); const es6Mode = process.argv.includes('--es6'); const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs'; const ThriftTestSvc = require(`./${genFolder}/ThriftTest.js`); const ThriftTestHandler = require('./test_handler').ThriftTestHandler; const ThriftTestSvcOpt = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: ThriftTestSvc, handler: ThriftTestHandler }; const ThriftWebServerOptions = { files: __dirname, services: { '/service': ThriftTestSvcOpt } }; const server = thrift.createWebServer(ThriftWebServerOptions); const port = es6Mode ? 8088 : 8089; server.listen(port); console.log(`Serving files from: ${__dirname}`); console.log(`Http/Thrift Server (ES6 mode ${es6Mode}) running on port: ${port}`); thrift-0.16.0/lib/js/test/server_https.js000066400000000000000000000044711420101504100203170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //This HTTP server is designed to server the test.html browser // based JavaScript test page (which must be in the current directory). // This server also supplies the Thrift based test service, which depends // on the standard ThriftTest.thrift IDL service (which must be compiled // for Node and browser based JavaScript in ./gen-nodejs and ./gen-js // respectively). The current directory must also include the browser // support libraries for test.html (jquery.js, qunit.js and qunit.css // in ./build/js/lib). const fs = require('fs'); const thrift = require('../../nodejs/lib/thrift'); const es6Mode = process.argv.includes('--es6'); const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs'; const ThriftTestSvc = require(`./${genFolder}/ThriftTest.js`); const ThriftTestHandler = require('./test_handler').ThriftTestHandler; //Setup the I/O stack options for the ThriftTest service const ThriftTestSvcOpt = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: ThriftTestSvc, handler: ThriftTestHandler }; const ThriftWebServerOptions = { files: __dirname, tls: { key: fs.readFileSync('../../../test/keys/server.key'), cert: fs.readFileSync('../../../test/keys/server.crt') }, services: { '/service': ThriftTestSvcOpt } }; const server = thrift.createWebServer(ThriftWebServerOptions); const port = es6Mode ? 8090 : 8091; server.listen(port); console.log(`Serving files from: ${__dirname}`); console.log(`Http/Thrift Server (ES6 mode ${es6Mode}) running on port: ${port}`); thrift-0.16.0/lib/js/test/src/000077500000000000000000000000001420101504100160125ustar00rootroot00000000000000thrift-0.16.0/lib/js/test/src/test/000077500000000000000000000000001420101504100167715ustar00rootroot00000000000000thrift-0.16.0/lib/js/test/src/test/Httpd.java000066400000000000000000000323351420101504100207250ustar00rootroot00000000000000/* * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package test; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.URLDecoder; import java.util.Locale; import org.apache.http.ConnectionClosedException; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpServerConnection; import org.apache.http.HttpStatus; import org.apache.http.MethodNotSupportedException; import org.apache.http.entity.ContentProducer; import org.apache.http.entity.EntityTemplate; import org.apache.http.entity.FileEntity; import org.apache.http.impl.DefaultHttpResponseFactory; import org.apache.http.impl.DefaultHttpServerConnection; import org.apache.http.impl.NoConnectionReuseStrategy; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.BasicHttpProcessor; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpProcessor; import org.apache.http.protocol.HttpRequestHandler; import org.apache.http.protocol.HttpRequestHandlerRegistry; import org.apache.http.protocol.HttpService; import org.apache.http.util.EntityUtils; import org.apache.thrift.TProcessor; import org.apache.thrift.protocol.TJSONProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TMemoryBuffer; import thrift.test.ThriftTest; import org.apache.thrift.server.ServerTestBase.TestHandler; import eu.medsea.mimeutil.detector.ExtensionMimeDetector; import eu.medsea.mimeutil.MimeUtil2; import eu.medsea.mimeutil.MimeType; import java.util.Collection; import java.util.Iterator; /** * Basic, yet fully functional and spec compliant, HTTP/1.1 file server. *

* Please note the purpose of this application is demonstrate the usage of * HttpCore APIs. It is NOT intended to demonstrate the most efficient way of * building an HTTP file server. * * */ public class Httpd { public static void main(String[] args) throws Exception { if (args.length < 1) { System.err.println("Please specify document root directory"); System.exit(1); } Thread t = new RequestListenerThread(8088, args[0]); t.setDaemon(false); t.start(); } static class HttpFileHandler implements HttpRequestHandler { private final String docRoot; public HttpFileHandler(final String docRoot) { super(); this.docRoot = docRoot; } public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException { String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH); if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) { throw new MethodNotSupportedException(method + " method not supported"); } String target = request.getRequestLine().getUri(); if (request instanceof HttpEntityEnclosingRequest && target.equals("/service")) { HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); byte[] entityContent = EntityUtils.toByteArray(entity); System.out.println("Incoming content: " + new String(entityContent)); final String output = this.thriftRequest(entityContent); System.out.println("Outgoing content: "+output); EntityTemplate body = new EntityTemplate(new ContentProducer() { public void writeTo(final OutputStream outstream) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); writer.write(output); writer.flush(); } }); body.setContentType("text/html; charset=UTF-8"); response.setEntity(body); } else { if(target.indexOf("?") != -1) { target = target.substring(1, target.indexOf("?")); } final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8")); if (!file.exists()) { response.setStatusCode(HttpStatus.SC_NOT_FOUND); EntityTemplate body = new EntityTemplate(new ContentProducer() { public void writeTo(final OutputStream outstream) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); writer.write("

"); writer.write("File "); writer.write(file.getPath()); writer.write(" not found"); writer.write("

"); writer.flush(); } }); body.setContentType("text/html; charset=UTF-8"); response.setEntity(body); System.out.println("File " + file.getPath() + " not found"); } else if (!file.canRead() || file.isDirectory()) { response.setStatusCode(HttpStatus.SC_FORBIDDEN); EntityTemplate body = new EntityTemplate(new ContentProducer() { public void writeTo(final OutputStream outstream) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); writer.write("

"); writer.write("Access denied"); writer.write("

"); writer.flush(); } }); body.setContentType("text/html; charset=UTF-8"); response.setEntity(body); System.out.println("Cannot read file " + file.getPath()); } else { String mimeType = "application/octet-stream"; MimeUtil2 mimeUtil = new MimeUtil2(); synchronized (this) { mimeUtil.registerMimeDetector(ExtensionMimeDetector.class.getName()); } Collection collection = mimeUtil.getMimeTypes(file); Iterator iterator = collection.iterator(); while(iterator.hasNext()) { MimeType mt = iterator.next(); mimeType = mt.getMediaType() + "/" + mt.getSubType(); break; } response.setStatusCode(HttpStatus.SC_OK); FileEntity body = new FileEntity(file, mimeType); response.addHeader("Content-Type", mimeType); response.setEntity(body); System.out.println("Serving file " + file.getPath()); } } } private String thriftRequest(byte[] input){ try{ //Input TMemoryBuffer inbuffer = new TMemoryBuffer(input.length); inbuffer.write(input); TProtocol inprotocol = new TJSONProtocol(inbuffer); //Output TMemoryBuffer outbuffer = new TMemoryBuffer(100); TProtocol outprotocol = new TJSONProtocol(outbuffer); TProcessor processor = new ThriftTest.Processor(new TestHandler()); processor.process(inprotocol, outprotocol); byte[] output = new byte[outbuffer.length()]; outbuffer.readAll(output, 0, output.length); return new String(output,"UTF-8"); }catch(Throwable t){ return "Error:"+t.getMessage(); } } } static class RequestListenerThread extends Thread { private final ServerSocket serversocket; private final HttpParams params; private final HttpService httpService; public RequestListenerThread(int port, final String docroot) throws IOException { this.serversocket = new ServerSocket(port); this.params = new BasicHttpParams(); this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 1000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); // Set up the HTTP protocol processor HttpProcessor httpproc = new BasicHttpProcessor(); // Set up request handlers HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); reqistry.register("*", new HttpFileHandler(docroot)); // Set up the HTTP service this.httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory()); this.httpService.setParams(this.params); this.httpService.setHandlerResolver(reqistry); } public void run() { System.out.println("Listening on port " + this.serversocket.getLocalPort()); System.out.println("Point your browser to http://localhost:8088/test/test.html"); while (!Thread.interrupted()) { try { // Set up HTTP connection Socket socket = this.serversocket.accept(); DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); System.out.println("Incoming connection from " + socket.getInetAddress()); conn.bind(socket, this.params); // Start worker thread Thread t = new WorkerThread(this.httpService, conn); t.setDaemon(true); t.start(); } catch (InterruptedIOException ex) { break; } catch (IOException e) { System.err.println("I/O error initialising connection thread: " + e.getMessage()); break; } } } } static class WorkerThread extends Thread { private final HttpService httpservice; private final HttpServerConnection conn; public WorkerThread(final HttpService httpservice, final HttpServerConnection conn) { super(); this.httpservice = httpservice; this.conn = conn; } public void run() { System.out.println("New connection thread"); HttpContext context = new BasicHttpContext(null); try { while (!Thread.interrupted() && this.conn.isOpen()) { this.httpservice.handleRequest(this.conn, context); } } catch (ConnectionClosedException ex) { System.err.println("Client closed connection"); } catch (IOException ex) { System.err.println("I/O error: " + ex.getMessage()); } catch (HttpException ex) { System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage()); } finally { try { this.conn.shutdown(); } catch (IOException ignore) { } } } } } thrift-0.16.0/lib/js/test/test-async.js000066400000000000000000000306171420101504100176620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ /* * Fully Async JavaScript test suite for ThriftTest.thrift. * These tests are designed to exercise the WebSocket transport * (which is exclusively async). * * To compile client code for this test use: * $ thrift -gen js ThriftTest.thrift */ // all Languages in UTF-8 const stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; function checkRecursively(assert, map1, map2) { if (typeof map1 !== 'function' && typeof map2 !== 'function') { if (!map1 || typeof map1 !== 'object') { assert.equal(map1, map2); } else { for (let key in map1) { checkRecursively(assert, map1[key], map2[key]); } } } } QUnit.module('Base Types'); QUnit.test('Void', function(assert) { assert.expect(1); const done = assert.async(); client.testVoid(function(result) { assert.equal(result, undefined); done(); }); }); QUnit.test('String', function(assert) { assert.expect(3); const done = assert.async(3); client.testString('', function(result) { assert.equal(result, ''); done(); }); client.testString(stringTest, function(result) { assert.equal(result, stringTest); done(); }); const specialCharacters = 'quote: \" backslash:' + ' forwardslash-escaped: \/ ' + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + ' now-all-of-them-together: "\\\/\b\n\r\t' + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; client.testString(specialCharacters, function(result) { assert.equal(result, specialCharacters); done(); }); }); QUnit.test('Double', function(assert) { assert.expect(4); const done = assert.async(4); client.testDouble(0, function(result) { assert.equal(result, 0); done(); }); client.testDouble(-1, function(result) { assert.equal(result, -1); done(); }); client.testDouble(3.14, function(result) { assert.equal(result, 3.14); done(); }); client.testDouble(Math.pow(2, 60), function(result) { assert.equal(result, Math.pow(2, 60)); done(); }); }); // TODO: add testBinary() QUnit.test('Byte', function(assert) { assert.expect(2); const done = assert.async(2); client.testByte(0, function(result) { assert.equal(result, 0); done(); }); client.testByte(0x01, function(result) { assert.equal(result, 0x01); done(); }); }); QUnit.test('I32', function(assert) { assert.expect(3); const done = assert.async(3); client.testI32(0, function(result) { assert.equal(result, 0); done(); }); client.testI32(Math.pow(2, 30), function(result) { assert.equal(result, Math.pow(2, 30)); done(); }); client.testI32(-Math.pow(2, 30), function(result) { assert.equal(result, -Math.pow(2, 30)); done(); }); }); QUnit.test('I64', function(assert) { assert.expect(3); const done = assert.async(3); client.testI64(0, function(result) { assert.equal(result, 0); done(); }); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately client.testI64(Math.pow(2, 52), function(result) { assert.equal(result, Math.pow(2, 52)); done(); }); client.testI64(-Math.pow(2, 52), function(result) { assert.equal(result, -Math.pow(2, 52)); done(); }); }); QUnit.module('Structured Types'); QUnit.test('Struct', function(assert) { assert.expect(5); const done = assert.async(); const structTestInput = new ThriftTest.Xtruct(); structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately structTestInput.i64_thing = Math.pow(2, 52); client.testStruct(structTestInput, function(result) { assert.equal(result.string_thing, structTestInput.string_thing); assert.equal(result.byte_thing, structTestInput.byte_thing); assert.equal(result.i32_thing, structTestInput.i32_thing); assert.equal(result.i64_thing, structTestInput.i64_thing); assert.equal(JSON.stringify(result), JSON.stringify(structTestInput)); done(); }); }); QUnit.test('Nest', function(assert) { assert.expect(7); const done = assert.async(); const xtrTestInput = new ThriftTest.Xtruct(); xtrTestInput.string_thing = 'worked'; xtrTestInput.byte_thing = 0x01; xtrTestInput.i32_thing = Math.pow(2, 30); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately xtrTestInput.i64_thing = Math.pow(2, 52); const nestTestInput = new ThriftTest.Xtruct2(); nestTestInput.byte_thing = 0x02; nestTestInput.struct_thing = xtrTestInput; nestTestInput.i32_thing = Math.pow(2, 15); client.testNest(nestTestInput, function(result) { assert.equal(result.byte_thing, nestTestInput.byte_thing); assert.equal(result.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); assert.equal(result.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); assert.equal(result.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); assert.equal(result.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); assert.equal(result.i32_thing, nestTestInput.i32_thing); assert.equal(JSON.stringify(result), JSON.stringify(nestTestInput)); done(); }); }); QUnit.test('Map', function(assert) { assert.expect(3); const done = assert.async(); const mapTestInput = {7: 77, 8: 88, 9: 99}; client.testMap(mapTestInput, function(result) { for (let key in result) { assert.equal(result[key], mapTestInput[key]); } done(); }); }); QUnit.test('StringMap', function(assert) { assert.expect(6); const done = assert.async(); const mapTestInput = { 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', 'longValue': stringTest, stringTest: 'long key' }; client.testStringMap(mapTestInput, function(result) { for (let key in result) { assert.equal(result[key], mapTestInput[key]); } done(); }); }); QUnit.test('Set', function(assert) { assert.expect(1); const done = assert.async(); const setTestInput = [1, 2, 3]; client.testSet(setTestInput, function(result) { assert.ok(result, setTestInput); done(); }); }); QUnit.test('List', function(assert) { assert.expect(1); const done = assert.async(); const listTestInput = [1, 2, 3]; client.testList(listTestInput, function(result) { assert.ok(result, listTestInput); done(); }); }); QUnit.test('Enum', function(assert) { assert.expect(1); const done = assert.async(); client.testEnum(ThriftTest.Numberz.ONE, function(result) { assert.equal(result, ThriftTest.Numberz.ONE); done(); }); }); QUnit.test('TypeDef', function(assert) { assert.expect(1); const done = assert.async(); client.testTypedef(69, function(result) { assert.equal(result, 69); done(); }); }); QUnit.module('deeper!'); QUnit.test('MapMap', function(assert) { assert.expect(16); const done = assert.async(); const mapMapTestExpectedResult = { '4': {'1': 1, '2': 2, '3': 3, '4': 4}, '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} }; client.testMapMap(1, function(result) { for (let key in result) { for (let key2 in result[key]) { assert.equal(result[key][key2], mapMapTestExpectedResult[key][key2]); } } checkRecursively(assert, result, mapMapTestExpectedResult); done(); }); }); QUnit.module('Exception'); QUnit.test('Xception', function(assert) { assert.expect(2); const done = assert.async(); client.testException('Xception', function(e) { assert.equal(e.errorCode, 1001); assert.equal(e.message, 'Xception'); done(); }); }); QUnit.test('no Exception', function(assert) { assert.expect(1); const done = assert.async(); client.testException('no Exception', function(e) { assert.ok(!e); done(); }); }); QUnit.module('Insanity'); QUnit.test('testInsanity', function(assert) { assert.expect(24); const done = assert.async(); const insanity = { '1': { '2': { 'userMap': { '5': 5, '8': 8 }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': 4 }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': 2 } ] }, '3': { 'userMap': { '5': 5, '8': 8 }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': 4 }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': 2 } ] } }, '2': { '6': { 'userMap': null, 'xtructs': null } } }; client.testInsanity(new ThriftTest.Insanity(), function(res) { assert.ok(res, JSON.stringify(res)); assert.ok(insanity, JSON.stringify(insanity)); checkRecursively(assert, res, insanity); done(); }); }); QUnit.module('Oneway'); QUnit.test('testOneway', function(assert) { assert.expect(1); const done = assert.async(); client.testOneway(1, function(result) { assert.equal(result, undefined); done(); }); }); thrift-0.16.0/lib/js/test/test-deep-constructor.html000077500000000000000000000045551420101504100224020ustar00rootroot00000000000000 Thrift Javascript Bindings: Unit Test

Thrift Javascript Bindings: Deep Constructor Test (JsDeepConstructorTest.thrift)

Valid XHTML 1.0!

thrift-0.16.0/lib/js/test/test-double-rendering.html000066400000000000000000000050241420101504100223140ustar00rootroot00000000000000+ Rendering Double Constants in JS: Unit Test

Rendering Double Constants in JS: Unit Test

thrift-0.16.0/lib/js/test/test-double-rendering.js000066400000000000000000000133711420101504100217700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ /* * JavaScript test suite for double constants inside * DoubleConstantsTest.thrift. These tests will run against Normal (-gen js) * Apache Thrift interfaces. * * To compile client code for this test use: * $ thrift -gen js DoubleConstantsTest.thrift */ // double assertion threshold const EPSILON = 0.0000001; // Work around for old API used by QUnitAdapter of jsTestDriver if (typeof QUnit.log == 'function') { // When using real QUnit (fron PhantomJS) log failures to console QUnit.log(function(details) { if (!details.result) { console.log('======== FAIL ========'); console.log('TestName: ' + details.name); if (details.message) console.log(details.message); console.log('Expected: ' + details.expected); console.log('Actual : ' + details.actual); console.log('======================'); } }); } QUnit.module('Double rendering'); QUnit.test('Double (rendering)', function(assert) { console.log('Double rendering test -- starts'); const EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1; const EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100; const EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807; const EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807; const EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359; const EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1; const EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1; const EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308; const EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43; const EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308; const EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43; assert.ok( Math.abs(EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT - DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT - DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT - DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT - DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS - DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE - DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE - DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE - DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE - DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE - DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST) <= EPSILON); assert.ok( Math.abs( EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE - DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST) <= EPSILON); assert.equal(typeof DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, 'number'); assert.equal(typeof DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST, 'number'); const EXPECTED_DOUBLE_LIST = [1,-100,100,9223372036854775807,-9223372036854775807,3.14159265359,1000000.1,-1000000.1,1.7e+308,-1.7e+308, 9223372036854775816.43,-9223372036854775816.43]; assert.equal(DOUBLE_LIST_TEST.length, EXPECTED_DOUBLE_LIST.length); for (let i = 0; i < EXPECTED_DOUBLE_LIST.length; ++i) { assert.ok(Math.abs(EXPECTED_DOUBLE_LIST[i] - DOUBLE_LIST_TEST[i]) <= EPSILON); } console.log('Double rendering test -- ends'); }); thrift-0.16.0/lib/js/test/test-es6.html000066400000000000000000000060631420101504100175700ustar00rootroot00000000000000 Thrift Javascript Bindings: Unit Test

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

thrift-0.16.0/lib/js/test/test-es6.js000066400000000000000000000313351420101504100172400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ /* * Fully Async JavaScript test suite for ThriftTest.thrift. * These tests are designed to exercise the WebSocket transport * (which is exclusively async). * * To compile client code for this test use: * $ thrift -gen js:es6 ThriftTest.thrift */ // all Languages in UTF-8 const stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; function checkRecursively(assert, map1, map2) { if (typeof map1 !== 'function' && typeof map2 !== 'function') { if (!map1 || typeof map1 !== 'object') { assert.equal(map1, map2); } else { for (var key in map1) { checkRecursively(assert, map1[key], map2[key]); } } } } QUnit.module('Base Types'); QUnit.test('Void', function( assert ) { assert.expect(1); const done = assert.async(); client.testVoid().then(function(result) { assert.equal(result, undefined); done(); }); }); QUnit.test('String', function( assert ) { assert.expect(3); const done = assert.async(3); client.testString('').then(function(result) { assert.equal(result, ''); done(); }); client.testString(stringTest).then(function(result) { assert.equal(result, stringTest); done(); }); var specialCharacters = 'quote: \" backslash:' + ' forwardslash-escaped: \/ ' + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + ' now-all-of-them-together: "\\\/\b\n\r\t' + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; client.testString(specialCharacters).then(function(result) { assert.equal(result, specialCharacters); done(); }); }); QUnit.test('Double', function( assert ) { assert.expect(4); const done = assert.async(4); client.testDouble(0).then(function(result) { assert.equal(result, 0); done(); }); client.testDouble(-1).then(function(result) { assert.equal(result, -1); done(); }); client.testDouble(3.14).then(function(result) { assert.equal(result, 3.14); done(); }); client.testDouble(Math.pow(2, 60)).then(function(result) { assert.equal(result, Math.pow(2, 60)); done(); }); }); // TODO: add testBinary() QUnit.test('Byte', function( assert ) { assert.expect(2); const done = assert.async(2); client.testByte(0).then(function(result) { assert.equal(result, 0); done(); }); client.testByte(0x01).then(function(result) { assert.equal(result, 0x01); done(); }); }); QUnit.test('I32', function( assert ) { assert.expect(3); const done = assert.async(3); client.testI32(0).then(function(result) { assert.equal(result, 0); done(); }); client.testI32(Math.pow(2, 30)).then(function(result) { assert.equal(result, Math.pow(2, 30)); done(); }); client.testI32(-Math.pow(2, 30)).then(function(result) { assert.equal(result, -Math.pow(2, 30)); done(); }); }); QUnit.test('I64', function( assert ) { assert.expect(3); const done = assert.async(3); client.testI64(0).then(function(result) { assert.equal(result, 0); done(); }); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately client.testI64(Math.pow(2, 52)).then(function(result) { assert.equal(result, Math.pow(2, 52)); done(); }); client.testI64(-Math.pow(2, 52)).then(function(result) { assert.equal(result, -Math.pow(2, 52)); done(); }); }); QUnit.module('Structured Types'); QUnit.test('Struct', function( assert ) { assert.expect(5); const done = assert.async(); var structTestInput = new ThriftTest.Xtruct(); structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately structTestInput.i64_thing = Math.pow(2, 52); client.testStruct(structTestInput).then(function(result) { assert.equal(result.string_thing, structTestInput.string_thing); assert.equal(result.byte_thing, structTestInput.byte_thing); assert.equal(result.i32_thing, structTestInput.i32_thing); assert.equal(result.i64_thing, structTestInput.i64_thing); assert.equal(JSON.stringify(result), JSON.stringify(structTestInput)); done(); }); }); QUnit.test('Nest', function( assert ) { assert.expect(7); const done = assert.async(); var xtrTestInput = new ThriftTest.Xtruct(); xtrTestInput.string_thing = 'worked'; xtrTestInput.byte_thing = 0x01; xtrTestInput.i32_thing = Math.pow(2, 30); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately xtrTestInput.i64_thing = Math.pow(2, 52); var nestTestInput = new ThriftTest.Xtruct2(); nestTestInput.byte_thing = 0x02; nestTestInput.struct_thing = xtrTestInput; nestTestInput.i32_thing = Math.pow(2, 15); client.testNest(nestTestInput).then(function(result) { assert.equal(result.byte_thing, nestTestInput.byte_thing); assert.equal(result.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); assert.equal(result.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); assert.equal(result.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); assert.equal(result.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); assert.equal(result.i32_thing, nestTestInput.i32_thing); assert.equal(JSON.stringify(result), JSON.stringify(nestTestInput)); done(); }); }); QUnit.test('Map', function( assert ) { assert.expect(3); const done = assert.async(); var mapTestInput = {7: 77, 8: 88, 9: 99}; client.testMap(mapTestInput).then(function(result) { for (var key in result) { assert.equal(result[key], mapTestInput[key]); } done(); }); }); QUnit.test('StringMap', function( assert ) { assert.expect(6); const done = assert.async(); var mapTestInput = { 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', 'longValue': stringTest, stringTest: 'long key' }; client.testStringMap(mapTestInput).then(function(result) { for (var key in result) { assert.equal(result[key], mapTestInput[key]); } done(); }); }); QUnit.test('Set', function( assert ) { assert.expect(1); const done = assert.async(); var setTestInput = [1, 2, 3]; client.testSet(setTestInput).then(function(result) { assert.ok(result, setTestInput); done(); }); }); QUnit.test('List', function( assert ) { assert.expect(1); const done = assert.async(); var listTestInput = [1, 2, 3]; client.testList(listTestInput).then(function(result) { assert.ok(result, listTestInput); done(); }); }); QUnit.test('Enum', function( assert ) { assert.expect(1); const done = assert.async(); client.testEnum(ThriftTest.Numberz.ONE).then(function(result) { assert.equal(result, ThriftTest.Numberz.ONE); done(); }); }); QUnit.test('TypeDef', function( assert ) { assert.expect(1); const done = assert.async(); client.testTypedef(69).then(function(result) { assert.equal(result, 69); done(); }); }); QUnit.module('deeper!'); QUnit.test('MapMap', function( assert ) { assert.expect(16); const done = assert.async(); var mapMapTestExpectedResult = { '4': {'1': 1, '2': 2, '3': 3, '4': 4}, '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} }; client.testMapMap(1).then(function(result) { for (var key in result) { for (var key2 in result[key]) { assert.equal(result[key][key2], mapMapTestExpectedResult[key][key2]); } } checkRecursively(assert, result, mapMapTestExpectedResult); done(); }); }); QUnit.module('Exception'); QUnit.test('Xception', function( assert ) { assert.expect(2); const done = assert.async(); client.testException('Xception').then(function(res) { assert.ok(false); }).catch(function(e) { console.log(`Exception exception e`); console.log(e); console.log(JSON.stringify(e, null, 2)); assert.equal(e.errorCode, 1001); assert.equal(e.message, 'Xception'); done(); }); }); QUnit.test('no Exception', function( assert ) { assert.expect(1); const done = assert.async(); client.testException('no Exception').then(function(e) { assert.ok(!e); done(); }); }); QUnit.module('Insanity'); QUnit.test('testInsanity', function( assert ) { assert.expect(24); const done = assert.async(); var insanity = { '1': { '2': { 'userMap': { '5': 5, '8': 8 }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': 4 }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': 2 } ] }, '3': { 'userMap': { '5': 5, '8': 8 }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': 4 }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': 2 } ] } }, '2': { '6': { 'userMap': null, 'xtructs': null } } }; client.testInsanity(new ThriftTest.Insanity()).then(function(res) { assert.ok(res, JSON.stringify(res)); assert.ok(insanity, JSON.stringify(insanity)); checkRecursively(assert, res, insanity); done(); }); }); QUnit.module('Oneway'); QUnit.test('testOneway', function( assert ) { assert.expect(1); const done = assert.async(); client.testOneway(1).then(function(result) { assert.equal(result, undefined); done(); }); }); thrift-0.16.0/lib/js/test/test-int64.html000066400000000000000000000047711420101504100200430ustar00rootroot00000000000000+ Int64 Constants in JS: Unit Test

Int64 Constants in JS: Unit Test

thrift-0.16.0/lib/js/test/test-int64.js000066400000000000000000000072261420101504100175110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ // Work around for old API used by QUnitAdapter of jsTestDriver if (typeof QUnit.log == 'function') { // When using real QUnit (fron PhantomJS) log failures to console QUnit.log(function(details) { if (!details.result) { console.log('======== FAIL ========'); console.log('TestName: ' + details.name); if (details.message) console.log(details.message); console.log('Expected: ' + details.expected); console.log('Actual : ' + details.actual); console.log('======================'); } }); } QUnit.module('Int64'); QUnit.test('Int64', function(assert) { console.log('Int64 test -- starts'); const EXPECTED_SMALL_INT64_AS_NUMBER = 42; const EXPECTED_SMALL_INT64 = new Int64(42); const EXPECTED_MAX_JS_SAFE_INT64 = new Int64(Number.MAX_SAFE_INTEGER); const EXPECTED_MIN_JS_SAFE_INT64 = new Int64(Number.MIN_SAFE_INTEGER); const EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64 = new Int64("0020000000000000"); // hex-encoded const EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64 = new Int64("ffe0000000000000"); // hex-encoded 2's complement const EXPECTED_MAX_SIGNED_INT64 = new Int64("7fffffffffffffff"); // hex-encoded const EXPECTED_MIN_SIGNED_INT64 = new Int64("8000000000000000"); // hex-encoded 2's complement const EXPECTED_INT64_LIST = [ EXPECTED_SMALL_INT64, EXPECTED_MAX_JS_SAFE_INT64, EXPECTED_MIN_JS_SAFE_INT64, EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64, EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64, EXPECTED_MAX_SIGNED_INT64, EXPECTED_MIN_SIGNED_INT64 ]; assert.ok(EXPECTED_SMALL_INT64.equals(Int64Test.SMALL_INT64)); assert.ok(EXPECTED_MAX_JS_SAFE_INT64.equals(Int64Test.MAX_JS_SAFE_INT64)); assert.ok(EXPECTED_MIN_JS_SAFE_INT64.equals(Int64Test.MIN_JS_SAFE_INT64)); assert.ok( EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64.equals( Int64Test.MAX_JS_SAFE_PLUS_ONE_INT64 ) ); assert.ok( EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64.equals( Int64Test.MIN_JS_SAFE_MINUS_ONE_INT64 ) ); assert.ok(EXPECTED_MAX_SIGNED_INT64.equals(Int64Test.MAX_SIGNED_INT64)); assert.ok(EXPECTED_MIN_SIGNED_INT64.equals(Int64Test.MIN_SIGNED_INT64)); assert.equal( EXPECTED_SMALL_INT64_AS_NUMBER, Int64Test.SMALL_INT64.toNumber() ); assert.equal( Number.MAX_SAFE_INTEGER, Int64Test.MAX_JS_SAFE_INT64.toNumber() ); assert.equal( Number.MIN_SAFE_INTEGER, Int64Test.MIN_JS_SAFE_INT64.toNumber() ); for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i) { assert.ok(EXPECTED_INT64_LIST[i].equals(Int64Test.INT64_LIST[i])); } for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i){ let int64Object = EXPECTED_INT64_LIST[i]; assert.ok(Int64Test.INT64_2_INT64_MAP[JSONInt64.toDecimalString(int64Object)].equals(int64Object)); } console.log('Int64 test -- ends'); }); thrift-0.16.0/lib/js/test/test-jq.js000066400000000000000000000110271420101504100171510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ /* * JavaScript test suite for ThriftTest.thrift. These tests * will run only with jQuery (-gen js:jquery) Apache Thrift * interfaces. To create client code: * $ thrift -gen js:jquery ThriftTest.thrift * * See also: * ++ test.js for generic tests * ++ test-nojq.js for "-gen js" only tests */ ////////////////////////////////// //jQuery asynchronous tests jQuery.ajaxSetup({ timeout: 0 }); QUnit.module('jQ Async Manual'); QUnit.test('testI32', function(assert) { assert.expect(2); const done = assert.async(2); const transport = new Thrift.Transport(); const protocol = new Thrift.Protocol(transport); const client = new ThriftTest.ThriftTestClient(protocol); const jqxhr = jQuery.ajax({ url: '/service', data: client.send_testI32(Math.pow(-2, 31)), type: 'POST', cache: false, dataType: 'text', success: function(res) { transport.setRecvBuffer(res); assert.equal(client.recv_testI32(), Math.pow(-2, 31)); done(); }, error: function() { assert.ok(false); }, complete: function() { assert.ok(true); done(); } }); }); QUnit.test('testI64', function(assert) { assert.expect(2); const done = assert.async(2); const transport = new Thrift.Transport(); const protocol = new Thrift.Protocol(transport); const client = new ThriftTest.ThriftTestClient(protocol); jQuery.ajax({ url: '/service', //This is usually 2^61 but JS cannot represent anything over 2^52 accurately data: client.send_testI64(Math.pow(-2, 52)), type: 'POST', cache: false, dataType: 'text', success: function(res) { transport.setRecvBuffer(res); //This is usually 2^61 but JS cannot represent anything over 2^52 accurately assert.equal(client.recv_testI64(), Math.pow(-2, 52)); done(); }, error: function() { assert.ok(false); }, complete: function() { assert.ok(true); done(); } }); }); QUnit.module('jQ Async'); QUnit.test('I32', function(assert) { assert.expect(3); const done = assert.async(3); client.testI32(Math.pow(2, 30), function(result) { assert.equal(result, Math.pow(2, 30)); done(); }); const jqxhr = client.testI32(Math.pow(-2, 31), function(result) { assert.equal(result, Math.pow(-2, 31)); done(); }); jqxhr.success(function(result) { assert.equal(result, Math.pow(-2, 31)); done(); }); }); QUnit.test('I64', function(assert) { assert.expect(4); const done = assert.async(4); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately client.testI64(Math.pow(2, 52), function(result) { assert.equal(result, Math.pow(2, 52)); done(); }); //This is usually 2^60 but JS cannot represent anything over 2^52 accurately client.testI64(Math.pow(-2, 52), function(result) { assert.equal(result, Math.pow(-2, 52)); done(); }) .error(function(xhr, status, e) { assert.ok(false, e.message); }) .success(function(result) { //This is usually 2^60 but JS cannot represent anything over 2^52 accurately assert.equal(result, Math.pow(-2, 52)); done(); }) .complete(function() { assert.ok(true); done(); }); }); QUnit.test('Xception', function(assert) { assert.expect(2); const done = assert.async(2); const dfd = client.testException('Xception', function(result) { assert.ok(false); done(); }) .error(function(xhr, status, e) { assert.equal(e.errorCode, 1001); assert.equal(e.message, 'Xception'); done(); $(document).ajaxError( function() { done(); } ); }); }); thrift-0.16.0/lib/js/test/test-nojq.html000066400000000000000000000051771420101504100200470ustar00rootroot00000000000000 Thrift Javascript Bindings: Unit Test

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

thrift-0.16.0/lib/js/test/test-nojq.js000066400000000000000000000027211420101504100175070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ /* * JavaScript test suite for ThriftTest.thrift. These tests * will run only with normal "-gen js" Apache Thrift interfaces. * To create client code: * $ thrift -gen js ThriftTest.thrift * * See also: * ++ test.js for generic tests * ++ test-jq.js for "-gen js:jquery" only tests */ ////////////////////////////////// //Async exception tests QUnit.module('NojQ Async'); QUnit.test('Xception', function(assert) { assert.expect(2); const done = assert.async(); client.testException('Xception', function(result) { assert.equal(result.errorCode, 1001); assert.equal(result.message, 'Xception'); done(); }); }); thrift-0.16.0/lib/js/test/test.html000077500000000000000000000053651420101504100171040ustar00rootroot00000000000000 Thrift Javascript Bindings: Unit Test

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

thrift-0.16.0/lib/js/test/test.js000077500000000000000000000352721420101504100165540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ /* * JavaScript test suite for ThriftTest.thrift. These tests * will run against Normal (-gen js) and jQuery (-gen js:jquery) * Apache Thrift interfaces. * * Synchronous blocking calls should be identical in both * Normal and jQuery interfaces. All synchronous tests belong * here. * * Asynchronous success callbacks passed as the last parameter * of an RPC call should be identical in both Normal and jQuery * interfaces. Async success tests belong here. * * Asynchronous exception processing is different in Normal * and jQuery interfaces. Such tests belong in the test-nojq.js * or test-jq.js files respectively. jQuery specific XHR object * tests also belong in test-jq.js. Do not create any jQuery * dependencies in this file or in test-nojq.js * * To compile client code for this test use: * $ thrift -gen js ThriftTest.thrift * -- or -- * $ thrift -gen js:jquery ThriftTest.thrift * * See also: * ++ test-nojq.js for "-gen js" only tests * ++ test-jq.js for "-gen js:jquery" only tests */ const transport = new Thrift.Transport('/service'); const protocol = new Thrift.Protocol(transport); const client = new ThriftTest.ThriftTestClient(protocol); const int64_2_pow_60 = new Int64('1000000000000000'); const int64_minus_2_pow_60 = new Int64('f000000000000000'); // Work around for old API used by QUnitAdapter of jsTestDriver if (typeof QUnit.log == 'function') { // When using real QUnit (fron PhantomJS) log failures to console QUnit.log(function(details) { if (!details.result) { console.log('======== FAIL ========'); console.log('TestName: ' + details.name); if (details.message) console.log(details.message); console.log('Expected: ' + details.expected); console.log('Actual : ' + details.actual); console.log('======================'); } }); } // all Languages in UTF-8 const stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; function checkRecursively(assert, map1, map2) { if (typeof map1 !== 'function' && typeof map2 !== 'function') { if (!map1 || typeof map1 !== 'object') { assert.equal(map1, map2); } else { for (let key in map1) { checkRecursively(assert, map1[key], map2[key]); } } } } QUnit.module('Base Types'); QUnit.test('Void', function(assert) { assert.equal(client.testVoid(), undefined); }); QUnit.test('Binary (String)', function(assert) { let binary = ''; for (let v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } assert.equal(client.testBinary(binary), binary); }); QUnit.test('Binary (Uint8Array)', function(assert) { let binary = ''; for (let v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } const arr = new Uint8Array(binary.length); for (let i = 0; i < binary.length; ++i) { arr[i] = binary[i].charCodeAt(); } assert.equal(client.testBinary(arr), binary); }); QUnit.test('String', function(assert) { assert.equal(client.testString(''), ''); assert.equal(client.testString(stringTest), stringTest); const specialCharacters = 'quote: \" backslash:' + ' forwardslash-escaped: \/ ' + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + ' now-all-of-them-together: "\\\/\b\n\r\t' + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; assert.equal(client.testString(specialCharacters), specialCharacters); }); QUnit.test('Double', function(assert) { assert.equal(client.testDouble(0), 0); assert.equal(client.testDouble(-1), -1); assert.equal(client.testDouble(3.14), 3.14); assert.equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60)); }); QUnit.test('Byte', function(assert) { assert.equal(client.testByte(0), 0); assert.equal(client.testByte(0x01), 0x01); }); QUnit.test('I32', function(assert) { assert.equal(client.testI32(0), 0); assert.equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30)); assert.equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30)); }); QUnit.test('I64', function(assert) { assert.equal(client.testI64(0), 0); let int64_2_pow_60_result = client.testI64(int64_2_pow_60); assert.ok(int64_2_pow_60.equals(int64_2_pow_60_result)); let int64_minus_2_pow_60_result = client.testI64(int64_minus_2_pow_60); assert.ok(int64_minus_2_pow_60.equals(int64_minus_2_pow_60_result)); }); QUnit.module('Structured Types'); QUnit.test('Struct', function(assert) { const structTestInput = new ThriftTest.Xtruct(); structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); structTestInput.i64_thing = int64_2_pow_60; const structTestOutput = client.testStruct(structTestInput); assert.equal(structTestOutput.string_thing, structTestInput.string_thing); assert.equal(structTestOutput.byte_thing, structTestInput.byte_thing); assert.equal(structTestOutput.i32_thing, structTestInput.i32_thing); assert.ok(structTestOutput.i64_thing.equals(structTestInput.i64_thing)); assert.equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput)); }); QUnit.test('Nest', function(assert) { const xtrTestInput = new ThriftTest.Xtruct(); xtrTestInput.string_thing = 'worked'; xtrTestInput.byte_thing = 0x01; xtrTestInput.i32_thing = Math.pow(2, 30); xtrTestInput.i64_thing = int64_2_pow_60; const nestTestInput = new ThriftTest.Xtruct2(); nestTestInput.byte_thing = 0x02; nestTestInput.struct_thing = xtrTestInput; nestTestInput.i32_thing = Math.pow(2, 15); const nestTestOutput = client.testNest(nestTestInput); assert.equal(nestTestOutput.byte_thing, nestTestInput.byte_thing); assert.equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); assert.equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); assert.equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); assert.ok(nestTestOutput.struct_thing.i64_thing.equals(nestTestInput.struct_thing.i64_thing)); assert.equal(nestTestOutput.i32_thing, nestTestInput.i32_thing); assert.equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput)); }); QUnit.test('Map', function(assert) { const mapTestInput = {7: 77, 8: 88, 9: 99}; const mapTestOutput = client.testMap(mapTestInput); for (let key in mapTestOutput) { assert.equal(mapTestOutput[key], mapTestInput[key]); } }); QUnit.test('StringMap', function(assert) { const mapTestInput = { 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', 'longValue': stringTest, stringTest: 'long key' }; const mapTestOutput = client.testStringMap(mapTestInput); for (let key in mapTestOutput) { assert.equal(mapTestOutput[key], mapTestInput[key]); } }); QUnit.test('Set', function(assert) { const setTestInput = [1, 2, 3]; assert.ok(client.testSet(setTestInput), setTestInput); }); QUnit.test('List', function(assert) { const listTestInput = [1, 2, 3]; assert.ok(client.testList(listTestInput), listTestInput); }); QUnit.test('Enum', function(assert) { assert.equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE); }); QUnit.test('TypeDef', function(assert) { assert.equal(client.testTypedef(69), 69); }); QUnit.test('Skip', function(assert) { const structTestInput = new ThriftTest.Xtruct(); const modifiedClient = new ThriftTest.ThriftTestClient(protocol); modifiedClient.recv_testStruct = function() { const input = modifiedClient.input; const xtruct3 = new ThriftTest.Xtruct3(); input.readMessageBegin(); input.readStructBegin(); // read Xtruct data with Xtruct3 input.readFieldBegin(); xtruct3.read(input); input.readFieldEnd(); // read Thrift.Type.STOP message input.readFieldBegin(); input.readFieldEnd(); input.readStructEnd(); input.readMessageEnd(); return xtruct3; }; structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); structTestInput.i64_thing = int64_2_pow_60; const structTestOutput = modifiedClient.testStruct(structTestInput); assert.equal(structTestOutput instanceof ThriftTest.Xtruct3, true); assert.equal(structTestOutput.string_thing, structTestInput.string_thing); assert.equal(structTestOutput.changed, null); assert.equal(structTestOutput.i32_thing, structTestInput.i32_thing); assert.ok(structTestOutput.i64_thing.equals(structTestInput.i64_thing)); }); QUnit.module('deeper!'); QUnit.test('MapMap', function(assert) { const mapMapTestExpectedResult = { '4': {'1': 1, '2': 2, '3': 3, '4': 4}, '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} }; const mapMapTestOutput = client.testMapMap(1); for (let key in mapMapTestOutput) { for (let key2 in mapMapTestOutput[key]) { assert.equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]); } } checkRecursively(assert, mapMapTestOutput, mapMapTestExpectedResult); }); QUnit.module('Exception'); QUnit.test('Xception', function(assert) { assert.expect(2); const done = assert.async(); try { client.testException('Xception'); assert.ok(false); }catch (e) { assert.equal(e.errorCode, 1001); assert.equal(e.message, 'Xception'); done(); } }); QUnit.test('no Exception', function(assert) { assert.expect(1); try { client.testException('no Exception'); assert.ok(true); }catch (e) { assert.ok(false); } }); QUnit.test('TException', function(assert) { //ThriftTest does not list TException as a legal exception so it will // generate an exception on the server that does not propagate back to // the client. This test has been modified to equate to "no exception" assert.expect(1); try { client.testException('TException'); } catch (e) { //assert.ok(false); } assert.ok(true); }); QUnit.module('Insanity'); const crazy = { 'userMap': { '5': 5, '8': 8 }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': new Int64(4) }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': new Int64(2) }] }; QUnit.test('testInsanity', function(assert) { const insanity = { '1': { '2': crazy, '3': crazy }, '2': { '6': { 'userMap': null, 'xtructs': null } } }; const res = client.testInsanity(new ThriftTest.Insanity(crazy)); assert.ok(res, JSON.stringify(res)); assert.ok(insanity, JSON.stringify(insanity)); checkRecursively(assert, res, insanity); }); ////////////////////////////////// //Run same tests asynchronously QUnit.module('Async'); QUnit.test('Double', function(assert) { assert.expect(1); const done = assert.async(); client.testDouble(3.14159265, function(result) { assert.equal(result, 3.14159265); done(); }); }); QUnit.test('Byte', function(assert) { assert.expect(1); const done = assert.async(); client.testByte(0x01, function(result) { assert.equal(result, 0x01); done(); }); }); QUnit.test('I32', function(assert) { assert.expect(2); const done = assert.async(2); client.testI32(Math.pow(2, 30), function(result) { assert.equal(result, Math.pow(2, 30)); done(); }); client.testI32(Math.pow(-2, 31), function(result) { assert.equal(result, Math.pow(-2, 31)); done(); }); }); QUnit.test('I64', function(assert) { assert.expect(2); const done = assert.async(2); client.testI64(int64_2_pow_60, function(result) { assert.ok(int64_2_pow_60.equals(result)); done(); }); client.testI64(int64_minus_2_pow_60, function(result) { assert.ok(int64_minus_2_pow_60.equals(result)); done(); }); }); thrift-0.16.0/lib/js/test/test_handler.js000066400000000000000000000133221420101504100202360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //This is the server side Node test handler for the standard // Apache Thrift test service. const es6Mode = process.argv.includes('--es6'); const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs'; const ttypes = require(`./${genFolder}/ThriftTest_types`); const TException = require('../../nodejs/lib/thrift').TException; const Int64 = require('node-int64'); exports.ThriftTestHandler = { testVoid: function(result) { console.log('testVoid()'); result(null); }, testString: function(thing, result) { console.log('testString(\'' + thing + '\')'); result(null, thing); }, testByte: function(thing, result) { console.log('testByte(' + thing + ')'); result(null, thing); }, testI32: function(thing, result) { console.log('testI32(' + thing + ')'); result(null, thing); }, testI64: function(thing, result) { console.log('testI64(' + thing + ')'); result(null, thing); }, testDouble: function(thing, result) { console.log('testDouble(' + thing + ')'); result(null, thing); }, testBinary: function(thing, result) { console.log('testBinary(\'' + thing + '\')'); result(null, thing); }, testStruct: function(thing, result) { console.log('testStruct('); console.log(thing); console.log(')'); result(null, thing); }, testNest: function(nest, result) { console.log('testNest('); console.log(nest); console.log(')'); result(null, nest); }, testMap: function(thing, result) { console.log('testMap('); console.log(thing); console.log(')'); result(null, thing); }, testStringMap: function(thing, result) { console.log('testStringMap('); console.log(thing); console.log(')'); result(null, thing); }, testSet: function(thing, result) { console.log('testSet('); console.log(thing); console.log(')'); result(null, thing); }, testList: function(thing, result) { console.log('testList('); console.log(thing); console.log(')'); result(null, thing); }, testEnum: function(thing, result) { console.log('testEnum(' + thing + ')'); result(null, thing); }, testTypedef: function(thing, result) { console.log('testTypedef(' + thing + ')'); result(null, thing); }, testMapMap: function(hello, result) { console.log('testMapMap(' + hello + ')'); const mapmap = []; const pos = []; const neg = []; for (let i = 1; i < 5; i++) { pos[i] = i; neg[-i] = -i; } mapmap[4] = pos; mapmap[-4] = neg; result(null, mapmap); }, testInsanity: function(argument, result) { console.log('testInsanity('); console.log(argument); console.log(')'); const hello = new ttypes.Xtruct(); hello.string_thing = 'Hello2'; hello.byte_thing = 2; hello.i32_thing = 2; hello.i64_thing = new Int64(2); const goodbye = new ttypes.Xtruct(); goodbye.string_thing = 'Goodbye4'; goodbye.byte_thing = 4; goodbye.i32_thing = 4; goodbye.i64_thing = new Int64(4); const crazy = new ttypes.Insanity(); crazy.userMap = []; crazy.userMap[ttypes.Numberz.EIGHT] = 8; crazy.userMap[ttypes.Numberz.FIVE] = 5; crazy.xtructs = [goodbye, hello]; const first_map = []; const second_map = []; first_map[ttypes.Numberz.TWO] = crazy; first_map[ttypes.Numberz.THREE] = crazy; const looney = new ttypes.Insanity(); second_map[ttypes.Numberz.SIX] = looney; const insane = []; insane[1] = first_map; insane[2] = second_map; console.log('insane result:'); console.log(insane); result(null, insane); }, testMulti: function(arg0, arg1, arg2, arg3, arg4, arg5, result) { console.log('testMulti()'); const hello = new ttypes.Xtruct(); hello.string_thing = 'Hello2'; hello.byte_thing = arg0; hello.i32_thing = arg1; hello.i64_thing = arg2; result(null, hello); }, testException: function(arg, result) { console.log('testException(' + arg + ')'); if (arg === 'Xception') { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = arg; result(x); } else if (arg === 'TException') { result(new TException(arg)); } else { result(null); } }, testMultiException: function(arg0, arg1, result) { console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); if (arg0 === ('Xception')) { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = 'This is an Xception'; result(x); } else if (arg0 === ('Xception2')) { const x2 = new ttypes.Xception2(); x2.errorCode = 2002; x2.struct_thing = new ttypes.Xtruct(); x2.struct_thing.string_thing = 'This is an Xception2'; result(x2); } const res = new ttypes.Xtruct(); res.string_thing = arg1; result(null, res); }, testOneway: function(sleepFor, result) { console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!'); } }; //ThriftTestSvcHandler thrift-0.16.0/lib/js/test/testws.html000066400000000000000000000060601420101504100174440ustar00rootroot00000000000000 Thrift Javascript Bindings: Unit Test

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

thrift-0.16.0/lib/json/000077500000000000000000000000001420101504100146015ustar00rootroot00000000000000thrift-0.16.0/lib/json/Makefile.am000066400000000000000000000017311420101504100166370ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # if WITH_JAVA # Schema validation test depends on java SUBDIRS = test endif clean-local: $(RM) -r test/build/ dist-hook: $(RM) -r $(distdir)/test/build/ EXTRA_DIST = \ schema.json \ test thrift-0.16.0/lib/json/schema.json000066400000000000000000000205411420101504100167360ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://thrift.apache.org/schema.json#", "description": "Schema for Apache Thrift protocol descriptors", "definitions": { "type-id": { "title": "Any type id (name)", "enum": [ "void", "string", "bool", "byte", "i8", "i16", "i32", "i64", "double", "list", "set", "map", "union", "struct", "binary" ] }, "base-type": { "title": "Base type schema", "type": "object", "properties": { "typeId": { "enum": ["void", "string", "bool", "byte", "i8", "i16", "i32", "i64", "double", "binary" ] } }, "required": [ "typeId" ] }, "list-type": { "title": "List and set schema", "type": "object", "properties": { "typeId": { "enum": [ "list", "set" ] }, "elemTypeId": { "$ref": "#/definitions/type-id" }, "elemType": { "$ref": "#/definitions/type-desc" } }, "required": [ "typeId", "elemTypeId" ] }, "map-type": { "title": "Map schema", "type": "object", "properties": { "typeId": { "enum": [ "map" ] }, "keyTypeId": { "$ref": "#/definitions/type-id" }, "keyType": { "$ref": "#/definitions/type-desc" }, "valueTypeId": { "$ref": "#/definitions/type-id" }, "valueType": { "$ref": "#/definitions/type-desc" } }, "required": [ "typeId", "keyTypeId", "valueTypeId" ] }, "struct-type": { "title": "Struct, union and exception schema", "type": "object", "properties": { "typeId": { "enum": [ "union", "struct", "exception" ] } }, "required": [ "typeId", "class" ] }, "type-desc": { "title": "Type descriptor schema", "allOf": [ { "type": "object", "properties": { "typeId": { "type": "string" }, "class": { "type": "string" } } }, { "oneOf": [ { "$ref": "#/definitions/base-type" }, { "$ref": "#/definitions/list-type" }, { "$ref": "#/definitions/map-type" }, { "$ref": "#/definitions/struct-type" } ] } ] }, "name-and-doc": { "title": "Name and documentation sub-schema", "type": "object", "properties": { "name": { "type": "string" }, "doc": { "type": "string" } }, "required": [ "name" ] }, "enum": { "title": "Thrift 'enum' definition schema", "type": "object", "allOf": [ { "$ref": "#/definitions/name-and-doc" }, { "required": [ "members" ], "properties": { "members": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "value": { "type": "integer" } }, "required": [ "name", "value" ] } } } } ] }, "typedef": { "title": "Thrift typedef definition schema", "type": "object", "allOf": [ { "$ref": "#/definitions/name-and-doc" }, { "properties": { "typeId": { "$ref": "#/definitions/type-id" }, "type": { "$ref": "#/definitions/type-desc" } }, "required": [ "typeId" ] } ] }, "constant": { "title": "Thrift constant definition schema", "type": "object", "allOf": [ { "$ref": "#/definitions/name-and-doc" }, { "$ref": "#/definitions/type-desc" }, { "properties": { "value": { "oneOf": [ { "type": "string" }, { "type": "number" }, { "type": "array" }, { "type": "object" } ] } }, "required": [ "value" ] } ] }, "field": { "title": "Thrift struct field definition schema", "type": "object", "allOf": [ { "$ref": "#/definitions/name-and-doc" }, { "properties": { "key": { "type": "integer", "minimum": 1, "maximum": 65535 }, "required": { "enum": [ "required", "optional", "req_out" ] }, "typeId": { "$ref": "#/definitions/type-id" }, "type": { "$ref": "#/definitions/type-desc" }, "default": { "oneOf": [ { "type": "string" }, { "type": "number" }, { "type": "array" }, { "type": "object" } ] } }, "required": [ "key", "required" ] } ] }, "struct": { "title": "Thrift struct definition schema", "type": "object", "allOf": [ { "$ref": "#/definitions/name-and-doc" }, { "properties": { "isException": { "type": "boolean" }, "isUnion": { "type": "boolean" }, "fields": { "type": "array", "items": { "$ref": "#/definitions/field" } } }, "required": [ "isException", "isUnion", "fields" ] } ] }, "union": { "title": "Thrift union definition schema", "$ref": "#/definitions/struct" }, "exception": { "title": "Thrift exception definition schema", "type": "object", "properties": { "key": { "type": "integer", "minimum": 1, "maximum": 65535 }, "name": { "type": "string" }, "typeId": { "enum": [ "exception" ] }, "type": { "$ref": "#/definitions/struct-type" } }, "required": [ "key", "name", "typeId" ] }, "function": { "title": "Thrift service function definition schema", "type": "object", "allOf": [ { "$ref": "#/definitions/name-and-doc" }, { "properties": { "oneway": { "type": "boolean" }, "returnType": { "$ref": "#/definitions/type-desc" }, "arguments": { "type": "array", "items": { "$ref": "#/definitions/field" } }, "exceptions": { "type": "array", "items": { "$ref": "#/definitions/exception" } } }, "required": [ "oneway", "arguments", "exceptions" ] } ] }, "service": { "title": "Thrift service definition schema", "type": "object", "allOf": [ { "$ref": "#/definitions/name-and-doc" }, { "properties": { "functions": { "type": "array", "items": { "$ref": "#/definitions/function" } } }, "required": [ "functions" ] } ] }, "annotations": { "title": "Map of annotation names to values", "type": "object", "additionalProperties": { "type": "string" } } }, "type": "object", "required": [ "name", "enums", "typedefs", "structs", "constants", "services" ], "properties": { "name": { "type": "string" }, "includes": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }, "namespaces": { "type": "object", "additionalProperties": { "type": "string" } }, "enums": { "type": "array", "items": { "$ref": "#/definitions/enum" } }, "typedefs": { "type": "array", "items": { "$ref": "#/definitions/typedef" } }, "structs": { "type": "array", "items": { "$ref": "#/definitions/struct" } }, "constants": { "type": "array", "items": { "$ref": "#/definitions/constant" } }, "services": { "type": "array", "items": { "$ref": "#/definitions/service" } } }, "additionalProperties": false } thrift-0.16.0/lib/json/test/000077500000000000000000000000001420101504100155605ustar00rootroot00000000000000thrift-0.16.0/lib/json/test/Makefile.am000066400000000000000000000017121420101504100176150ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # check: $(ANT) $(ANT_FLAGS) test # Make sure this doesn't fail if ant is not configured. clean-local: ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ $$ANT $(ANT_FLAGS) clean thrift-0.16.0/lib/json/test/build.properties000066400000000000000000000005071420101504100207770ustar00rootroot00000000000000# Jar versions mvn.ant.task.version=2.1.3 # Dependency versions json-schema-validator.version=2.2.6 # Maven dependency download locations mvn.repo=https://repo1.maven.org/maven2 mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version} mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar thrift-0.16.0/lib/json/test/build.xml000066400000000000000000000120641420101504100174040ustar00rootroot00000000000000 JSON Schema Validation Test Thrift compiler is missing ! thrift-0.16.0/lib/lua/000077500000000000000000000000001420101504100144115ustar00rootroot00000000000000thrift-0.16.0/lib/lua/Makefile.am000066400000000000000000000042001420101504100164410ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # AUTOMAKE_OPTIONS = subdir-objects nostdinc SUBDIRS = . lib_LTLIBRARIES = \ libluasocket.la \ liblualongnumber.la \ libluabpack.la \ libluabitwise.la libluasocket_la_SOURCES = \ src/luasocket.c \ src/usocket.c nobase_include_HEADERS = src/socket.h libluasocket_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE libluasocket_la_LDFLAGS = $(AM_LDFLAGS) libluasocket_la_LIBADD = $(LUA_LIB) -lm libluabpack_la_SOURCES = src/luabpack.c libluabpack_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE libluabpack_la_LDFLAGS = $(AM_LDFLAGS) libluabpack_la_LIBADD = liblualongnumber.la $(LUA_LIB) -lm libluabitwise_la_SOURCES = src/luabitwise.c libluabitwise_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE libluabitwise_la_LDFLAGS = $(AM_LDFLAGS) libluabitwise_la_LIBADD = $(LUA_LIB) -lm liblualongnumber_la_SOURCES = \ src/lualongnumber.c \ src/longnumberutils.c liblualongnumber_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE liblualongnumber_la_LDFLAGS = $(AM_LDFLAGS) liblualongnumber_la_LIBADD = $(LUA_LIB) -lm EXTRA_DIST = \ coding_standards.md \ TBinaryProtocol.lua \ TBufferedTransport.lua \ TCompactProtocol.lua \ TFramedTransport.lua \ Thrift.lua \ THttpTransport.lua \ TJsonProtocol.lua \ TMemoryBuffer.lua \ TProtocol.lua \ TServer.lua \ TSocket.lua \ TTransport.lua thrift-0.16.0/lib/lua/TBinaryProtocol.lua000066400000000000000000000137751420101504100202230ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TProtocol' require 'libluabpack' require 'libluabitwise' TBinaryProtocol = __TObject.new(TProtocolBase, { __type = 'TBinaryProtocol', VERSION_MASK = -65536, -- 0xffff0000 VERSION_1 = -2147418112, -- 0x80010000 TYPE_MASK = 0x000000ff, strictRead = false, strictWrite = true }) function TBinaryProtocol:writeMessageBegin(name, ttype, seqid) if self.strictWrite then self:writeI32(libluabitwise.bor(TBinaryProtocol.VERSION_1, ttype)) self:writeString(name) self:writeI32(seqid) else self:writeString(name) self:writeByte(ttype) self:writeI32(seqid) end end function TBinaryProtocol:writeMessageEnd() end function TBinaryProtocol:writeStructBegin(name) end function TBinaryProtocol:writeStructEnd() end function TBinaryProtocol:writeFieldBegin(name, ttype, id) self:writeByte(ttype) self:writeI16(id) end function TBinaryProtocol:writeFieldEnd() end function TBinaryProtocol:writeFieldStop() self:writeByte(TType.STOP); end function TBinaryProtocol:writeMapBegin(ktype, vtype, size) self:writeByte(ktype) self:writeByte(vtype) self:writeI32(size) end function TBinaryProtocol:writeMapEnd() end function TBinaryProtocol:writeListBegin(etype, size) self:writeByte(etype) self:writeI32(size) end function TBinaryProtocol:writeListEnd() end function TBinaryProtocol:writeSetBegin(etype, size) self:writeByte(etype) self:writeI32(size) end function TBinaryProtocol:writeSetEnd() end function TBinaryProtocol:writeBool(bool) if bool then self:writeByte(1) else self:writeByte(0) end end function TBinaryProtocol:writeByte(byte) local buff = libluabpack.bpack('c', byte) self.trans:write(buff) end function TBinaryProtocol:writeI16(i16) local buff = libluabpack.bpack('s', i16) self.trans:write(buff) end function TBinaryProtocol:writeI32(i32) local buff = libluabpack.bpack('i', i32) self.trans:write(buff) end function TBinaryProtocol:writeI64(i64) local buff = libluabpack.bpack('l', i64) self.trans:write(buff) end function TBinaryProtocol:writeDouble(dub) local buff = libluabpack.bpack('d', dub) self.trans:write(buff) end function TBinaryProtocol:writeString(str) -- Should be utf-8 self:writeI32(string.len(str)) self.trans:write(str) end function TBinaryProtocol:readMessageBegin() local sz, ttype, name, seqid = self:readI32() if sz < 0 then local version = libluabitwise.band(sz, TBinaryProtocol.VERSION_MASK) if version ~= TBinaryProtocol.VERSION_1 then terror(TProtocolException:new{ message = 'Bad version in readMessageBegin: ' .. sz }) end ttype = libluabitwise.band(sz, TBinaryProtocol.TYPE_MASK) name = self:readString() seqid = self:readI32() else if self.strictRead then terror(TProtocolException:new{message = 'No protocol version header'}) end name = self.trans:readAll(sz) ttype = self:readByte() seqid = self:readI32() end return name, ttype, seqid end function TBinaryProtocol:readMessageEnd() end function TBinaryProtocol:readStructBegin() return nil end function TBinaryProtocol:readStructEnd() end function TBinaryProtocol:readFieldBegin() local ttype = self:readByte() if ttype == TType.STOP then return nil, ttype, 0 end local id = self:readI16() return nil, ttype, id end function TBinaryProtocol:readFieldEnd() end function TBinaryProtocol:readMapBegin() local ktype = self:readByte() local vtype = self:readByte() local size = self:readI32() return ktype, vtype, size end function TBinaryProtocol:readMapEnd() end function TBinaryProtocol:readListBegin() local etype = self:readByte() local size = self:readI32() return etype, size end function TBinaryProtocol:readListEnd() end function TBinaryProtocol:readSetBegin() local etype = self:readByte() local size = self:readI32() return etype, size end function TBinaryProtocol:readSetEnd() end function TBinaryProtocol:readBool() local byte = self:readByte() if byte == 0 then return false end return true end function TBinaryProtocol:readByte() local buff = self.trans:readAll(1) local val = libluabpack.bunpack('c', buff) return val end function TBinaryProtocol:readI16() local buff = self.trans:readAll(2) local val = libluabpack.bunpack('s', buff) return val end function TBinaryProtocol:readI32() local buff = self.trans:readAll(4) local val = libluabpack.bunpack('i', buff) return val end function TBinaryProtocol:readI64() local buff = self.trans:readAll(8) local val = libluabpack.bunpack('l', buff) return val end function TBinaryProtocol:readDouble() local buff = self.trans:readAll(8) local val = libluabpack.bunpack('d', buff) return val end function TBinaryProtocol:readString() local len = self:readI32() local str = self.trans:readAll(len) return str end TBinaryProtocolFactory = TProtocolFactory:new{ __type = 'TBinaryProtocolFactory', strictRead = false } function TBinaryProtocolFactory:getProtocol(trans) -- TODO Enforce that this must be a transport class (ie not a bool) if not trans then terror(TProtocolException:new{ message = 'Must supply a transport to ' .. ttype(self) }) end return TBinaryProtocol:new{ trans = trans, strictRead = self.strictRead, strictWrite = true } end thrift-0.16.0/lib/lua/TBufferedTransport.lua000066400000000000000000000043661420101504100207100ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TTransport' TBufferedTransport = TTransportBase:new{ __type = 'TBufferedTransport', rBufSize = 2048, wBufSize = 2048, wBuf = '', rBuf = '' } function TBufferedTransport:new(obj) if ttype(obj) ~= 'table' then error(ttype(self) .. 'must be initialized with a table') end -- Ensure a transport is provided if not obj.trans then error('You must provide ' .. ttype(self) .. ' with a trans') end return TTransportBase.new(self, obj) end function TBufferedTransport:isOpen() return self.trans:isOpen() end function TBufferedTransport:open() return self.trans:open() end function TBufferedTransport:close() return self.trans:close() end function TBufferedTransport:read(len) return self.trans:read(len) end function TBufferedTransport:readAll(len) return self.trans:readAll(len) end function TBufferedTransport:write(buf) self.wBuf = self.wBuf .. buf if string.len(self.wBuf) >= self.wBufSize then self.trans:write(self.wBuf) self.wBuf = '' end end function TBufferedTransport:flush() if string.len(self.wBuf) > 0 then self.trans:write(self.wBuf) self.wBuf = '' end end TBufferedTransportFactory = TTransportFactoryBase:new{ __type = 'TBufferedTransportFactory' } function TBufferedTransportFactory:getTransport(trans) if not trans then terror(TTransportException:new{ message = 'Must supply a transport to ' .. ttype(self) }) end return TBufferedTransport:new{ trans = trans } end thrift-0.16.0/lib/lua/TCompactProtocol.lua000066400000000000000000000314741420101504100203610ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TProtocol' require 'libluabpack' require 'libluabitwise' require 'liblualongnumber' TCompactProtocol = __TObject.new(TProtocolBase, { __type = 'TCompactProtocol', COMPACT_PROTOCOL_ID = 0x82, COMPACT_VERSION = 1, COMPACT_VERSION_MASK = 0x1f, COMPACT_TYPE_MASK = 0xE0, COMPACT_TYPE_BITS = 0x07, COMPACT_TYPE_SHIFT_AMOUNT = 5, -- Used to keep track of the last field for the current and previous structs, -- so we can do the delta stuff. lastField = {}, lastFieldId = 0, lastFieldIndex = 1, -- If we encounter a boolean field begin, save the TField here so it can -- have the value incorporated. booleanFieldName = "", booleanFieldId = 0, booleanFieldPending = false, -- If we read a field header, and it's a boolean field, save the boolean -- value here so that readBool can use it. boolValue = false, boolValueIsNotNull = false, }) TCompactType = { COMPACT_BOOLEAN_TRUE = 0x01, COMPACT_BOOLEAN_FALSE = 0x02, COMPACT_BYTE = 0x03, COMPACT_I16 = 0x04, COMPACT_I32 = 0x05, COMPACT_I64 = 0x06, COMPACT_DOUBLE = 0x07, COMPACT_BINARY = 0x08, COMPACT_LIST = 0x09, COMPACT_SET = 0x0A, COMPACT_MAP = 0x0B, COMPACT_STRUCT = 0x0C } TTypeToCompactType = {} TTypeToCompactType[TType.STOP] = TType.STOP TTypeToCompactType[TType.BOOL] = TCompactType.COMPACT_BOOLEAN_TRUE TTypeToCompactType[TType.BYTE] = TCompactType.COMPACT_BYTE TTypeToCompactType[TType.I16] = TCompactType.COMPACT_I16 TTypeToCompactType[TType.I32] = TCompactType.COMPACT_I32 TTypeToCompactType[TType.I64] = TCompactType.COMPACT_I64 TTypeToCompactType[TType.DOUBLE] = TCompactType.COMPACT_DOUBLE TTypeToCompactType[TType.STRING] = TCompactType.COMPACT_BINARY TTypeToCompactType[TType.LIST] = TCompactType.COMPACT_LIST TTypeToCompactType[TType.SET] = TCompactType.COMPACT_SET TTypeToCompactType[TType.MAP] = TCompactType.COMPACT_MAP TTypeToCompactType[TType.STRUCT] = TCompactType.COMPACT_STRUCT CompactTypeToTType = {} CompactTypeToTType[TType.STOP] = TType.STOP CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_TRUE] = TType.BOOL CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_FALSE] = TType.BOOL CompactTypeToTType[TCompactType.COMPACT_BYTE] = TType.BYTE CompactTypeToTType[TCompactType.COMPACT_I16] = TType.I16 CompactTypeToTType[TCompactType.COMPACT_I32] = TType.I32 CompactTypeToTType[TCompactType.COMPACT_I64] = TType.I64 CompactTypeToTType[TCompactType.COMPACT_DOUBLE] = TType.DOUBLE CompactTypeToTType[TCompactType.COMPACT_BINARY] = TType.STRING CompactTypeToTType[TCompactType.COMPACT_LIST] = TType.LIST CompactTypeToTType[TCompactType.COMPACT_SET] = TType.SET CompactTypeToTType[TCompactType.COMPACT_MAP] = TType.MAP CompactTypeToTType[TCompactType.COMPACT_STRUCT] = TType.STRUCT function TCompactProtocol:resetLastField() self.lastField = {} self.lastFieldId = 0 self.lastFieldIndex = 1 end function TCompactProtocol:packCompactType(ktype, vtype) return libluabitwise.bor(libluabitwise.shiftl(ktype, 4), vtype) end function TCompactProtocol:writeMessageBegin(name, ttype, seqid) self:writeByte(TCompactProtocol.COMPACT_PROTOCOL_ID) self:writeByte(libluabpack.packMesgType(TCompactProtocol.COMPACT_VERSION, TCompactProtocol.COMPACT_VERSION_MASK,ttype, TCompactProtocol.COMPACT_TYPE_SHIFT_AMOUNT, TCompactProtocol.COMPACT_TYPE_MASK)) self:writeVarint32(seqid) self:writeString(name) self:resetLastField() end function TCompactProtocol:writeMessageEnd() end function TCompactProtocol:writeStructBegin(name) self.lastField[self.lastFieldIndex] = self.lastFieldId self.lastFieldIndex = self.lastFieldIndex + 1 self.lastFieldId = 0 end function TCompactProtocol:writeStructEnd() self.lastFieldIndex = self.lastFieldIndex - 1 self.lastFieldId = self.lastField[self.lastFieldIndex] end function TCompactProtocol:writeFieldBegin(name, ttype, id) if ttype == TType.BOOL then self.booleanFieldName = name self.booleanFieldId = id self.booleanFieldPending = true else self:writeFieldBeginInternal(name, ttype, id, -1) end end function TCompactProtocol:writeFieldEnd() end function TCompactProtocol:writeFieldStop() self:writeByte(TType.STOP); end function TCompactProtocol:writeMapBegin(ktype, vtype, size) if size == 0 then self:writeByte(0) else self:writeVarint32(size) self:writeByte(self:packCompactType(TTypeToCompactType[ktype], TTypeToCompactType[vtype])) end end function TCompactProtocol:writeMapEnd() end function TCompactProtocol:writeListBegin(etype, size) self:writeCollectionBegin(etype, size) end function TCompactProtocol:writeListEnd() end function TCompactProtocol:writeSetBegin(etype, size) self:writeCollectionBegin(etype, size) end function TCompactProtocol:writeSetEnd() end function TCompactProtocol:writeBool(bool) local value = TCompactType.COMPACT_BOOLEAN_FALSE if bool then value = TCompactType.COMPACT_BOOLEAN_TRUE end if self.booleanFieldPending then self:writeFieldBeginInternal(self.booleanFieldName, TType.BOOL, self.booleanFieldId, value) self.booleanFieldPending = false else self:writeByte(value) end end function TCompactProtocol:writeByte(byte) local buff = libluabpack.bpack('c', byte) self.trans:write(buff) end function TCompactProtocol:writeI16(i16) self:writeVarint32(libluabpack.i32ToZigzag(i16)) end function TCompactProtocol:writeI32(i32) self:writeVarint32(libluabpack.i32ToZigzag(i32)) end function TCompactProtocol:writeI64(i64) self:writeVarint64(libluabpack.i64ToZigzag(i64)) end function TCompactProtocol:writeDouble(dub) local buff = libluabpack.bpack('d', dub) self.trans:write(buff) end function TCompactProtocol:writeString(str) -- Should be utf-8 self:writeBinary(str) end function TCompactProtocol:writeBinary(str) -- Should be utf-8 self:writeVarint32(string.len(str)) self.trans:write(str) end function TCompactProtocol:writeFieldBeginInternal(name, ttype, id, typeOverride) if typeOverride == -1 then typeOverride = TTypeToCompactType[ttype] end local offset = id - self.lastFieldId if id > self.lastFieldId and offset <= 15 then self:writeByte(libluabitwise.bor(libluabitwise.shiftl(offset, 4), typeOverride)) else self:writeByte(typeOverride) self:writeI16(id) end self.lastFieldId = id end function TCompactProtocol:writeCollectionBegin(etype, size) if size <= 14 then self:writeByte(libluabitwise.bor(libluabitwise.shiftl(size, 4), TTypeToCompactType[etype])) else self:writeByte(libluabitwise.bor(0xf0, TTypeToCompactType[etype])) self:writeVarint32(size) end end function TCompactProtocol:writeVarint32(i32) -- Should be utf-8 local str = libluabpack.toVarint32(i32) self.trans:write(str) end function TCompactProtocol:writeVarint64(i64) -- Should be utf-8 local str = libluabpack.toVarint64(i64) self.trans:write(str) end function TCompactProtocol:readMessageBegin() local protocolId = self:readSignByte() if protocolId ~= self.COMPACT_PROTOCOL_ID then terror(TProtocolException:new{ message = "Expected protocol id " .. self.COMPACT_PROTOCOL_ID .. " but got " .. protocolId}) end local versionAndType = self:readSignByte() local version = libluabitwise.band(versionAndType, self.COMPACT_VERSION_MASK) local ttype = libluabitwise.band(libluabitwise.shiftr(versionAndType, self.COMPACT_TYPE_SHIFT_AMOUNT), self.COMPACT_TYPE_BITS) if version ~= self.COMPACT_VERSION then terror(TProtocolException:new{ message = "Expected version " .. self.COMPACT_VERSION .. " but got " .. version}) end local seqid = self:readVarint32() local name = self:readString() return name, ttype, seqid end function TCompactProtocol:readMessageEnd() end function TCompactProtocol:readStructBegin() self.lastField[self.lastFieldIndex] = self.lastFieldId self.lastFieldIndex = self.lastFieldIndex + 1 self.lastFieldId = 0 return nil end function TCompactProtocol:readStructEnd() self.lastFieldIndex = self.lastFieldIndex - 1 self.lastFieldId = self.lastField[self.lastFieldIndex] end function TCompactProtocol:readFieldBegin() local field_and_ttype = self:readSignByte() local ttype = self:getTType(field_and_ttype) if ttype == TType.STOP then return nil, ttype, 0 end local modifier = libluabitwise.shiftr(field_and_ttype, 4) local id = 0 if modifier == 0 then id = self:readI16() else id = self.lastFieldId + modifier end local type = libluabitwise.band(field_and_ttype, 0x0f) if type == TCompactType.COMPACT_BOOLEAN_TRUE then self.boolValue = true self.boolValueIsNotNull = true elseif type == TCompactType.COMPACT_BOOLEAN_FALSE then self.boolValue = false self.boolValueIsNotNull = true end self.lastFieldId = id return nil, ttype, id end function TCompactProtocol:readFieldEnd() end function TCompactProtocol:readMapBegin() local size = self:readVarint32() local kvtype = 0 if size > 0 then kvtype = self:readSignByte() end local ktype = self:getTType(libluabitwise.shiftr(kvtype, 4)) local vtype = self:getTType(kvtype) return ktype, vtype, size end function TCompactProtocol:readMapEnd() end function TCompactProtocol:readListBegin() local size_and_type = self:readSignByte() local size = libluabitwise.band(libluabitwise.shiftr(size_and_type, 4), 0x0f) if size == 15 then size = self:readVarint32() end if size < 0 then return nil,nil end local etype = self:getTType(libluabitwise.band(size_and_type, 0x0f)) return etype, size end function TCompactProtocol:readListEnd() end function TCompactProtocol:readSetBegin() return self:readListBegin() end function TCompactProtocol:readSetEnd() end function TCompactProtocol:readBool() if self.boolValueIsNotNull then self.boolValueIsNotNull = false return self.boolValue end local val = self:readSignByte() if val == TCompactType.COMPACT_BOOLEAN_TRUE then return true end return false end function TCompactProtocol:readByte() local buff = self.trans:readAll(1) local val = libluabpack.bunpack('c', buff) return val end function TCompactProtocol:readSignByte() local buff = self.trans:readAll(1) local val = libluabpack.bunpack('C', buff) return val end function TCompactProtocol:readI16() return self:readI32() end function TCompactProtocol:readI32() local v = self:readVarint32() local value = libluabpack.zigzagToI32(v) return value end function TCompactProtocol:readI64() local value = self:readVarint64() return value end function TCompactProtocol:readDouble() local buff = self.trans:readAll(8) local val = libluabpack.bunpack('d', buff) return val end function TCompactProtocol:readString() return self:readBinary() end function TCompactProtocol:readBinary() local size = self:readVarint32() if size <= 0 then return "" end return self.trans:readAll(size) end function TCompactProtocol:readVarint32() local shiftl = 0 local result = 0 while true do b = self:readByte() result = libluabitwise.bor(result, libluabitwise.shiftl(libluabitwise.band(b, 0x7f), shiftl)) if libluabitwise.band(b, 0x80) ~= 0x80 then break end shiftl = shiftl + 7 end return result end function TCompactProtocol:readVarint64() local result = liblualongnumber.new local data = result(0) local shiftl = 0 while true do b = self:readSignByte() endFlag, data = libluabpack.fromVarint64(b, shiftl, data) shiftl = shiftl + 7 if endFlag == 0 then break end end return data end function TCompactProtocol:getTType(ctype) return CompactTypeToTType[libluabitwise.band(ctype, 0x0f)] end TCompactProtocolFactory = TProtocolFactory:new{ __type = 'TCompactProtocolFactory', } function TCompactProtocolFactory:getProtocol(trans) -- TODO Enforce that this must be a transport class (ie not a bool) if not trans then terror(TProtocolException:new{ message = 'Must supply a transport to ' .. ttype(self) }) end return TCompactProtocol:new{ trans = trans } end thrift-0.16.0/lib/lua/TFramedTransport.lua000066400000000000000000000056101420101504100203550ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TTransport' require 'libluabpack' TFramedTransport = TTransportBase:new{ __type = 'TFramedTransport', doRead = true, doWrite = true, wBuf = '', rBuf = '' } function TFramedTransport:new(obj) if ttype(obj) ~= 'table' then error(ttype(self) .. 'must be initialized with a table') end -- Ensure a transport is provided if not obj.trans then error('You must provide ' .. ttype(self) .. ' with a trans') end return TTransportBase.new(self, obj) end function TFramedTransport:isOpen() return self.trans:isOpen() end function TFramedTransport:open() return self.trans:open() end function TFramedTransport:close() return self.trans:close() end function TFramedTransport:read(len) if string.len(self.rBuf) == 0 then self:__readFrame() end if self.doRead == false then return self.trans:read(len) end if len > string.len(self.rBuf) then local val = self.rBuf self.rBuf = '' return val end local val = string.sub(self.rBuf, 0, len) self.rBuf = string.sub(self.rBuf, len+1) return val end function TFramedTransport:__readFrame() local buf = self.trans:readAll(4) local frame_len = libluabpack.bunpack('i', buf) self.rBuf = self.trans:readAll(frame_len) end function TFramedTransport:write(buf, len) if self.doWrite == false then return self.trans:write(buf, len) end if len and len < string.len(buf) then buf = string.sub(buf, 0, len) end self.wBuf = self.wBuf .. buf end function TFramedTransport:flush() if self.doWrite == false then return self.trans:flush() end -- If the write fails we still want wBuf to be clear local tmp = self.wBuf self.wBuf = '' local frame_len_buf = libluabpack.bpack("i", string.len(tmp)) tmp = frame_len_buf .. tmp self.trans:write(tmp) self.trans:flush() end TFramedTransportFactory = TTransportFactoryBase:new{ __type = 'TFramedTransportFactory' } function TFramedTransportFactory:getTransport(trans) if not trans then terror(TProtocolException:new{ message = 'Must supply a transport to ' .. ttype(self) }) end return TFramedTransport:new{trans = trans} end thrift-0.16.0/lib/lua/THttpTransport.lua000066400000000000000000000112151420101504100200740ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TTransport' THttpTransport = TTransportBase:new{ __type = 'THttpTransport', path = '/', wBuf = '', rBuf = '', CRLF = '\r\n', VERSION = version, isServer = true } function THttpTransport:new(obj) if ttype(obj) ~= 'table' then error(ttype(self) .. 'must be initialized with a table') end -- Ensure a transport is provided if not obj.trans then error('You must provide ' .. ttype(self) .. ' with a trans') end return TTransportBase.new(self, obj) end function THttpTransport:isOpen() return self.trans:isOpen() end function THttpTransport:open() return self.trans:open() end function THttpTransport:close() return self.trans:close() end function THttpTransport:readAll(len) return self:read(len) end function THttpTransport:read(len) if string.len(self.rBuf) == 0 then self:_readMsg() end if len > string.len(self.rBuf) then local val = self.rBuf self.rBuf = '' return val end local val = string.sub(self.rBuf, 0, len) self.rBuf = string.sub(self.rBuf, len+1) return val end function THttpTransport:_readMsg() while true do self.rBuf = self.rBuf .. self.trans:read(4) if string.find(self.rBuf, self.CRLF .. self.CRLF) then break end end if not self.rBuf then self.rBuf = "" return end self:getLine() local headers = self:_parseHeaders() if not headers then self.rBuf = "" return end local length = tonumber(headers["Content-Length"]) if length then length = length - string.len(self.rBuf) self.rBuf = self.rBuf .. self.trans:readAll(length) end if self.rBuf == nil then self.rBuf = "" end end function THttpTransport:getLine() local a,b = string.find(self.rBuf, self.CRLF) local line = "" if a and b then line = string.sub(self.rBuf, 0, a-1) self.rBuf = string.sub(self.rBuf, b+1) end return line end function THttpTransport:_parseHeaders() local headers = {} repeat local line = self:getLine() for key, val in string.gmatch(line, "([%w%-]+)%s*:%s*(.+)") do if headers[key] then local delimiter = ", " if key == "Set-Cookie" then delimiter = "; " end headers[key] = headers[key] .. delimiter .. tostring(val) else headers[key] = tostring(val) end end until string.find(line, "^%s*$") return headers end function THttpTransport:write(buf, len) if len and len < string.len(buf) then buf = string.sub(buf, 0, len) end self.wBuf = self.wBuf .. buf end function THttpTransport:writeHttpHeader(content_len) if self.isServer then local header = "HTTP/1.1 200 OK" .. self.CRLF .. "Server: Thrift/" .. self.VERSION .. self.CRLF .. "Access-Control-Allow-Origin: *" .. self.CRLF .. "Content-Type: application/x-thrift" .. self.CRLF .. "Content-Length: " .. content_len .. self.CRLF .. "Connection: Keep-Alive" .. self.CRLF .. self.CRLF self.trans:write(header) else local header = "POST " .. self.path .. " HTTP/1.1" .. self.CRLF .. "Host: " .. self.trans.host .. self.CRLF .. "Content-Type: application/x-thrift" .. self.CRLF .. "Content-Length: " .. content_len .. self.CRLF .. "Accept: application/x-thrift " .. self.CRLF .. "User-Agent: Thrift/" .. self.VERSION .. " (Lua/THttpClient)" .. self.CRLF .. self.CRLF self.trans:write(header) end end function THttpTransport:flush() -- If the write fails we still want wBuf to be clear local tmp = self.wBuf self.wBuf = '' self:writeHttpHeader(string.len(tmp)) self.trans:write(tmp) self.trans:flush() end THttpTransportFactory = TTransportFactoryBase:new{ __type = 'THttpTransportFactory' } function THttpTransportFactory:getTransport(trans) if not trans then terror(TProtocolException:new{ message = 'Must supply a transport to ' .. ttype(self) }) end return THttpTransport:new{trans = trans} end thrift-0.16.0/lib/lua/TJsonProtocol.lua000066400000000000000000000443401420101504100177000ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"), you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TProtocol' require 'libluabpack' require 'libluabitwise' TJSONProtocol = __TObject.new(TProtocolBase, { __type = 'TJSONProtocol', THRIFT_JSON_PROTOCOL_VERSION = 1, jsonContext = {}, jsonContextVal = {first = true, colon = true, ttype = 2, null = true}, jsonContextIndex = 1, hasReadByte = "" }) TTypeToString = {} TTypeToString[TType.BOOL] = "tf" TTypeToString[TType.BYTE] = "i8" TTypeToString[TType.I16] = "i16" TTypeToString[TType.I32] = "i32" TTypeToString[TType.I64] = "i64" TTypeToString[TType.DOUBLE] = "dbl" TTypeToString[TType.STRING] = "str" TTypeToString[TType.STRUCT] = "rec" TTypeToString[TType.LIST] = "lst" TTypeToString[TType.SET] = "set" TTypeToString[TType.MAP] = "map" StringToTType = { tf = TType.BOOL, i8 = TType.BYTE, i16 = TType.I16, i32 = TType.I32, i64 = TType.I64, dbl = TType.DOUBLE, str = TType.STRING, rec = TType.STRUCT, map = TType.MAP, set = TType.SET, lst = TType.LIST } JSONNode = { ObjectBegin = '{', ObjectEnd = '}', ArrayBegin = '[', ArrayEnd = ']', PairSeparator = ':', ElemSeparator = ',', Backslash = '\\', StringDelimiter = '"', ZeroChar = '0', EscapeChar = 'u', Nan = 'NaN', Infinity = 'Infinity', NegativeInfinity = '-Infinity', EscapeChars = "\"\\bfnrt", EscapePrefix = "\\u00" } EscapeCharVals = { '"', '\\', '\b', '\f', '\n', '\r', '\t' } JSONCharTable = { --0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 0, 0, 0, 0, 0, 0, 0, 98,116,110, 0,102,114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, } -- character table string local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- encoding function base64_encode(data) return ((data:gsub('.', function(x) local r,b='',x:byte() for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end return r; end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) if (#x < 6) then return '' end local c=0 for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end return b:sub(c+1,c+1) end)..({ '', '==', '=' })[#data%3+1]) end -- decoding function base64_decode(data) data = string.gsub(data, '[^'..b..'=]', '') return (data:gsub('.', function(x) if (x == '=') then return '' end local r,f='',(b:find(x)-1) for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end return r; end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x) if (#x ~= 8) then return '' end local c=0 for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end return string.char(c) end)) end function TJSONProtocol:resetContext() self.jsonContext = {} self.jsonContextVal = {first = true, colon = true, ttype = 2, null = true} self.jsonContextIndex = 1 end function TJSONProtocol:contextPush(context) self.jsonContextIndex = self.jsonContextIndex + 1 self.jsonContext[self.jsonContextIndex] = self.jsonContextVal self.jsonContextVal = context end function TJSONProtocol:contextPop() self.jsonContextVal = self.jsonContext[self.jsonContextIndex] self.jsonContextIndex = self.jsonContextIndex - 1 end function TJSONProtocol:escapeNum() if self.jsonContextVal.ttype == 1 then return self.jsonContextVal.colon else return false end end function TJSONProtocol:writeElemSeparator() if self.jsonContextVal.null then return end if self.jsonContextVal.first then self.jsonContextVal.first = false else if self.jsonContextVal.ttype == 1 then if self.jsonContextVal.colon then self.trans:write(JSONNode.PairSeparator) self.jsonContextVal.colon = false else self.trans:write(JSONNode.ElemSeparator) self.jsonContextVal.colon = true end else self.trans:write(JSONNode.ElemSeparator) end end end function TJSONProtocol:hexChar(val) val = libluabitwise.band(val, 0x0f) if val < 10 then return val + 48 else return val + 87 end end function TJSONProtocol:writeJSONEscapeChar(ch) self.trans:write(JSONNode.EscapePrefix) local outCh = hexChar(libluabitwise.shiftr(ch, 4)) local buff = libluabpack.bpack('c', outCh) self.trans:write(buff) outCh = hexChar(ch) buff = libluabpack.bpack('c', outCh) self.trans:write(buff) end function TJSONProtocol:writeJSONChar(byte) ch = string.byte(byte) if ch >= 0x30 then if ch == JSONNode.Backslash then self.trans:write(JSONNode.Backslash) self.trans:write(JSONNode.Backslash) else self.trans:write(byte) end else local outCh = JSONCharTable[ch+1] if outCh == 1 then self.trans:write(byte) elseif outCh > 1 then self.trans:write(JSONNode.Backslash) local buff = libluabpack.bpack('c', outCh) self.trans:write(buff) else self:writeJSONEscapeChar(ch) end end end function TJSONProtocol:writeJSONString(str) self:writeElemSeparator() self.trans:write(JSONNode.StringDelimiter) -- TODO escape special characters local length = string.len(str) local ii = 1 while ii <= length do self:writeJSONChar(string.sub(str, ii, ii)) ii = ii + 1 end self.trans:write(JSONNode.StringDelimiter) end function TJSONProtocol:writeJSONBase64(str) self:writeElemSeparator() self.trans:write(JSONNode.StringDelimiter) local length = string.len(str) local offset = 1 while length >= 3 do -- Encode 3 bytes at a time local bytes = base64_encode(string.sub(str, offset, offset+3)) self.trans:write(bytes) length = length - 3 offset = offset + 3 end if length > 0 then local bytes = base64_encode(string.sub(str, offset, offset+length)) self.trans:write(bytes) end self.trans:write(JSONNode.StringDelimiter) end function TJSONProtocol:writeJSONInteger(num) self:writeElemSeparator() if self:escapeNum() then self.trans:write(JSONNode.StringDelimiter) end local numstr = "" .. num numstr = string.sub(numstr, string.find(numstr, "^[+-]?%d+")) self.trans:write(numstr) if self:escapeNum() then self.trans:write(JSONNode.StringDelimiter) end end function TJSONProtocol:writeJSONDouble(dub) self:writeElemSeparator() local val = "" .. dub local prefix = string.sub(val, 1, 1) local special = false if prefix == 'N' or prefix == 'n' then val = JSONNode.Nan special = true elseif prefix == 'I' or prefix == 'i' then val = JSONNode.Infinity special = true elseif prefix == '-' then local secondByte = string.sub(val, 2, 2) if secondByte == 'I' or secondByte == 'i' then val = JSONNode.NegativeInfinity special = true end end if special or self:escapeNum() then self.trans:write(JSONNode.StringDelimiter) end self.trans:write(val) if special or self:escapeNum() then self.trans:write(JSONNode.StringDelimiter) end end function TJSONProtocol:writeJSONObjectBegin() self:writeElemSeparator() self.trans:write(JSONNode.ObjectBegin) self:contextPush({first = true, colon = true, ttype = 1, null = false}) end function TJSONProtocol:writeJSONObjectEnd() self:contextPop() self.trans:write(JSONNode.ObjectEnd) end function TJSONProtocol:writeJSONArrayBegin() self:writeElemSeparator() self.trans:write(JSONNode.ArrayBegin) self:contextPush({first = true, colon = true, ttype = 2, null = false}) end function TJSONProtocol:writeJSONArrayEnd() self:contextPop() self.trans:write(JSONNode.ArrayEnd) end function TJSONProtocol:writeMessageBegin(name, ttype, seqid) self:resetContext() self:writeJSONArrayBegin() self:writeJSONInteger(TJSONProtocol.THRIFT_JSON_PROTOCOL_VERSION) self:writeJSONString(name) self:writeJSONInteger(ttype) self:writeJSONInteger(seqid) end function TJSONProtocol:writeMessageEnd() self:writeJSONArrayEnd() end function TJSONProtocol:writeStructBegin(name) self:writeJSONObjectBegin() end function TJSONProtocol:writeStructEnd() self:writeJSONObjectEnd() end function TJSONProtocol:writeFieldBegin(name, ttype, id) self:writeJSONInteger(id) self:writeJSONObjectBegin() self:writeJSONString(TTypeToString[ttype]) end function TJSONProtocol:writeFieldEnd() self:writeJSONObjectEnd() end function TJSONProtocol:writeFieldStop() end function TJSONProtocol:writeMapBegin(ktype, vtype, size) self:writeJSONArrayBegin() self:writeJSONString(TTypeToString[ktype]) self:writeJSONString(TTypeToString[vtype]) self:writeJSONInteger(size) return self:writeJSONObjectBegin() end function TJSONProtocol:writeMapEnd() self:writeJSONObjectEnd() self:writeJSONArrayEnd() end function TJSONProtocol:writeListBegin(etype, size) self:writeJSONArrayBegin() self:writeJSONString(TTypeToString[etype]) self:writeJSONInteger(size) end function TJSONProtocol:writeListEnd() self:writeJSONArrayEnd() end function TJSONProtocol:writeSetBegin(etype, size) self:writeJSONArrayBegin() self:writeJSONString(TTypeToString[etype]) self:writeJSONInteger(size) end function TJSONProtocol:writeSetEnd() self:writeJSONArrayEnd() end function TJSONProtocol:writeBool(bool) if bool then self:writeJSONInteger(1) else self:writeJSONInteger(0) end end function TJSONProtocol:writeByte(byte) local buff = libluabpack.bpack('c', byte) local val = libluabpack.bunpack('c', buff) self:writeJSONInteger(val) end function TJSONProtocol:writeI16(i16) local buff = libluabpack.bpack('s', i16) local val = libluabpack.bunpack('s', buff) self:writeJSONInteger(val) end function TJSONProtocol:writeI32(i32) local buff = libluabpack.bpack('i', i32) local val = libluabpack.bunpack('i', buff) self:writeJSONInteger(val) end function TJSONProtocol:writeI64(i64) local buff = libluabpack.bpack('l', i64) local val = libluabpack.bunpack('l', buff) self:writeJSONInteger(tostring(val)) end function TJSONProtocol:writeDouble(dub) self:writeJSONDouble(string.format("%.16f", dub)) end function TJSONProtocol:writeString(str) self:writeJSONString(str) end function TJSONProtocol:writeBinary(str) -- Should be utf-8 self:writeJSONBase64(str) end function TJSONProtocol:readJSONSyntaxChar(ch) local ch2 = "" if self.hasReadByte ~= "" then ch2 = self.hasReadByte self.hasReadByte = "" else ch2 = self.trans:readAll(1) end if ch2 ~= ch then terror(TProtocolException:new{message = "Expected ".. ch .. ", got " .. ch2}) end end function TJSONProtocol:readElemSeparator() if self.jsonContextVal.null then return end if self.jsonContextVal.first then self.jsonContextVal.first = false else if self.jsonContextVal.ttype == 1 then if self.jsonContextVal.colon then self:readJSONSyntaxChar(JSONNode.PairSeparator) self.jsonContextVal.colon = false else self:readJSONSyntaxChar(JSONNode.ElemSeparator) self.jsonContextVal.colon = true end else self:readJSONSyntaxChar(JSONNode.ElemSeparator) end end end function TJSONProtocol:hexVal(ch) local val = string.byte(ch) if val >= 48 and val <= 57 then return val - 48 elseif val >= 97 and val <= 102 then return val - 87 else terror(TProtocolException:new{message = "Expected hex val ([0-9a-f]); got " .. ch}) end end function TJSONProtocol:readJSONEscapeChar(ch) self:readJSONSyntaxChar(JSONNode.ZeroChar) self:readJSONSyntaxChar(JSONNode.ZeroChar) local b1 = self.trans:readAll(1) local b2 = self.trans:readAll(1) return libluabitwise.shiftl(self:hexVal(b1), 4) + self:hexVal(b2) end function TJSONProtocol:readJSONString() self:readElemSeparator() self:readJSONSyntaxChar(JSONNode.StringDelimiter) local result = "" while true do local ch = self.trans:readAll(1) if ch == JSONNode.StringDelimiter then break end if ch == JSONNode.Backslash then ch = self.trans:readAll(1) if ch == JSONNode.EscapeChar then self:readJSONEscapeChar(ch) else local pos, _ = string.find(JSONNode.EscapeChars, ch) if pos == nil then terror(TProtocolException:new{message = "Expected control char, got " .. ch}) end ch = EscapeCharVals[pos] end end result = result .. ch end return result end function TJSONProtocol:readJSONBase64() local result = self:readJSONString() local length = string.len(result) local str = "" local offset = 1 while length >= 4 do local bytes = string.sub(result, offset, offset+4) str = str .. base64_decode(bytes) offset = offset + 4 length = length - 4 end if length >= 0 then str = str .. base64_decode(string.sub(result, offset, offset + length)) end return str end function TJSONProtocol:readJSONNumericChars() local result = "" while true do local ch = self.trans:readAll(1) if string.find(ch, '[-+0-9.Ee]') then result = result .. ch else self.hasReadByte = ch break end end return result end function TJSONProtocol:readJSONLongInteger() self:readElemSeparator() if self:escapeNum() then self:readJSONSyntaxChar(JSONNode.StringDelimiter) end local result = self:readJSONNumericChars() if self:escapeNum() then self:readJSONSyntaxChar(JSONNode.StringDelimiter) end return result end function TJSONProtocol:readJSONInteger() return tonumber(self:readJSONLongInteger()) end function TJSONProtocol:readJSONDouble() self:readElemSeparator() local delimiter = self.trans:readAll(1) local num = 0.0 if delimiter == JSONNode.StringDelimiter then local str = self:readJSONString() if str == JSONNode.Nan then num = 1.0 elseif str == JSONNode.Infinity then num = math.maxinteger elseif str == JSONNode.NegativeInfinity then num = math.mininteger else num = tonumber(str) end else if self:escapeNum() then self:readJSONSyntaxChar(JSONNode.StringDelimiter) end local result = self:readJSONNumericChars() num = tonumber(delimiter.. result) end return num end function TJSONProtocol:readJSONObjectBegin() self:readElemSeparator() self:readJSONSyntaxChar(JSONNode.ObjectBegin) self:contextPush({first = true, colon = true, ttype = 1, null = false}) end function TJSONProtocol:readJSONObjectEnd() self:readJSONSyntaxChar(JSONNode.ObjectEnd) self:contextPop() end function TJSONProtocol:readJSONArrayBegin() self:readElemSeparator() self:readJSONSyntaxChar(JSONNode.ArrayBegin) self:contextPush({first = true, colon = true, ttype = 2, null = false}) end function TJSONProtocol:readJSONArrayEnd() self:readJSONSyntaxChar(JSONNode.ArrayEnd) self:contextPop() end function TJSONProtocol:readMessageBegin() self:resetContext() self:readJSONArrayBegin() local version = self:readJSONInteger() if version ~= self.THRIFT_JSON_PROTOCOL_VERSION then terror(TProtocolException:new{message = "Message contained bad version."}) end local name = self:readJSONString() local ttype = self:readJSONInteger() local seqid = self:readJSONInteger() return name, ttype, seqid end function TJSONProtocol:readMessageEnd() self:readJSONArrayEnd() end function TJSONProtocol:readStructBegin() self:readJSONObjectBegin() return nil end function TJSONProtocol:readStructEnd() self:readJSONObjectEnd() end function TJSONProtocol:readFieldBegin() local ttype = TType.STOP local id = 0 local ch = self.trans:readAll(1) self.hasReadByte = ch if ch ~= JSONNode.ObjectEnd then id = self:readJSONInteger() self:readJSONObjectBegin() local typeName = self:readJSONString() ttype = StringToTType[typeName] end return nil, ttype, id end function TJSONProtocol:readFieldEnd() self:readJSONObjectEnd() end function TJSONProtocol:readMapBegin() self:readJSONArrayBegin() local typeName = self:readJSONString() local ktype = StringToTType[typeName] typeName = self:readJSONString() local vtype = StringToTType[typeName] local size = self:readJSONInteger() self:readJSONObjectBegin() return ktype, vtype, size end function TJSONProtocol:readMapEnd() self:readJSONObjectEnd() self:readJSONArrayEnd() end function TJSONProtocol:readListBegin() self:readJSONArrayBegin() local typeName = self:readJSONString() local etype = StringToTType[typeName] local size = self:readJSONInteger() return etype, size end function TJSONProtocol:readListEnd() return self:readJSONArrayEnd() end function TJSONProtocol:readSetBegin() return self:readListBegin() end function TJSONProtocol:readSetEnd() return self:readJSONArrayEnd() end function TJSONProtocol:readBool() local result = self:readJSONInteger() if result == 1 then return true else return false end end function TJSONProtocol:readByte() local result = self:readJSONInteger() if result >= 256 then terror(TProtocolException:new{message = "UnExpected Byte " .. result}) end return result end function TJSONProtocol:readI16() return self:readJSONInteger() end function TJSONProtocol:readI32() return self:readJSONInteger() end function TJSONProtocol:readI64() local long = liblualongnumber.new return long(self:readJSONLongInteger()) end function TJSONProtocol:readDouble() return self:readJSONDouble() end function TJSONProtocol:readString() return self:readJSONString() end function TJSONProtocol:readBinary() return self:readJSONBase64() end TJSONProtocolFactory = TProtocolFactory:new{ __type = 'TJSONProtocolFactory', } function TJSONProtocolFactory:getProtocol(trans) -- TODO Enforce that this must be a transport class (ie not a bool) if not trans then terror(TProtocolException:new{ message = 'Must supply a transport to ' .. ttype(self) }) end return TJSONProtocol:new{ trans = trans } end thrift-0.16.0/lib/lua/TMemoryBuffer.lua000066400000000000000000000043321420101504100176440ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TTransport' TMemoryBuffer = TTransportBase:new{ __type = 'TMemoryBuffer', buffer = '', bufferSize = 1024, wPos = 0, rPos = 0 } function TMemoryBuffer:isOpen() return 1 end function TMemoryBuffer:open() end function TMemoryBuffer:close() end function TMemoryBuffer:peak() return self.rPos < self.wPos end function TMemoryBuffer:getBuffer() return self.buffer end function TMemoryBuffer:resetBuffer(buf) if buf then self.buffer = buf self.bufferSize = string.len(buf) else self.buffer = '' self.bufferSize = 1024 end self.wPos = string.len(buf) self.rPos = 0 end function TMemoryBuffer:available() return self.wPos - self.rPos end function TMemoryBuffer:read(len) local avail = self:available() if avail == 0 then return '' end if avail < len then len = avail end local val = string.sub(self.buffer, self.rPos + 1, self.rPos + len) self.rPos = self.rPos + len return val end function TMemoryBuffer:readAll(len) local avail = self:available() if avail < len then local msg = string.format('Attempt to readAll(%d) found only %d available', len, avail) terror(TTransportException:new{message = msg}) end -- read should block so we don't need a loop here return self:read(len) end function TMemoryBuffer:write(buf) self.buffer = self.buffer .. buf self.wPos = self.wPos + string.len(buf) end function TMemoryBuffer:flush() end thrift-0.16.0/lib/lua/TProtocol.lua000066400000000000000000000120431420101504100170410ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'Thrift' TProtocolException = TException:new { UNKNOWN = 0, INVALID_DATA = 1, NEGATIVE_SIZE = 2, SIZE_LIMIT = 3, BAD_VERSION = 4, INVALID_PROTOCOL = 5, DEPTH_LIMIT = 6, errorCode = 0, __type = 'TProtocolException' } function TProtocolException:__errorCodeToString() if self.errorCode == self.INVALID_DATA then return 'Invalid data' elseif self.errorCode == self.NEGATIVE_SIZE then return 'Negative size' elseif self.errorCode == self.SIZE_LIMIT then return 'Size limit' elseif self.errorCode == self.BAD_VERSION then return 'Bad version' elseif self.errorCode == self.INVALID_PROTOCOL then return 'Invalid protocol' elseif self.errorCode == self.DEPTH_LIMIT then return 'Exceeded size limit' else return 'Default (unknown)' end end TProtocolBase = __TObject:new{ __type = 'TProtocolBase', trans } function TProtocolBase:new(obj) if ttype(obj) ~= 'table' then error(ttype(self) .. 'must be initialized with a table') end -- Ensure a transport is provided if not obj.trans then error('You must provide ' .. ttype(self) .. ' with a trans') end return __TObject.new(self, obj) end function TProtocolBase:writeMessageBegin(name, ttype, seqid) end function TProtocolBase:writeMessageEnd() end function TProtocolBase:writeStructBegin(name) end function TProtocolBase:writeStructEnd() end function TProtocolBase:writeFieldBegin(name, ttype, id) end function TProtocolBase:writeFieldEnd() end function TProtocolBase:writeFieldStop() end function TProtocolBase:writeMapBegin(ktype, vtype, size) end function TProtocolBase:writeMapEnd() end function TProtocolBase:writeListBegin(ttype, size) end function TProtocolBase:writeListEnd() end function TProtocolBase:writeSetBegin(ttype, size) end function TProtocolBase:writeSetEnd() end function TProtocolBase:writeBool(bool) end function TProtocolBase:writeByte(byte) end function TProtocolBase:writeI16(i16) end function TProtocolBase:writeI32(i32) end function TProtocolBase:writeI64(i64) end function TProtocolBase:writeDouble(dub) end function TProtocolBase:writeString(str) end function TProtocolBase:readMessageBegin() end function TProtocolBase:readMessageEnd() end function TProtocolBase:readStructBegin() end function TProtocolBase:readStructEnd() end function TProtocolBase:readFieldBegin() end function TProtocolBase:readFieldEnd() end function TProtocolBase:readMapBegin() end function TProtocolBase:readMapEnd() end function TProtocolBase:readListBegin() end function TProtocolBase:readListEnd() end function TProtocolBase:readSetBegin() end function TProtocolBase:readSetEnd() end function TProtocolBase:readBool() end function TProtocolBase:readByte() end function TProtocolBase:readI16() end function TProtocolBase:readI32() end function TProtocolBase:readI64() end function TProtocolBase:readDouble() end function TProtocolBase:readString() end function TProtocolBase:skip(ttype) if ttype == TType.BOOL then self:readBool() elseif ttype == TType.BYTE then self:readByte() elseif ttype == TType.I16 then self:readI16() elseif ttype == TType.I32 then self:readI32() elseif ttype == TType.I64 then self:readI64() elseif ttype == TType.DOUBLE then self:readDouble() elseif ttype == TType.STRING then self:readString() elseif ttype == TType.STRUCT then local name = self:readStructBegin() while true do local name, ttype, id = self:readFieldBegin() if ttype == TType.STOP then break end self:skip(ttype) self:readFieldEnd() end self:readStructEnd() elseif ttype == TType.MAP then local kttype, vttype, size = self:readMapBegin() for i = 1, size, 1 do self:skip(kttype) self:skip(vttype) end self:readMapEnd() elseif ttype == TType.SET then local ettype, size = self:readSetBegin() for i = 1, size, 1 do self:skip(ettype) end self:readSetEnd() elseif ttype == TType.LIST then local ettype, size = self:readListBegin() for i = 1, size, 1 do self:skip(ettype) end self:readListEnd() else terror(TProtocolException:new{ message = 'Invalid data' }) end end TProtocolFactory = __TObject:new{ __type = 'TProtocolFactory', } function TProtocolFactory:getProtocol(trans) end thrift-0.16.0/lib/lua/TServer.lua000066400000000000000000000101251420101504100165050ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'Thrift' require 'TFramedTransport' require 'TBinaryProtocol' -- TServer TServer = __TObject:new{ __type = 'TServer' } -- 2 possible constructors -- 1. {processor, serverTransport} -- 2. {processor, serverTransport, transportFactory, protocolFactory} function TServer:new(args) if ttype(args) ~= 'table' then error('TServer must be initialized with a table') end if args.processor == nil then terror('You must provide ' .. ttype(self) .. ' with a processor') end if args.serverTransport == nil then terror('You must provide ' .. ttype(self) .. ' with a serverTransport') end -- Create the object local obj = __TObject.new(self, args) if obj.transportFactory then obj.inputTransportFactory = obj.transportFactory obj.outputTransportFactory = obj.transportFactory obj.transportFactory = nil else obj.inputTransportFactory = TFramedTransportFactory:new{} obj.outputTransportFactory = obj.inputTransportFactory end if obj.protocolFactory then obj.inputProtocolFactory = obj.protocolFactory obj.outputProtocolFactory = obj.protocolFactory obj.protocolFactory = nil else obj.inputProtocolFactory = TBinaryProtocolFactory:new{} obj.outputProtocolFactory = obj.inputProtocolFactory end -- Set the __server variable in the handler so we can stop the server obj.processor.handler.__server = self return obj end function TServer:setServerEventHandler(handler) self.serverEventHandler = handler end function TServer:_clientBegin(content, iprot, oprot) if self.serverEventHandler and type(self.serverEventHandler.clientBegin) == 'function' then self.serverEventHandler:clientBegin(iprot, oprot) end end function TServer:_preServe() if self.serverEventHandler and type(self.serverEventHandler.preServe) == 'function' then self.serverEventHandler:preServe(self.serverTransport:getSocketInfo()) end end function TServer:setExceptionHandler(exceptionHandler) self.exceptionHandler = exceptionHandler end function TServer:_handleException(err) if string.find(err, 'TTransportException') == nil then if self.exceptionHandler then self.exceptionHandler(err) else print(err) end end end function TServer:serve() end function TServer:handle(client) local itrans, otrans = self.inputTransportFactory:getTransport(client), self.outputTransportFactory:getTransport(client) local iprot, oprot = self.inputProtocolFactory:getProtocol(itrans), self.outputProtocolFactory:getProtocol(otrans) self:_clientBegin(iprot, oprot) while true do local ret, err = pcall(self.processor.process, self.processor, iprot, oprot) if ret == false and err then if not string.find(err, "TTransportException") then self:_handleException(err) end break end end itrans:close() otrans:close() end function TServer:close() self.serverTransport:close() end -- TSimpleServer -- Single threaded server that handles one transport (connection) TSimpleServer = __TObject:new(TServer, { __type = 'TSimpleServer', __stop = false }) function TSimpleServer:serve() self.serverTransport:listen() self:_preServe() while not self.__stop do client = self.serverTransport:accept() self:handle(client) end self:close() end function TSimpleServer:stop() self.__stop = true end thrift-0.16.0/lib/lua/TSocket.lua000066400000000000000000000056641420101504100165030ustar00rootroot00000000000000---- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'TTransport' require 'libluasocket' -- TSocketBase TSocketBase = TTransportBase:new{ __type = 'TSocketBase', timeout = 1000, host = 'localhost', port = 9090, handle } function TSocketBase:close() if self.handle then self.handle:destroy() self.handle = nil end end -- Returns a table with the fields host and port function TSocketBase:getSocketInfo() if self.handle then return self.handle:getsockinfo() end terror(TTransportException:new{errorCode = TTransportException.NOT_OPEN}) end function TSocketBase:setTimeout(timeout) if timeout and ttype(timeout) == 'number' then if self.handle then self.handle:settimeout(timeout) end self.timeout = timeout end end -- TSocket TSocket = TSocketBase:new{ __type = 'TSocket', host = 'localhost', port = 9090 } function TSocket:isOpen() if self.handle then return true end return false end function TSocket:open() if self.handle then self:close() end -- Create local handle local sock, err = luasocket.create_and_connect( self.host, self.port, self.timeout) if err == nil then self.handle = sock end if err then terror(TTransportException:new{ message = 'Could not connect to ' .. self.host .. ':' .. self.port .. ' (' .. err .. ')' }) end end function TSocket:read(len) local buf = self.handle:receive(self.handle, len) if not buf or string.len(buf) ~= len then terror(TTransportException:new{errorCode = TTransportException.UNKNOWN}) end return buf end function TSocket:write(buf) self.handle:send(self.handle, buf) end function TSocket:flush() end -- TServerSocket TServerSocket = TSocketBase:new{ __type = 'TServerSocket', host = 'localhost', port = 9090 } function TServerSocket:listen() if self.handle then self:close() end local sock, err = luasocket.create(self.host, self.port) if not err then self.handle = sock else terror(err) end self.handle:settimeout(self.timeout) self.handle:listen() end function TServerSocket:accept() local client, err = self.handle:accept() if err then terror(err) end return TSocket:new({handle = client}) end thrift-0.16.0/lib/lua/TTransport.lua000066400000000000000000000053601420101504100172400ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- require 'Thrift' TTransportException = TException:new { UNKNOWN = 0, NOT_OPEN = 1, ALREADY_OPEN = 2, TIMED_OUT = 3, END_OF_FILE = 4, INVALID_FRAME_SIZE = 5, INVALID_TRANSFORM = 6, INVALID_CLIENT_TYPE = 7, errorCode = 0, __type = 'TTransportException' } function TTransportException:__errorCodeToString() if self.errorCode == self.NOT_OPEN then return 'Transport not open' elseif self.errorCode == self.ALREADY_OPEN then return 'Transport already open' elseif self.errorCode == self.TIMED_OUT then return 'Transport timed out' elseif self.errorCode == self.END_OF_FILE then return 'End of file' elseif self.errorCode == self.INVALID_FRAME_SIZE then return 'Invalid frame size' elseif self.errorCode == self.INVALID_TRANSFORM then return 'Invalid transform' elseif self.errorCode == self.INVALID_CLIENT_TYPE then return 'Invalid client type' else return 'Default (unknown)' end end TTransportBase = __TObject:new{ __type = 'TTransportBase' } function TTransportBase:isOpen() end function TTransportBase:open() end function TTransportBase:close() end function TTransportBase:read(len) end function TTransportBase:readAll(len) local buf, have, chunk = '', 0 while have < len do chunk = self:read(len - have) have = have + string.len(chunk) buf = buf .. chunk if string.len(chunk) == 0 then terror(TTransportException:new{ errorCode = TTransportException.END_OF_FILE }) end end return buf end function TTransportBase:write(buf) end function TTransportBase:flush() end TServerTransportBase = __TObject:new{ __type = 'TServerTransportBase' } function TServerTransportBase:listen() end function TServerTransportBase:accept() end function TServerTransportBase:close() end TTransportFactoryBase = __TObject:new{ __type = 'TTransportFactoryBase' } function TTransportFactoryBase:getTransport(trans) return trans end thrift-0.16.0/lib/lua/Thrift.lua000066400000000000000000000151301420101504100163540ustar00rootroot00000000000000-- -- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file -- to you under the Apache License, Version 2.0 (the -- "License"); you may not use this file except in compliance -- with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, -- software distributed under the License is distributed on an -- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -- KIND, either express or implied. See the License for the -- specific language governing permissions and limitations -- under the License. -- ---- namespace thrift --thrift = {} --setmetatable(thrift, {__index = _G}) --> perf hit for accessing global methods --setfenv(1, thrift) package.cpath = package.cpath .. ';bin/?.so' -- TODO FIX function ttype(obj) if type(obj) == 'table' and obj.__type and type(obj.__type) == 'string' then return obj.__type end return type(obj) end function terror(e) if e and e.__tostring then error(e:__tostring()) return end error(e) end function ttable_size(t) local count = 0 for k, v in pairs(t) do count = count + 1 end return count end version = '0.16.0' TType = { STOP = 0, VOID = 1, BOOL = 2, BYTE = 3, I08 = 3, DOUBLE = 4, I16 = 6, I32 = 8, I64 = 10, STRING = 11, UTF7 = 11, STRUCT = 12, MAP = 13, SET = 14, LIST = 15, UTF8 = 16, UTF16 = 17 } TMessageType = { CALL = 1, REPLY = 2, EXCEPTION = 3, ONEWAY = 4 } -- Recursive __index function to achieve inheritance function __tobj_index(self, key) local v = rawget(self, key) if v ~= nil then return v end local p = rawget(self, '__parent') if p then return __tobj_index(p, key) end return nil end -- Basic Thrift-Lua Object __TObject = { __type = '__TObject', __mt = { __index = __tobj_index } } function __TObject:new(init_obj) local obj = {} if ttype(obj) == 'table' then obj = init_obj end -- Use the __parent key and the __index function to achieve inheritance obj.__parent = self setmetatable(obj, __TObject.__mt) return obj end -- Return a string representation of any lua variable function thrift_print_r(t) local ret = '' local ltype = type(t) if (ltype == 'table') then ret = ret .. '{ ' for key,value in pairs(t) do ret = ret .. tostring(key) .. '=' .. thrift_print_r(value) .. ' ' end ret = ret .. '}' elseif ltype == 'string' then ret = ret .. "'" .. tostring(t) .. "'" else ret = ret .. tostring(t) end return ret end -- Basic Exception TException = __TObject:new{ message, errorCode, __type = 'TException' } function TException:__tostring() if self.message then return string.format('%s: %s', self.__type, self.message) else local message if self.errorCode and self.__errorCodeToString then message = string.format('%d: %s', self.errorCode, self:__errorCodeToString()) else message = thrift_print_r(self) end return string.format('%s:%s', self.__type, message) end end TApplicationException = TException:new{ UNKNOWN = 0, UNKNOWN_METHOD = 1, INVALID_MESSAGE_TYPE = 2, WRONG_METHOD_NAME = 3, BAD_SEQUENCE_ID = 4, MISSING_RESULT = 5, INTERNAL_ERROR = 6, PROTOCOL_ERROR = 7, INVALID_TRANSFORM = 8, INVALID_PROTOCOL = 9, UNSUPPORTED_CLIENT_TYPE = 10, errorCode = 0, __type = 'TApplicationException' } function TApplicationException:__errorCodeToString() if self.errorCode == self.UNKNOWN_METHOD then return 'Unknown method' elseif self.errorCode == self.INVALID_MESSAGE_TYPE then return 'Invalid message type' elseif self.errorCode == self.WRONG_METHOD_NAME then return 'Wrong method name' elseif self.errorCode == self.BAD_SEQUENCE_ID then return 'Bad sequence ID' elseif self.errorCode == self.MISSING_RESULT then return 'Missing result' elseif self.errorCode == self.INTERNAL_ERROR then return 'Internal error' elseif self.errorCode == self.PROTOCOL_ERROR then return 'Protocol error' elseif self.errorCode == self.INVALID_TRANSFORM then return 'Invalid transform' elseif self.errorCode == self.INVALID_PROTOCOL then return 'Invalid protocol' elseif self.errorCode == self.UNSUPPORTED_CLIENT_TYPE then return 'Unsupported client type' else return 'Default (unknown)' end end function TException:read(iprot) iprot:readStructBegin() while true do local fname, ftype, fid = iprot:readFieldBegin() if ftype == TType.STOP then break elseif fid == 1 then if ftype == TType.STRING then self.message = iprot:readString() else iprot:skip(ftype) end elseif fid == 2 then if ftype == TType.I32 then self.errorCode = iprot:readI32() else iprot:skip(ftype) end else iprot:skip(ftype) end iprot:readFieldEnd() end iprot:readStructEnd() end function TException:write(oprot) oprot:writeStructBegin('TApplicationException') if self.message then oprot:writeFieldBegin('message', TType.STRING, 1) oprot:writeString(self.message) oprot:writeFieldEnd() end if self.errorCode then oprot:writeFieldBegin('type', TType.I32, 2) oprot:writeI32(self.errorCode) oprot:writeFieldEnd() end oprot:writeFieldStop() oprot:writeStructEnd() end -- Basic Client (used in generated lua code) __TClient = __TObject:new{ __type = '__TClient', _seqid = 0 } function __TClient:new(obj) if ttype(obj) ~= 'table' then error('TClient must be initialized with a table') end -- Set iprot & oprot if obj.protocol then obj.iprot = obj.protocol obj.oprot = obj.protocol obj.protocol = nil elseif not obj.iprot then error('You must provide ' .. ttype(self) .. ' with an iprot') end if not obj.oprot then obj.oprot = obj.iprot end return __TObject.new(self, obj) end function __TClient:close() self.iprot.trans:close() self.oprot.trans:close() end -- Basic Processor (used in generated lua code) __TProcessor = __TObject:new{ __type = '__TProcessor' } function __TProcessor:new(obj) if ttype(obj) ~= 'table' then error('TProcessor must be initialized with a table') end -- Ensure a handler is provided if not obj.handler then error('You must provide ' .. ttype(self) .. ' with a handler') end return __TObject.new(self, obj) end thrift-0.16.0/lib/lua/coding_standards.md000066400000000000000000000001031420101504100202330ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/lua/src/000077500000000000000000000000001420101504100152005ustar00rootroot00000000000000thrift-0.16.0/lib/lua/src/longnumberutils.c000066400000000000000000000031741420101504100206020ustar00rootroot00000000000000// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #include #include #include #include const char * LONG_NUM_TYPE = "__thrift_longnumber"; int64_t lualongnumber_checklong(lua_State *L, int index) { switch (lua_type(L, index)) { case LUA_TNUMBER: return (int64_t)lua_tonumber(L, index); case LUA_TSTRING: return atoll(lua_tostring(L, index)); default: return *((int64_t *)luaL_checkudata(L, index, LONG_NUM_TYPE)); } } // Creates a new longnumber and pushes it onto the statck int64_t * lualongnumber_pushlong(lua_State *L, int64_t *val) { int64_t *data = (int64_t *)lua_newuserdata(L, sizeof(int64_t)); // longnum luaL_getmetatable(L, LONG_NUM_TYPE); // longnum, mt lua_setmetatable(L, -2); // longnum if (val) { *data = *val; } return data; } thrift-0.16.0/lib/lua/src/luabitwise.c000066400000000000000000000037371420101504100175260ustar00rootroot00000000000000// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #include #include static int l_not(lua_State *L) { int a = luaL_checkinteger(L, 1); a = ~a; lua_pushnumber(L, a); return 1; } static int l_xor(lua_State *L) { int a = luaL_checkinteger(L, 1); int b = luaL_checkinteger(L, 2); a ^= b; lua_pushnumber(L, a); return 1; } static int l_and(lua_State *L) { int a = luaL_checkinteger(L, 1); int b = luaL_checkinteger(L, 2); a &= b; lua_pushnumber(L, a); return 1; } static int l_or(lua_State *L) { int a = luaL_checkinteger(L, 1); int b = luaL_checkinteger(L, 2); a |= b; lua_pushnumber(L, a); return 1; } static int l_shiftr(lua_State *L) { int a = luaL_checkinteger(L, 1); int b = luaL_checkinteger(L, 2); a = a >> b; lua_pushnumber(L, a); return 1; } static int l_shiftl(lua_State *L) { int a = luaL_checkinteger(L, 1); int b = luaL_checkinteger(L, 2); a = a << b; lua_pushnumber(L, a); return 1; } static const struct luaL_Reg funcs[] = { {"band", l_and}, {"bor", l_or}, {"bxor", l_xor}, {"bnot", l_not}, {"shiftl", l_shiftl}, {"shiftr", l_shiftr}, {NULL, NULL} }; int luaopen_libluabitwise(lua_State *L) { luaL_register(L, "libluabitwise", funcs); return 1; } thrift-0.16.0/lib/lua/src/luabpack.c000066400000000000000000000177371420101504100171450ustar00rootroot00000000000000// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #include #include #include #include #include extern int64_t lualongnumber_checklong(lua_State *L, int index); extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val); // host order to network order (64-bit) static int64_t T_htonll(uint64_t data) { uint32_t d1 = htonl((uint32_t)data); uint32_t d2 = htonl((uint32_t)(data >> 32)); return ((uint64_t)d1 << 32) + (uint64_t)d2; } // network order to host order (64-bit) static int64_t T_ntohll(uint64_t data) { uint32_t d1 = ntohl((uint32_t)data); uint32_t d2 = ntohl((uint32_t)(data >> 32)); return ((uint64_t)d1 << 32) + (uint64_t)d2; } /** * bpack(type, data) * c - Signed Byte * s - Signed Short * i - Signed Int * l - Signed Long * d - Double */ static int l_bpack(lua_State *L) { const char *code = luaL_checkstring(L, 1); luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character."); luaL_Buffer buf; luaL_buffinit(L, &buf); switch (code[0]) { case 'c': { int8_t data = luaL_checknumber(L, 2); luaL_addlstring(&buf, (void*)&data, sizeof(data)); break; } case 's': { int16_t data = luaL_checknumber(L, 2); data = (int16_t)htons(data); luaL_addlstring(&buf, (void*)&data, sizeof(data)); break; } case 'i': { int32_t data = luaL_checkinteger(L, 2); data = (int32_t)htonl(data); luaL_addlstring(&buf, (void*)&data, sizeof(data)); break; } case 'l': { int64_t data = lualongnumber_checklong(L, 2); data = (int64_t)T_htonll(data); luaL_addlstring(&buf, (void*)&data, sizeof(data)); break; } case 'd': { double data = luaL_checknumber(L, 2); luaL_addlstring(&buf, (void*)&data, sizeof(data)); break; } default: luaL_argcheck(L, 0, 0, "Invalid format code."); } luaL_pushresult(&buf); return 1; } /** * bunpack(type, data) * c - Signed Byte * C - Unsigned Byte * s - Signed Short * i - Signed Int * l - Signed Long * d - Double */ static int l_bunpack(lua_State *L) { const char *code = luaL_checkstring(L, 1); luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character."); const char *data = luaL_checkstring(L, 2); #if LUA_VERSION_NUM >= 502 size_t len = lua_rawlen(L, 2); #else size_t len = lua_objlen(L, 2); #endif switch (code[0]) { case 'c': { int8_t val; luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); memcpy(&val, data, sizeof(val)); lua_pushnumber(L, val); break; } /** * unpack unsigned Byte. */ case 'C': { uint8_t val; luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); memcpy(&val, data, sizeof(val)); lua_pushnumber(L, val); break; } case 's': { int16_t val; luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); memcpy(&val, data, sizeof(val)); val = (int16_t)ntohs(val); lua_pushnumber(L, val); break; } case 'i': { int32_t val; luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); memcpy(&val, data, sizeof(val)); val = (int32_t)ntohl(val); lua_pushnumber(L, val); break; } case 'l': { int64_t val; luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); memcpy(&val, data, sizeof(val)); val = (int64_t)T_ntohll(val); lualongnumber_pushlong(L, &val); break; } case 'd': { double val; luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); memcpy(&val, data, sizeof(val)); lua_pushnumber(L, val); break; } default: luaL_argcheck(L, 0, 0, "Invalid format code."); } return 1; } /** * Convert l into a zigzag long. This allows negative numbers to be * represented compactly as a varint. */ static int l_i64ToZigzag(lua_State *L) { int64_t n = lualongnumber_checklong(L, 1); int64_t result = (n << 1) ^ (n >> 63); lualongnumber_pushlong(L, &result); return 1; } /** * Convert n into a zigzag int. This allows negative numbers to be * represented compactly as a varint. */ static int l_i32ToZigzag(lua_State *L) { int32_t n = luaL_checkinteger(L, 1); uint32_t result = (uint32_t)(n << 1) ^ (n >> 31); lua_pushnumber(L, result); return 1; } /** * Convert from zigzag int to int. */ static int l_zigzagToI32(lua_State *L) { uint32_t n = luaL_checkinteger(L, 1); int32_t result = (int32_t)(n >> 1) ^ (uint32_t)(-(int32_t)(n & 1)); lua_pushnumber(L, result); return 1; } /** * Convert from zigzag long to long. */ static int l_zigzagToI64(lua_State *L) { int64_t n = lualongnumber_checklong(L, 1); int64_t result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1)); lualongnumber_pushlong(L, &result); return 1; } /** * Convert an i32 to a varint. Results in 1-5 bytes on the buffer. */ static int l_toVarint32(lua_State *L) { uint8_t buf[5]; uint32_t n = luaL_checkinteger(L, 1); uint32_t wsize = 0; while (1) { if ((n & ~0x7F) == 0) { buf[wsize++] = (int8_t)n; break; } else { buf[wsize++] = (int8_t)((n & 0x7F) | 0x80); n >>= 7; } } lua_pushlstring(L, buf, wsize); return 1; } /** * Convert an i64 to a varint. Results in 1-10 bytes on the buffer. */ static int l_toVarint64(lua_State *L) { uint8_t data[10]; uint64_t n = lualongnumber_checklong(L, 1); uint32_t wsize = 0; luaL_Buffer buf; luaL_buffinit(L, &buf); while (1) { if ((n & ~0x7FL) == 0) { data[wsize++] = (int8_t)n; break; } else { data[wsize++] = (int8_t)((n & 0x7F) | 0x80); n >>= 7; } } luaL_addlstring(&buf, (void*)&data, wsize); luaL_pushresult(&buf); return 1; } /** * Convert a varint to i64. */ static int l_fromVarint64(lua_State *L) { int64_t result; uint8_t byte = luaL_checknumber(L, 1); int32_t shift = luaL_checknumber(L, 2); uint64_t n = (uint64_t)lualongnumber_checklong(L, 3); n |= (uint64_t)(byte & 0x7f) << shift; if (!(byte & 0x80)) { result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1)); lua_pushnumber(L, 0); } else { result = n; lua_pushnumber(L, 1); } lualongnumber_pushlong(L, &result); return 2; } /** * To pack message type of compact protocol. */ static int l_packMesgType(lua_State *L) { int32_t version_n = luaL_checkinteger(L, 1); int32_t version_mask = luaL_checkinteger(L, 2); int32_t messagetype = luaL_checkinteger(L, 3); int32_t type_shift_amount = luaL_checkinteger(L, 4); int32_t type_mask = luaL_checkinteger(L, 5); int32_t to_mesg_type = (version_n & version_mask) | (((int32_t)messagetype << type_shift_amount) & type_mask); lua_pushnumber(L, to_mesg_type); return 1; } static const struct luaL_Reg lua_bpack[] = { {"bpack", l_bpack}, {"bunpack", l_bunpack}, {"i32ToZigzag", l_i32ToZigzag}, {"i64ToZigzag", l_i64ToZigzag}, {"zigzagToI32", l_zigzagToI32}, {"zigzagToI64", l_zigzagToI64}, {"toVarint32", l_toVarint32}, {"toVarint64", l_toVarint64}, {"fromVarint64", l_fromVarint64}, {"packMesgType", l_packMesgType}, {NULL, NULL} }; int luaopen_libluabpack(lua_State *L) { luaL_register(L, "libluabpack", lua_bpack); return 1; } thrift-0.16.0/lib/lua/src/lualongnumber.c000066400000000000000000000126421420101504100202230ustar00rootroot00000000000000// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #include #include #include #include #include #include extern const char * LONG_NUM_TYPE; extern int64_t lualongnumber_checklong(lua_State *L, int index); extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val); //////////////////////////////////////////////////////////////////////////////// static void l_serialize(char *buf, int len, int64_t val) { snprintf(buf, len, "%"PRId64, val); } static int64_t l_deserialize(const char *buf) { int64_t data; int rv; // Support hex prefixed with '0x' if (strstr(buf, "0x") == buf) { rv = sscanf(buf, "%"PRIx64, &data); } else { rv = sscanf(buf, "%"PRId64, &data); } if (rv == 1) { return data; } return 0; // Failed } //////////////////////////////////////////////////////////////////////////////// static int l_new(lua_State *L) { int64_t val; const char *str = NULL; if (lua_type(L, 1) == LUA_TSTRING) { str = lua_tostring(L, 1); val = l_deserialize(str); } else if (lua_type(L, 1) == LUA_TNUMBER) { val = (int64_t)lua_tonumber(L, 1); str = (const char *)1; } lualongnumber_pushlong(L, (str ? &val : NULL)); return 1; } //////////////////////////////////////////////////////////////////////////////// // a + b static int l_add(lua_State *L) { int64_t a, b, c; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); c = a + b; lualongnumber_pushlong(L, &c); return 1; } // a / b static int l_div(lua_State *L) { int64_t a, b, c; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); c = a / b; lualongnumber_pushlong(L, &c); return 1; } // a == b (both a and b are lualongnumber's) static int l_eq(lua_State *L) { int64_t a, b; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); lua_pushboolean(L, (a == b ? 1 : 0)); return 1; } // garbage collection static int l_gc(lua_State *L) { lua_pushnil(L); lua_setmetatable(L, 1); return 0; } // a < b static int l_lt(lua_State *L) { int64_t a, b; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); lua_pushboolean(L, (a < b ? 1 : 0)); return 1; } // a <= b static int l_le(lua_State *L) { int64_t a, b; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); lua_pushboolean(L, (a <= b ? 1 : 0)); return 1; } // a % b static int l_mod(lua_State *L) { int64_t a, b, c; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); c = a % b; lualongnumber_pushlong(L, &c); return 1; } // a * b static int l_mul(lua_State *L) { int64_t a, b, c; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); c = a * b; lualongnumber_pushlong(L, &c); return 1; } // a ^ b static int l_pow(lua_State *L) { long double a, b; int64_t c; a = (long double)lualongnumber_checklong(L, 1); b = (long double)lualongnumber_checklong(L, 2); c = (int64_t)pow(a, b); lualongnumber_pushlong(L, &c); return 1; } // a - b static int l_sub(lua_State *L) { int64_t a, b, c; a = lualongnumber_checklong(L, 1); b = lualongnumber_checklong(L, 2); c = a - b; lualongnumber_pushlong(L, &c); return 1; } // tostring() static int l_tostring(lua_State *L) { int64_t a; char str[256]; l_serialize(str, 256, lualongnumber_checklong(L, 1)); lua_pushstring(L, str); return 1; } // -a static int l_unm(lua_State *L) { int64_t a, c; a = lualongnumber_checklong(L, 1); c = -a; lualongnumber_pushlong(L, &c); return 1; } //////////////////////////////////////////////////////////////////////////////// static const luaL_Reg methods[] = { {"__add", l_add}, {"__div", l_div}, {"__eq", l_eq}, {"__gc", l_gc}, {"__lt", l_lt}, {"__le", l_le}, {"__mod", l_mod}, {"__mul", l_mul}, {"__pow", l_pow}, {"__sub", l_sub}, {"__tostring", l_tostring}, {"__unm", l_unm}, {NULL, NULL}, }; static const luaL_Reg funcs[] = { {"new", l_new}, {NULL, NULL} }; //////////////////////////////////////////////////////////////////////////////// static void set_methods(lua_State *L, const char *metatablename, const struct luaL_Reg *methods) { luaL_getmetatable(L, metatablename); // mt // No need for a __index table since everything is __* for (; methods->name; methods++) { lua_pushstring(L, methods->name); // mt, "name" lua_pushcfunction(L, methods->func); // mt, "name", func lua_rawset(L, -3); // mt } lua_pop(L, 1); } LUALIB_API int luaopen_liblualongnumber(lua_State *L) { luaL_newmetatable(L, LONG_NUM_TYPE); lua_pop(L, 1); set_methods(L, LONG_NUM_TYPE, methods); luaL_register(L, "liblualongnumber", funcs); return 1; } thrift-0.16.0/lib/lua/src/luasocket.c000066400000000000000000000260051420101504100173410ustar00rootroot00000000000000// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #include #include #include #include "string.h" #include "socket.h" //////////////////////////////////////////////////////////////////////////////// static const char *SOCKET_ANY = "__thrift_socket_any"; static const char *SOCKET_CONN = "__thrift_socket_connected"; static const char *SOCKET_GENERIC = "__thrift_socket_generic"; static const char *SOCKET_CLIENT = "__thrift_socket_client"; static const char *SOCKET_SERVER = "__thrift_socket_server"; static const char *DEFAULT_HOST = "localhost"; typedef struct __t_tcp { t_socket sock; int timeout; // Milliseconds } t_tcp; typedef t_tcp *p_tcp; //////////////////////////////////////////////////////////////////////////////// // Util static void throw_argerror(lua_State *L, int index, const char *expected) { char msg[256]; sprintf(msg, "%s expected, got %s", expected, luaL_typename(L, index)); luaL_argerror(L, index, msg); } static void *checkgroup(lua_State *L, int index, const char *groupname) { if (!lua_getmetatable(L, index)) { throw_argerror(L, index, groupname); } lua_pushstring(L, groupname); lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 2); throw_argerror(L, index, groupname); } else { lua_pop(L, 2); return lua_touserdata(L, index); } return NULL; // Not reachable } static void *checktype(lua_State *L, int index, const char *typename) { if (strcmp(typename, SOCKET_ANY) == 0 || strcmp(typename, SOCKET_CONN) == 0) { return checkgroup(L, index, typename); } else { return luaL_checkudata(L, index, typename); } } static void settype(lua_State *L, int index, const char *typename) { luaL_getmetatable(L, typename); lua_setmetatable(L, index); } #define LUA_SUCCESS_RETURN(L) \ lua_pushnumber(L, 1); \ return 1 #define LUA_CHECK_RETURN(L, err) \ if (err) { \ lua_pushnil(L); \ lua_pushstring(L, err); \ return 2; \ } \ LUA_SUCCESS_RETURN(L) //////////////////////////////////////////////////////////////////////////////// static int l_socket_create(lua_State *L); static int l_socket_destroy(lua_State *L); static int l_socket_settimeout(lua_State *L); static int l_socket_getsockinfo(lua_State *L); static int l_socket_accept(lua_State *L); static int l_socket_listen(lua_State *L); static int l_socket_create_and_connect(lua_State *L); static int l_socket_connect(lua_State *L); static int l_socket_send(lua_State *L); static int l_socket_receive(lua_State *L); //////////////////////////////////////////////////////////////////////////////// static const struct luaL_Reg methods_generic[] = { {"destroy", l_socket_destroy}, {"settimeout", l_socket_settimeout}, {"getsockinfo", l_socket_getsockinfo}, {"listen", l_socket_listen}, {"connect", l_socket_connect}, {NULL, NULL} }; static const struct luaL_Reg methods_server[] = { {"destroy", l_socket_destroy}, {"getsockinfo", l_socket_getsockinfo}, {"accept", l_socket_accept}, {"send", l_socket_send}, {"receive", l_socket_receive}, {NULL, NULL} }; static const struct luaL_Reg methods_client[] = { {"destroy", l_socket_destroy}, {"settimeout", l_socket_settimeout}, {"getsockinfo", l_socket_getsockinfo}, {"send", l_socket_send}, {"receive", l_socket_receive}, {NULL, NULL} }; static const struct luaL_Reg funcs_luasocket[] = { {"create", l_socket_create}, {"create_and_connect", l_socket_create_and_connect}, {NULL, NULL} }; //////////////////////////////////////////////////////////////////////////////// // Check/enforce inheritance static void add_to_group(lua_State *L, const char *metatablename, const char *groupname) { luaL_getmetatable(L, metatablename); // mt lua_pushstring(L, groupname); // mt, "name" lua_pushboolean(L, 1); // mt, "name", true lua_rawset(L, -3); // mt lua_pop(L, 1); } static void set_methods(lua_State *L, const char *metatablename, const struct luaL_Reg *methods) { luaL_getmetatable(L, metatablename); // mt // Create the __index table lua_pushstring(L, "__index"); // mt, "__index" lua_newtable(L); // mt, "__index", t for (; methods->name; methods++) { lua_pushstring(L, methods->name); // mt, "__index", t, "name" lua_pushcfunction(L, methods->func); // mt, "__index", t, "name", func lua_rawset(L, -3); // mt, "__index", t } lua_rawset(L, -3); // mt lua_pop(L, 1); } int luaopen_libluasocket(lua_State *L) { luaL_newmetatable(L, SOCKET_GENERIC); luaL_newmetatable(L, SOCKET_CLIENT); luaL_newmetatable(L, SOCKET_SERVER); lua_pop(L, 3); add_to_group(L, SOCKET_GENERIC, SOCKET_ANY); add_to_group(L, SOCKET_CLIENT, SOCKET_ANY); add_to_group(L, SOCKET_SERVER, SOCKET_ANY); add_to_group(L, SOCKET_CLIENT, SOCKET_CONN); add_to_group(L, SOCKET_SERVER, SOCKET_CONN); set_methods(L, SOCKET_GENERIC, methods_generic); set_methods(L, SOCKET_CLIENT, methods_client); set_methods(L, SOCKET_SERVER, methods_server); luaL_register(L, "luasocket", funcs_luasocket); return 1; } //////////////////////////////////////////////////////////////////////////////// // General // sock,err create(bind_host, bind_port) // sock,err create(bind_host) -> any port // sock,err create() -> any port on localhost static int l_socket_create(lua_State *L) { const char *err; t_socket sock; const char *addr = lua_tostring(L, 1); if (!addr) { addr = DEFAULT_HOST; } unsigned short port = lua_tonumber(L, 2); err = tcp_create(&sock); if (!err) { err = tcp_bind(&sock, addr, port); // bind on create if (err) { tcp_destroy(&sock); } else { p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); settype(L, -2, SOCKET_GENERIC); socket_setnonblocking(&sock); tcp->sock = sock; tcp->timeout = 0; return 1; // Return userdata } } LUA_CHECK_RETURN(L, err); } // destroy() static int l_socket_destroy(lua_State *L) { p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_ANY); const char *err = tcp_destroy(&tcp->sock); LUA_CHECK_RETURN(L, err); } // send(socket, data) static int l_socket_send(lua_State *L) { p_tcp self = (p_tcp) checktype(L, 1, SOCKET_CONN); p_tcp tcp = (p_tcp) checktype(L, 2, SOCKET_CONN); size_t len; const char *data = luaL_checklstring(L, 3, &len); const char *err = tcp_send(&tcp->sock, data, len, tcp->timeout); LUA_CHECK_RETURN(L, err); } #define LUA_READ_STEP 8192 static int l_socket_receive(lua_State *L) { p_tcp self = (p_tcp) checktype(L, 1, SOCKET_CONN); p_tcp handle = (p_tcp) checktype(L, 2, SOCKET_CONN); size_t len = luaL_checknumber(L, 3); char buf[LUA_READ_STEP]; const char *err = NULL; int received; size_t got = 0, step = 0; luaL_Buffer b; luaL_buffinit(L, &b); do { step = (LUA_READ_STEP < len - got ? LUA_READ_STEP : len - got); err = tcp_raw_receive(&handle->sock, buf, step, self->timeout, &received); if (err == NULL) { luaL_addlstring(&b, buf, received); got += received; } } while (err == NULL && got < len); if (err) { lua_pushnil(L); lua_pushstring(L, err); return 2; } luaL_pushresult(&b); return 1; } // settimeout(timeout) static int l_socket_settimeout(lua_State *L) { p_tcp self = (p_tcp) checktype(L, 1, SOCKET_ANY); int timeout = luaL_checknumber(L, 2); self->timeout = timeout; LUA_SUCCESS_RETURN(L); } // table getsockinfo() static int l_socket_getsockinfo(lua_State *L) { char buf[256]; short port = 0; p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_ANY); if (socket_get_info(&tcp->sock, &port, buf, 256) == SUCCESS) { lua_newtable(L); // t lua_pushstring(L, "host"); // t, "host" lua_pushstring(L, buf); // t, "host", buf lua_rawset(L, -3); // t lua_pushstring(L, "port"); // t, "port" lua_pushnumber(L, port); // t, "port", port lua_rawset(L, -3); // t return 1; } return 0; } //////////////////////////////////////////////////////////////////////////////// // Server // accept() static int l_socket_accept(lua_State *L) { const char *err; p_tcp self = (p_tcp) checktype(L, 1, SOCKET_SERVER); t_socket sock; err = tcp_accept(&self->sock, &sock, self->timeout); if (!err) { // Success // Create a reference to the client p_tcp client = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); settype(L, 2, SOCKET_CLIENT); socket_setnonblocking(&sock); client->sock = sock; client->timeout = self->timeout; return 1; } LUA_CHECK_RETURN(L, err); } static int l_socket_listen(lua_State *L) { const char* err; p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_GENERIC); int backlog = 10; err = tcp_listen(&tcp->sock, backlog); if (!err) { // Set the current as a server settype(L, 1, SOCKET_SERVER); // Now a server } LUA_CHECK_RETURN(L, err); } //////////////////////////////////////////////////////////////////////////////// // Client // create_and_connect(host, port, timeout) extern double __gettime(); static int l_socket_create_and_connect(lua_State *L) { const char* err = NULL; double end; t_socket sock; const char *host = luaL_checkstring(L, 1); unsigned short port = luaL_checknumber(L, 2); int timeout = luaL_checknumber(L, 3); // Create and connect loop for timeout milliseconds end = __gettime() + timeout/1000; do { // Create and connect the socket err = tcp_create_and_connect(&sock, host, port, timeout); if (err) { tcp_destroy(&sock); usleep(100000); // sleep for 100ms } else { p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); settype(L, -2, SOCKET_CLIENT); socket_setnonblocking(&sock); tcp->sock = sock; tcp->timeout = timeout; return 1; // Return userdata } } while (err && __gettime() < end); LUA_CHECK_RETURN(L, err); } // connect(host, port) static int l_socket_connect(lua_State *L) { const char *err; p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_GENERIC); const char *host = luaL_checkstring(L, 2); unsigned short port = luaL_checknumber(L, 3); err = tcp_connect(&tcp->sock, host, port, tcp->timeout); if (!err) { settype(L, 1, SOCKET_CLIENT); // Now a client } LUA_CHECK_RETURN(L, err); } thrift-0.16.0/lib/lua/src/socket.h000066400000000000000000000055111420101504100166430ustar00rootroot00000000000000// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #ifndef LUA_THRIFT_SOCKET_H #define LUA_THRIFT_SOCKET_H #include #ifdef _WIN32 // SOL #else typedef int t_socket; typedef t_socket* p_socket; #endif // Error Codes enum { SUCCESS = 0, TIMEOUT = -1, CLOSED = -2, }; typedef int T_ERRCODE; static const char * TIMEOUT_MSG = "Timeout"; static const char * CLOSED_MSG = "Connection Closed"; typedef struct sockaddr t_sa; typedef t_sa * p_sa; T_ERRCODE socket_create(p_socket sock, int domain, int type, int protocol); T_ERRCODE socket_destroy(p_socket sock); T_ERRCODE socket_bind(p_socket sock, p_sa addr, int addr_len); T_ERRCODE socket_get_info(p_socket sock, short *port, char *buf, size_t len); T_ERRCODE socket_send(p_socket sock, const char *data, size_t len, int timeout); T_ERRCODE socket_recv(p_socket sock, char *data, size_t len, int timeout, int *received); T_ERRCODE socket_setblocking(p_socket sock); T_ERRCODE socket_setnonblocking(p_socket sock); T_ERRCODE socket_accept(p_socket sock, p_socket sibling, p_sa addr, socklen_t *addr_len, int timeout); T_ERRCODE socket_listen(p_socket sock, int backlog); T_ERRCODE socket_connect(p_socket sock, p_sa addr, int addr_len, int timeout); const char * tcp_create(p_socket sock); const char * tcp_destroy(p_socket sock); const char * tcp_bind(p_socket sock, const char *host, unsigned short port); const char * tcp_send(p_socket sock, const char *data, size_t w_len, int timeout); const char * tcp_receive(p_socket sock, char *data, size_t r_len, int timeout); const char * tcp_raw_receive(p_socket sock, char * data, size_t r_len, int timeout, int *received); const char * tcp_listen(p_socket sock, int backlog); const char * tcp_accept(p_socket sock, p_socket client, int timeout); const char * tcp_connect(p_socket sock, const char *host, unsigned short port, int timeout); const char * tcp_create_and_connect(p_socket sock, const char *host, unsigned short port, int timeout); #endif thrift-0.16.0/lib/lua/src/usocket.c000066400000000000000000000252041420101504100170240ustar00rootroot00000000000000// // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #include #include #include #include #include #include #include #include #include // TODO REMOVE #include "socket.h" //////////////////////////////////////////////////////////////////////////////// // Private // Num seconds since Jan 1 1970 (UTC) #ifdef _WIN32 // SOL #else double __gettime() { struct timeval v; gettimeofday(&v, (struct timezone*) NULL); return v.tv_sec + v.tv_usec/1.0e6; } #endif #define WAIT_MODE_R 1 #define WAIT_MODE_W 2 #define WAIT_MODE_C (WAIT_MODE_R|WAIT_MODE_W) T_ERRCODE socket_wait(p_socket sock, int mode, int timeout) { int ret = 0; fd_set rfds, wfds; struct timeval tv; double end, t; if (!timeout) { return TIMEOUT; } end = __gettime() + timeout/1000; do { FD_ZERO(&rfds); FD_ZERO(&wfds); // Specify what I/O operations we care about if (mode & WAIT_MODE_R) { FD_SET(*sock, &rfds); } if (mode & WAIT_MODE_W) { FD_SET(*sock, &wfds); } // Check for timeout t = end - __gettime(); if (t < 0.0) { break; } // Wait tv.tv_sec = (int)t; tv.tv_usec = (int)((t - tv.tv_sec) * 1.0e6); ret = select(*sock+1, &rfds, &wfds, NULL, &tv); } while (ret == -1 && errno == EINTR); if (ret == -1) { return errno; } // Check for timeout if (ret == 0) { return TIMEOUT; } return SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // General T_ERRCODE socket_create(p_socket sock, int domain, int type, int protocol) { *sock = socket(domain, type, protocol); if (*sock > 0) { return SUCCESS; } else { return errno; } } T_ERRCODE socket_destroy(p_socket sock) { // TODO Figure out if I should be free-ing this if (*sock > 0) { (void)socket_setblocking(sock); close(*sock); *sock = -1; } return SUCCESS; } T_ERRCODE socket_bind(p_socket sock, p_sa addr, int addr_len) { int ret = socket_setblocking(sock); if (ret != SUCCESS) { return ret; } if (bind(*sock, addr, addr_len)) { ret = errno; } int ret2 = socket_setnonblocking(sock); return ret == SUCCESS ? ret2 : ret; } T_ERRCODE socket_get_info(p_socket sock, short *port, char *buf, size_t len) { struct sockaddr_storage sa; memset(&sa, 0, sizeof(sa)); socklen_t addrlen = sizeof(sa); int rc = getsockname(*sock, (struct sockaddr*)&sa, &addrlen); if (!rc) { if (sa.ss_family == AF_INET6) { struct sockaddr_in6* sin = (struct sockaddr_in6*)(&sa); if (!inet_ntop(AF_INET6, &sin->sin6_addr, buf, len)) { return errno; } *port = ntohs(sin->sin6_port); } else { struct sockaddr_in* sin = (struct sockaddr_in*)(&sa); if (!inet_ntop(AF_INET, &sin->sin_addr, buf, len)) { return errno; } *port = ntohs(sin->sin_port); } return SUCCESS; } return errno; } //////////////////////////////////////////////////////////////////////////////// // Server T_ERRCODE socket_accept(p_socket sock, p_socket client, p_sa addr, socklen_t *addrlen, int timeout) { int err; if (*sock < 0) { return CLOSED; } do { *client = accept(*sock, addr, addrlen); if (*client > 0) { return SUCCESS; } } while ((err = errno) == EINTR); if (err == EAGAIN || err == ECONNABORTED) { return socket_wait(sock, WAIT_MODE_R, timeout); } return err; } T_ERRCODE socket_listen(p_socket sock, int backlog) { int ret = socket_setblocking(sock); if (ret != SUCCESS) { return ret; } if (listen(*sock, backlog)) { ret = errno; } int ret2 = socket_setnonblocking(sock); return ret == SUCCESS ? ret2 : ret; } //////////////////////////////////////////////////////////////////////////////// // Client T_ERRCODE socket_connect(p_socket sock, p_sa addr, int addr_len, int timeout) { int err; if (*sock < 0) { return CLOSED; } do { if (connect(*sock, addr, addr_len) == 0) { return SUCCESS; } } while ((err = errno) == EINTR); if (err != EINPROGRESS && err != EAGAIN) { return err; } return socket_wait(sock, WAIT_MODE_C, timeout); } T_ERRCODE socket_send( p_socket sock, const char *data, size_t len, int timeout) { int err, put = 0; if (*sock < 0) { return CLOSED; } do { put = send(*sock, data, len, 0); if (put > 0) { return SUCCESS; } } while ((err = errno) == EINTR); if (err == EAGAIN) { return socket_wait(sock, WAIT_MODE_W, timeout); } return err; } T_ERRCODE socket_recv( p_socket sock, char *data, size_t len, int timeout, int *received) { int err, got = 0; if (*sock < 0) { return CLOSED; } *received = 0; do { got = recv(*sock, data, len, 0); if (got > 0) { *received = got; return SUCCESS; } err = errno; // Connection has been closed by peer if (got == 0) { return CLOSED; } } while (err == EINTR); if (err == EAGAIN) { return socket_wait(sock, WAIT_MODE_R, timeout); } return err; } //////////////////////////////////////////////////////////////////////////////// // Util T_ERRCODE socket_setnonblocking(p_socket sock) { int flags = fcntl(*sock, F_GETFL, 0); flags |= O_NONBLOCK; return fcntl(*sock, F_SETFL, flags) != -1 ? SUCCESS : errno; } T_ERRCODE socket_setblocking(p_socket sock) { int flags = fcntl(*sock, F_GETFL, 0); flags &= (~(O_NONBLOCK)); return fcntl(*sock, F_SETFL, flags) != -1 ? SUCCESS : errno; } //////////////////////////////////////////////////////////////////////////////// // TCP #define ERRORSTR_RETURN(err) \ if (err == SUCCESS) { \ return NULL; \ } else if (err == TIMEOUT) { \ return TIMEOUT_MSG; \ } else if (err == CLOSED) { \ return CLOSED_MSG; \ } \ return strerror(err) const char * tcp_create(p_socket sock) { // TODO support IPv6 int err = socket_create(sock, AF_INET, SOCK_STREAM, 0); ERRORSTR_RETURN(err); } const char * tcp_destroy(p_socket sock) { int err = socket_destroy(sock); ERRORSTR_RETURN(err); } const char * tcp_bind(p_socket sock, const char *host, unsigned short port) { // TODO support IPv6 int err; struct hostent *h; struct sockaddr_in local; memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(port); if (strcmp(host, "*") && !inet_aton(host, &local.sin_addr)) { h = gethostbyname(host); if (!h) { return hstrerror(h_errno); } memcpy(&local.sin_addr, (struct in_addr *)h->h_addr_list[0], sizeof(struct in_addr)); } err = socket_bind(sock, (p_sa) &local, sizeof(local)); ERRORSTR_RETURN(err); } const char * tcp_listen(p_socket sock, int backlog) { int err = socket_listen(sock, backlog); ERRORSTR_RETURN(err); } const char * tcp_accept(p_socket sock, p_socket client, int timeout) { int err = socket_accept(sock, client, NULL, NULL, timeout); ERRORSTR_RETURN(err); } const char * tcp_connect(p_socket sock, const char *host, unsigned short port, int timeout) { // TODO support IPv6 int err; struct hostent *h; struct sockaddr_in remote; memset(&remote, 0, sizeof(remote)); remote.sin_family = AF_INET; remote.sin_port = htons(port); if (strcmp(host, "*") && !inet_aton(host, &remote.sin_addr)) { h = gethostbyname(host); if (!h) { return hstrerror(h_errno); } memcpy(&remote.sin_addr, (struct in_addr *)h->h_addr_list[0], sizeof(struct in_addr)); } err = socket_connect(sock, (p_sa) &remote, sizeof(remote), timeout); ERRORSTR_RETURN(err); } const char * tcp_create_and_connect(p_socket sock, const char *host, unsigned short port, int timeout) { int err; struct sockaddr_in sa4; struct sockaddr_in6 sa6; memset(&sa4, 0, sizeof(sa4)); sa4.sin_family = AF_INET; sa4.sin_port = htons(port); memset(&sa6, 0, sizeof(sa6)); sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(port); if (inet_pton(AF_INET, host, &sa4.sin_addr)) { socket_create(sock, AF_INET, SOCK_STREAM, 0); err = socket_connect(sock, (p_sa) &sa4, sizeof(sa4), timeout); ERRORSTR_RETURN(err); } else if (inet_pton(AF_INET6, host, &sa6.sin6_addr)) { socket_create(sock, AF_INET6, SOCK_STREAM, 0); err = socket_connect(sock, (p_sa) &sa6, sizeof(sa6), timeout); ERRORSTR_RETURN(err); } else { struct addrinfo hints, *servinfo, *rp; char portStr[6]; int rv; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; sprintf(portStr, "%u", port); if ((rv = getaddrinfo(host, portStr, &hints, &servinfo)) != 0) { return gai_strerror(rv); } err = TIMEOUT; for (rp = servinfo; rp != NULL; rp = rp->ai_next) { err = socket_create(sock, rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (err != SUCCESS) { continue; } err = socket_connect(sock, (p_sa) rp->ai_addr, rp->ai_addrlen, timeout); if (err == SUCCESS) { break; } close(*sock); } freeaddrinfo(servinfo); if (rp == NULL) { *sock = -1; return "Failed to connect"; } else { ERRORSTR_RETURN(err); } } } #define WRITE_STEP 8192 const char * tcp_send( p_socket sock, const char * data, size_t w_len, int timeout) { int err; size_t put = 0, step; if (!w_len) { return NULL; } do { step = (WRITE_STEP < w_len - put ? WRITE_STEP : w_len - put); err = socket_send(sock, data + put, step, timeout); put += step; } while (err == SUCCESS && put < w_len); ERRORSTR_RETURN(err); } const char * tcp_raw_receive( p_socket sock, char * data, size_t r_len, int timeout, int *received) { int err = socket_recv(sock, data, r_len, timeout, received); ERRORSTR_RETURN(err); } thrift-0.16.0/lib/netstd/000077500000000000000000000000001420101504100151315ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Benchmarks/000077500000000000000000000000001420101504100172065ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Benchmarks/Thrift.Benchmarks/000077500000000000000000000000001420101504100225225ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Benchmarks/Thrift.Benchmarks/CompactProtocolBenchmarks.cs000066400000000000000000000047041420101504100301640ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.IO; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Thrift.Protocol; using Thrift.Transport.Client; namespace Thrift.Benchmarks { [MemoryDiagnoser] public class CompactProtocolBenchmarks { private MemoryStream? _Stream; private TProtocol? _Protocol; [Params(10000)] public int NumberOfOperationsPerIteration { get; set; } [GlobalSetup] public void GlobalSetup() { _Stream = new MemoryStream(); var transport = new TStreamTransport(_Stream, _Stream, null); _Protocol = new TCompactProtocol(transport); } [GlobalCleanup] public void GlobalCleanup() { _Protocol?.Dispose(); } [Benchmark] public async Task WriteString() { if ((_Protocol is null) || (_Stream is null)) throw new System.Exception("unexpected internal state"); for (int i = 0; i < NumberOfOperationsPerIteration; i++) { await _Protocol.WriteStringAsync("Thrift String Benchmark"); _Stream.Seek(0, SeekOrigin.Begin); } } [Benchmark] public async Task ReadString() { if ((_Protocol is null) || (_Stream is null)) throw new System.Exception("unexpected internal state"); await _Protocol.WriteStringAsync("Thrift String Benchmark"); for (int i = 0; i < NumberOfOperationsPerIteration; i++) { _Stream.Seek(0, SeekOrigin.Begin); await _Protocol.ReadStringAsync(); } } } } thrift-0.16.0/lib/netstd/Benchmarks/Thrift.Benchmarks/Program.cs000066400000000000000000000017741420101504100244710ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using BenchmarkDotNet.Running; namespace Thrift.Benchmarks { internal static class Program { public static void Main(string[] args) { BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); } } } thrift-0.16.0/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj000066400000000000000000000026601420101504100272640ustar00rootroot00000000000000 Exe net6.0 false true enable thrift-0.16.0/lib/netstd/Directory.Build.props000066400000000000000000000002461420101504100212220ustar00rootroot00000000000000 thrift-0.16.0/lib/netstd/Makefile.am000066400000000000000000000051221420101504100171650ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . all-local: $(DOTNETCORE) build -c Release check-local: $(DOTNETCORE) test Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj $(DOTNETCORE) test Tests/Thrift.Tests/Thrift.Tests.csproj $(DOTNETCORE) test Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj clean-local: $(RM) -r Thrift/bin $(RM) -r Thrift/obj $(RM) -r Benchmarks/Thrift.Benchmarks/bin $(RM) -r Benchmarks/Thrift.Benchmarks/obj $(RM) -r Tests/Thrift.Tests/bin $(RM) -r Tests/Thrift.Tests/obj $(RM) -r Tests/Thrift.IntegrationTests/bin $(RM) -r Tests/Thrift.IntegrationTests/obj $(RM) -r Tests/Thrift.PublicInterfaces.Compile.Tests/bin $(RM) -r Tests/Thrift.PublicInterfaces.Compile.Tests/obj EXTRA_DIST = \ README.md \ Directory.Build.props \ Benchmarks/Thrift.Benchmarks \ Tests/Thrift.IntegrationTests/Protocols \ Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj \ Tests/Thrift.PublicInterfaces.Compile.Tests \ Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift \ Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift \ Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs \ Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj \ Tests/Thrift.Tests/Collections \ Tests/Thrift.Tests/DataModel \ Tests/Thrift.Tests/Protocols \ Tests/Thrift.Tests/Transports \ Tests/Thrift.Tests/Thrift.Tests.csproj \ Thrift/.editorconfig \ Thrift/Collections \ Thrift/Processor \ Thrift/Properties \ Thrift/Protocol \ Thrift/Server \ Thrift/GlobalSuppressions.cs \ Thrift/TApplicationException.cs \ Thrift/TBaseClient.cs \ Thrift/TConfiguration.cs \ Thrift/TException.cs \ Thrift/Thrift.csproj \ Thrift/Transport \ Thrift/*.snk \ Thrift.sln \ build.cmd \ build.sh \ runtests.cmd \ runtests.sh thrift-0.16.0/lib/netstd/README.md000066400000000000000000000065171420101504100164210ustar00rootroot00000000000000# Apache Thrift netstd Thrift client library for Microsoft .NET Standard # Build the library ## How to build on Windows - Get Thrift IDL compiler executable, add to some folder and add path to this folder into PATH variable - Open the Thrift.sln project with Visual Studio and build. or - Build with scripts ## How to build on Unix/Linux - Ensure you have .NET Core SDK 3.1 (LTS) installed, or use the [Ubuntu docker image](../../build/docker/README.md) - Follow common automake build practice: `./ bootstrap && ./ configure && make` ## Known issues - In trace logging mode you can see some not important internal exceptions # Migration to netstd ## ... from netcore If you are migrating your code from netcore library, you will have to: - Switch to `thrift -gen netstd` - the following compiler flags are no longer needed or supported: `hashcode` is now standard, while `nullable` is no longer supported. - the `Thrift.Transport` and `Thrift.Protocol` namespaces now use the singular form - add `using Thrift.Processor;` in the server code where appropriate - rename all `T*ClientTransport` to `T*Transport` - rename all `TBaseServer` occurrences in your code to `TServer` - the `SingletonTProcessorFactory` is now called `TSingletonProcessorFactory` - and the `AsyncBaseServer` is now the `TSimpleAsyncServer` You may wonder why we changed so many names. The naming scheme has been revised for two reasons: First, we want to get back the established, well-known naming consistency across the Thrift libraries which the netcore library did not fully respect. Second, by achieving that first objective, we get the additional benefit of making migration at least a bit easier for C# projects. ## ... from csharp Because of the different environment requirements, migration from C# takes slightly more efforts. While the code changes related to Thrift itself are moderate, you may need to upgrade certain dependencies, components or even modules to more recent versions. 1. Client and server applications must use at least framework 4.6.1, any version below will not work. 1. Switch to `thrift -gen netstd`. The following compiler flags are no longer needed or supported: `hashcode` and `async` are now standard, while `nullable` is no longer supported. 1. [Familiarize yourself with the `async/await` model](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx), if you have not already done so. As netstd does not support `ISync` anymore, async is mandatory. The synchronous model is simply no longer available (that's also the reason why we don't need the `async` flag anymore). 1. Consider proper use of `cancellationToken` parameters. They are optional but may be quite helpful. 1. As you probably already guessed, there are a few names that have been changed: - add `using Thrift.Processor;` in the server code where appropriate - the `TServerSocket` is now called `TServerSocketTransport` - change `IProtocolFactory` into `ITProtocolFactory` - if you are looking for `TSimpleServer`, try `TSimpleAsyncServer` instead - similarly, the `TThreadPoolServer` is now a `TThreadPoolAsyncServer` - the server's `Serve()` method does now `ServeAsync()` - In case you are using Thrift server event handlers: the `SetEventHandler` method now starts with an uppercase letter - and you will also have to revise the method names of all `TServerEventHandler` descendants you have in your code thrift-0.16.0/lib/netstd/Tests/000077500000000000000000000000001420101504100162335ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.IntegrationTests/000077500000000000000000000000001420101504100230005ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.IntegrationTests/Protocols/000077500000000000000000000000001420101504100247645ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.IntegrationTests/Protocols/ProtocolsOperationsTests.cs000066400000000000000000000433601420101504100323740ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.IO; using System.Text; using System.Threading.Tasks; using KellermanSoftware.CompareNetObjects; using Microsoft.VisualStudio.TestTools.UnitTesting; using Thrift.Protocol; using Thrift.Protocol.Entities; using Thrift.Transport.Client; #pragma warning disable IDE0063 // using namespace Thrift.IntegrationTests.Protocols { [TestClass] public class ProtocolsOperationsTests { private readonly CompareLogic _compareLogic = new(); private static readonly TConfiguration Configuration = new(); [DataTestMethod] [DataRow(typeof(TBinaryProtocol), TMessageType.Call)] [DataRow(typeof(TBinaryProtocol), TMessageType.Exception)] [DataRow(typeof(TBinaryProtocol), TMessageType.Oneway)] [DataRow(typeof(TBinaryProtocol), TMessageType.Reply)] [DataRow(typeof(TCompactProtocol), TMessageType.Call)] [DataRow(typeof(TCompactProtocol), TMessageType.Exception)] [DataRow(typeof(TCompactProtocol), TMessageType.Oneway)] [DataRow(typeof(TCompactProtocol), TMessageType.Reply)] [DataRow(typeof(TJsonProtocol), TMessageType.Call)] [DataRow(typeof(TJsonProtocol), TMessageType.Exception)] [DataRow(typeof(TJsonProtocol), TMessageType.Oneway)] [DataRow(typeof(TJsonProtocol), TMessageType.Reply)] public async Task WriteReadMessage_Test(Type protocolType, TMessageType messageType) { var expected = new TMessage(nameof(TMessage), messageType, 1); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteMessageBeginAsync(expected, default); await protocol.WriteMessageEndAsync(default); stream.Seek(0, SeekOrigin.Begin); var actualMessage = await protocol.ReadMessageBeginAsync(default); await protocol.ReadMessageEndAsync(default); var result = _compareLogic.Compare(expected, actualMessage); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] [ExpectedException(typeof(Exception))] public async Task WriteReadStruct_Test(Type protocolType) { var expected = new TStruct(nameof(TStruct)); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteStructBeginAsync(expected, default); await protocol.WriteStructEndAsync(default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadStructBeginAsync(default); await protocol.ReadStructEndAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] [ExpectedException(typeof(Exception))] public async Task WriteReadField_Test(Type protocolType) { var expected = new TField(nameof(TField), TType.String, 1); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteFieldBeginAsync(expected, default); await protocol.WriteFieldEndAsync(default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadFieldBeginAsync(default); await protocol.ReadFieldEndAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadMap_Test(Type protocolType) { var expected = new TMap(TType.String, TType.String, 1); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteMapBeginAsync(expected, default); await protocol.WriteMapEndAsync(default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadMapBeginAsync(default); await protocol.ReadMapEndAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadList_Test(Type protocolType) { var expected = new TList(TType.String, 1); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteListBeginAsync(expected, default); await protocol.WriteListEndAsync(default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadListBeginAsync(default); await protocol.ReadListEndAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadSet_Test(Type protocolType) { var expected = new TSet(TType.String, 1); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteSetBeginAsync(expected, default); await protocol.WriteSetEndAsync(default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadSetBeginAsync(default); await protocol.ReadSetEndAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadBool_Test(Type protocolType) { var expected = true; try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteBoolAsync(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadBoolAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadByte_Test(Type protocolType) { var expected = sbyte.MaxValue; try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteByteAsync(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadByteAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadI16_Test(Type protocolType) { var expected = short.MaxValue; try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteI16Async(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadI16Async(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadI32_Test(Type protocolType) { var expected = int.MaxValue; try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteI32Async(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadI32Async(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadI64_Test(Type protocolType) { var expected = long.MaxValue; try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteI64Async(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadI64Async(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadDouble_Test(Type protocolType) { var expected = double.MaxValue; try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteDoubleAsync(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadDoubleAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadString_Test(Type protocolType) { var expected = nameof(String); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteStringAsync(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadStringAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } [DataTestMethod] [DataRow(typeof(TBinaryProtocol))] [DataRow(typeof(TCompactProtocol))] [DataRow(typeof(TJsonProtocol))] public async Task WriteReadBinary_Test(Type protocolType) { var expected = Encoding.UTF8.GetBytes(nameof(String)); try { var tuple = GetProtocolInstance(protocolType); using (var stream = tuple.Item1) { var protocol = tuple.Item2; await protocol.WriteBinaryAsync(expected, default); stream?.Seek(0, SeekOrigin.Begin); var actual = await protocol.ReadBinaryAsync(default); var result = _compareLogic.Compare(expected, actual); Assert.IsTrue(result.AreEqual, result.DifferencesString); } } catch (Exception e) { throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e); } } private static Tuple GetProtocolInstance(Type protocolType) { var memoryStream = new MemoryStream(); var streamClientTransport = new TStreamTransport(memoryStream, memoryStream,Configuration); if( Activator.CreateInstance(protocolType, streamClientTransport) is TProtocol protocol) return new Tuple(memoryStream, protocol); throw new Exception("Unexpected"); } } } thrift-0.16.0/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj000066400000000000000000000044711420101504100307750ustar00rootroot00000000000000 net6.0 Thrift.IntegrationTests Thrift.IntegrationTests 0.16.0.0 Exe false false false false false false enable thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/000077500000000000000000000000001420101504100254045ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift000066400000000000000000000721311420101504100313710ustar00rootroot00000000000000#!/usr/local/bin/thrift --java --php --py # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # *** PLEASE REMEMBER TO EDIT THE VERSION CONSTANT WHEN MAKING CHANGES *** # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Interface definition for Cassandra Service # namespace netstd Apache.Cassandra.Test # Thrift.rb has a bug where top-level modules that include modules # with the same name are not properly referenced, so we can't do # Cassandra::Cassandra::Client. namespace rb CassandraThrift # The API version (NOT the product version), composed as a dot delimited # string with major, minor, and patch level components. # # - Major: Incremented for backward incompatible changes. An example would # be changes to the number or disposition of method arguments. # - Minor: Incremented for backward compatible changes. An example would # be the addition of a new (optional) method. # - Patch: Incremented for bug fixes. The patch level should be increased # for every edit that doesn't result in a change to major/minor. # # See the Semantic Versioning Specification (SemVer) http://semver.org. const string VERSION = "19.24.0" # # data structures # /** Basic unit of data within a ColumnFamily. * @param name, the name by which this column is set and retrieved. Maximum 64KB long. * @param value. The data associated with the name. Maximum 2GB long, but in practice you should limit it to small numbers of MB (since Thrift must read the full value into memory to operate on it). * @param timestamp. The timestamp is used for conflict detection/resolution when two columns with same name need to be compared. * @param ttl. An optional, positive delay (in seconds) after which the column will be automatically deleted. */ struct Column { 1: required binary name, 2: optional binary value, 3: optional i64 timestamp, 4: optional i32 ttl, } /** A named list of columns. * @param name. see Column.name. * @param columns. A collection of standard Columns. The columns within a super column are defined in an adhoc manner. * Columns within a super column do not have to have matching structures (similarly named child columns). */ struct SuperColumn { 1: required binary name, 2: required list columns, } struct CounterColumn { 1: required binary name, 2: required i64 value } struct CounterSuperColumn { 1: required binary name, 2: required list columns } /** Methods for fetching rows/records from Cassandra will return either a single instance of ColumnOrSuperColumn or a list of ColumnOrSuperColumns (get_slice()). If you're looking up a SuperColumn (or list of SuperColumns) then the resulting instances of ColumnOrSuperColumn will have the requested SuperColumn in the attribute super_column. For queries resulting in Columns, those values will be in the attribute column. This change was made between 0.3 and 0.4 to standardize on single query methods that may return either a SuperColumn or Column. If the query was on a counter column family, you will either get a counter_column (instead of a column) or a counter_super_column (instead of a super_column) @param column. The Column returned by get() or get_slice(). @param super_column. The SuperColumn returned by get() or get_slice(). @param counter_column. The Counterolumn returned by get() or get_slice(). @param counter_super_column. The CounterSuperColumn returned by get() or get_slice(). */ struct ColumnOrSuperColumn { 1: optional Column column, 2: optional SuperColumn super_column, 3: optional CounterColumn counter_column, 4: optional CounterSuperColumn counter_super_column } # # Exceptions # (note that internal server errors will raise a TApplicationException, courtesy of Thrift) # /** A specific column was requested that does not exist. */ exception NotFoundException { } /** Invalid request could mean keyspace or column family does not exist, required parameters are missing, or a parameter is malformed. why contains an associated error message. */ exception InvalidRequestException { 1: required string why } /** Not all the replicas required could be created and/or read. */ exception UnavailableException { } /** RPC timeout was exceeded. either a node failed mid-operation, or load was too high, or the requested op was too large. */ exception TimedOutException { } /** invalid authentication request (invalid keyspace, user does not exist, or credentials invalid) */ exception AuthenticationException { 1: required string why } /** invalid authorization request (user does not have access to keyspace) */ exception AuthorizationException { 1: required string why } /** schemas are not in agreement across all nodes */ exception SchemaDisagreementException { } # # service api # /** * The ConsistencyLevel is an enum that controls both read and write * behavior based on the ReplicationFactor of the keyspace. The * different consistency levels have different meanings, depending on * if you're doing a write or read operation. * * If W + R > ReplicationFactor, where W is the number of nodes to * block for on write, and R the number to block for on reads, you * will have strongly consistent behavior; that is, readers will * always see the most recent write. Of these, the most interesting is * to do QUORUM reads and writes, which gives you consistency while * still allowing availability in the face of node failures up to half * of . Of course if latency is more important than * consistency then you can use lower values for either or both. * * Some ConsistencyLevels (ONE, TWO, THREE) refer to a specific number * of replicas rather than a logical concept that adjusts * automatically with the replication factor. Of these, only ONE is * commonly used; TWO and (even more rarely) THREE are only useful * when you care more about guaranteeing a certain level of * durability, than consistency. * * Write consistency levels make the following guarantees before reporting success to the client: * ANY Ensure that the write has been written once somewhere, including possibly being hinted in a non-target node. * ONE Ensure that the write has been written to at least 1 node's commit log and memory table * TWO Ensure that the write has been written to at least 2 node's commit log and memory table * THREE Ensure that the write has been written to at least 3 node's commit log and memory table * QUORUM Ensure that the write has been written to / 2 + 1 nodes * LOCAL_QUORUM Ensure that the write has been written to / 2 + 1 nodes, within the local datacenter (requires NetworkTopologyStrategy) * EACH_QUORUM Ensure that the write has been written to / 2 + 1 nodes in each datacenter (requires NetworkTopologyStrategy) * ALL Ensure that the write is written to <ReplicationFactor> nodes before responding to the client. * * Read consistency levels make the following guarantees before returning successful results to the client: * ANY Not supported. You probably want ONE instead. * ONE Returns the record obtained from a single replica. * TWO Returns the record with the most recent timestamp once two replicas have replied. * THREE Returns the record with the most recent timestamp once three replicas have replied. * QUORUM Returns the record with the most recent timestamp once a majority of replicas have replied. * LOCAL_QUORUM Returns the record with the most recent timestamp once a majority of replicas within the local datacenter have replied. * EACH_QUORUM Returns the record with the most recent timestamp once a majority of replicas within each datacenter have replied. * ALL Returns the record with the most recent timestamp once all replicas have replied (implies no replica may be down).. */ enum ConsistencyLevel { ONE = 1, QUORUM = 2, LOCAL_QUORUM = 3, EACH_QUORUM = 4, ALL = 5, ANY = 6, TWO = 7, THREE = 8, } /** ColumnParent is used when selecting groups of columns from the same ColumnFamily. In directory structure terms, imagine ColumnParent as ColumnPath + '/../'. See also ColumnPath */ struct ColumnParent { 3: required string column_family, 4: optional binary super_column, } /** The ColumnPath is the path to a single column in Cassandra. It might make sense to think of ColumnPath and * ColumnParent in terms of a directory structure. * * ColumnPath is used to looking up a single column. * * @param column_family. The name of the CF of the column being looked up. * @param super_column. The super column name. * @param column. The column name. */ struct ColumnPath { 3: required string column_family, 4: optional binary super_column, 5: optional binary column, } /** A slice range is a structure that stores basic range, ordering and limit information for a query that will return multiple columns. It could be thought of as Cassandra's version of LIMIT and ORDER BY @param start. The column name to start the slice with. This attribute is not required, though there is no default value, and can be safely set to '', i.e., an empty byte array, to start with the first column name. Otherwise, it must a valid value under the rules of the Comparator defined for the given ColumnFamily. @param finish. The column name to stop the slice at. This attribute is not required, though there is no default value, and can be safely set to an empty byte array to not stop until 'count' results are seen. Otherwise, it must also be a valid value to the ColumnFamily Comparator. @param reversed. Whether the results should be ordered in reversed order. Similar to ORDER BY blah DESC in SQL. @param count. How many columns to return. Similar to LIMIT in SQL. May be arbitrarily large, but Thrift will materialize the whole result into memory before returning it to the client, so be aware that you may be better served by iterating through slices by passing the last value of one call in as the 'start' of the next instead of increasing 'count' arbitrarily large. */ struct SliceRange { 1: required binary start, 2: required binary finish, 3: required bool reversed=0, 4: required i32 count=100, } /** A SlicePredicate is similar to a mathematic predicate (see http://en.wikipedia.org/wiki/Predicate_(mathematical_logic)), which is described as "a property that the elements of a set have in common." SlicePredicate's in Cassandra are described with either a list of column_names or a SliceRange. If column_names is specified, slice_range is ignored. @param column_name. A list of column names to retrieve. This can be used similar to Memcached's "multi-get" feature to fetch N known column names. For instance, if you know you wish to fetch columns 'Joe', 'Jack', and 'Jim' you can pass those column names as a list to fetch all three at once. @param slice_range. A SliceRange describing how to range, order, and/or limit the slice. */ struct SlicePredicate { 1: optional list column_names, 2: optional SliceRange slice_range, } enum IndexOperator { EQ, GTE, GT, LTE, LT } struct IndexExpression { 1: required binary column_name, 2: required IndexOperator op, 3: required binary value, } struct IndexClause { 1: required list expressions 2: required binary start_key, 3: required i32 count=100, } /** The semantics of start keys and tokens are slightly different. Keys are start-inclusive; tokens are start-exclusive. Token ranges may also wrap -- that is, the end token may be less than the start one. Thus, a range from keyX to keyX is a one-element range, but a range from tokenY to tokenY is the full ring. */ struct KeyRange { 1: optional binary start_key, 2: optional binary end_key, 3: optional string start_token, 4: optional string end_token, 5: required i32 count=100 } /** A KeySlice is key followed by the data it maps to. A collection of KeySlice is returned by the get_range_slice operation. @param key. a row key @param columns. List of data represented by the key. Typically, the list is pared down to only the columns specified by a SlicePredicate. */ struct KeySlice { 1: required binary key, 2: required list columns, } struct KeyCount { 1: required binary key, 2: required i32 count } /** * Note that the timestamp is only optional in case of counter deletion. */ struct Deletion { 1: optional i64 timestamp, 2: optional binary super_column, 3: optional SlicePredicate predicate, } /** A Mutation is either an insert (represented by filling column_or_supercolumn) or a deletion (represented by filling the deletion attribute). @param column_or_supercolumn. An insert to a column or supercolumn (possibly counter column or supercolumn) @param deletion. A deletion of a column or supercolumn */ struct Mutation { 1: optional ColumnOrSuperColumn column_or_supercolumn, 2: optional Deletion deletion, } struct EndpointDetails { 1: string host, 2: string datacenter, 3: optional string rack } /** A TokenRange describes part of the Cassandra ring, it is a mapping from a range to endpoints responsible for that range. @param start_token The first token in the range @param end_token The last token in the range @param endpoints The endpoints responsible for the range (listed by their configured listen_address) @param rpc_endpoints The endpoints responsible for the range (listed by their configured rpc_address) */ struct TokenRange { 1: required string start_token, 2: required string end_token, 3: required list endpoints, 4: optional list rpc_endpoints 5: optional list endpoint_details, } /** Authentication requests can contain any data, dependent on the IAuthenticator used */ struct AuthenticationRequest { 1: required map credentials } enum IndexType { KEYS, CUSTOM } /* describes a column in a column family. */ struct ColumnDef { 1: required binary name, 2: required string validation_class, 3: optional IndexType index_type, 4: optional string index_name, 5: optional map index_options } /* describes a column family. */ struct CfDef { 1: required string keyspace, 2: required string name, 3: optional string column_type="Standard", 5: optional string comparator_type="BytesType", 6: optional string subcomparator_type, 8: optional string comment, 12: optional double read_repair_chance=1.0, 13: optional list column_metadata, 14: optional i32 gc_grace_seconds, 15: optional string default_validation_class, 16: optional i32 id, 17: optional i32 min_compaction_threshold, 18: optional i32 max_compaction_threshold, 24: optional bool replicate_on_write, 25: optional double merge_shards_chance, 26: optional string key_validation_class, 28: optional binary key_alias, 29: optional string compaction_strategy, 30: optional map compaction_strategy_options, 32: optional map compression_options, 33: optional double bloom_filter_fp_chance, } /* describes a keyspace. */ struct KsDef { 1: required string name, 2: required string strategy_class, 3: optional map strategy_options, /** @deprecated */ 4: optional i32 replication_factor, 5: required list cf_defs, 6: optional bool durable_writes=1, } /** CQL query compression */ enum Compression { GZIP = 1, NONE = 2 } enum CqlResultType { ROWS = 1, VOID = 2, INT = 3 } /** Row returned from a CQL query */ struct CqlRow { 1: required binary key, 2: required list columns } struct CqlMetadata { 1: required map name_types, 2: required map value_types, 3: required string default_name_type, 4: required string default_value_type } struct CqlResult { 1: required CqlResultType type, 2: optional list rows, 3: optional i32 num, 4: optional CqlMetadata schema } struct CqlPreparedResult { 1: required i32 itemId, 2: required i32 count } service Cassandra { # auth methods void login(1: required AuthenticationRequest auth_request) throws (1:AuthenticationException authnx, 2:AuthorizationException authzx), # set keyspace void set_keyspace(1: required string keyspace) throws (1:InvalidRequestException ire), # retrieval methods /** Get the Column or SuperColumn at the given column_path. If no value is present, NotFoundException is thrown. (This is the only method that can throw an exception under non-failure conditions.) */ ColumnOrSuperColumn get(1:required binary key, 2:required ColumnPath column_path, 3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:NotFoundException nfe, 3:UnavailableException ue, 4:TimedOutException te), /** Get the group of columns contained by column_parent (either a ColumnFamily name or a ColumnFamily/SuperColumn name pair) specified by the given SlicePredicate. If no matching values are found, an empty list is returned. */ list get_slice(1:required binary key, 2:required ColumnParent column_parent, 3:required SlicePredicate predicate, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** returns the number of columns matching predicate for a particular key, ColumnFamily and optionally SuperColumn. */ i32 get_count(1:required binary key, 2:required ColumnParent column_parent, 3:required SlicePredicate predicate, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** Performs a get_slice for column_parent and predicate for the given keys in parallel. */ map> multiget_slice(1:required list keys, 2:required ColumnParent column_parent, 3:required SlicePredicate predicate, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** Perform a get_count in parallel on the given list keys. The return value maps keys to the count found. */ map multiget_count(1:required list keys, 2:required ColumnParent column_parent, 3:required SlicePredicate predicate, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** returns a subset of columns for a contiguous range of keys. */ list get_range_slices(1:required ColumnParent column_parent, 2:required SlicePredicate predicate, 3:required KeyRange range, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** Returns the subset of columns specified in SlicePredicate for the rows matching the IndexClause */ list get_indexed_slices(1:required ColumnParent column_parent, 2:required IndexClause index_clause, 3:required SlicePredicate column_predicate, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), # modification methods /** * Insert a Column at the given column_parent.column_family and optional column_parent.super_column. */ void insert(1:required binary key, 2:required ColumnParent column_parent, 3:required Column column, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** * Increment or decrement a counter. */ void add(1:required binary key, 2:required ColumnParent column_parent, 3:required CounterColumn column, 4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** Remove data from the row specified by key at the granularity specified by column_path, and the given timestamp. Note that all the values in column_path besides column_path.column_family are truly optional: you can remove the entire row by just specifying the ColumnFamily, or you can remove a SuperColumn or a single Column by specifying those levels too. */ void remove(1:required binary key, 2:required ColumnPath column_path, 3:required i64 timestamp, 4:ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** * Remove a counter at the specified location. * Note that counters have limited support for deletes: if you remove a counter, you must wait to issue any following update * until the delete has reached all the nodes and all of them have been fully compacted. */ void remove_counter(1:required binary key, 2:required ColumnPath path, 3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** Mutate many columns or super columns for many row keys. See also: Mutation. mutation_map maps key to column family to a list of Mutation objects to take place at that scope. **/ void batch_mutate(1:required map>> mutation_map, 2:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te), /** Truncate will mark and entire column family as deleted. From the user's perspective a successful call to truncate will result complete data deletion from cfname. Internally, however, disk space will not be immediatily released, as with all deletes in cassandra, this one only marks the data as deleted. The operation succeeds only if all hosts in the cluster at available and will throw an UnavailableException if some hosts are down. */ void truncate(1:required string cfname) throws (1: InvalidRequestException ire, 2: UnavailableException ue, 3: TimedOutException te), // Meta-APIs -- APIs to get information about the node or cluster, // rather than user data. The nodeprobe program provides usage examples. /** * for each schema version present in the cluster, returns a list of nodes at that version. * hosts that do not respond will be under the key DatabaseDescriptor.INITIAL_VERSION. * the cluster is all on the same version if the size of the map is 1. */ map> describe_schema_versions() throws (1: InvalidRequestException ire), /** list the defined keyspaces in this cluster */ list describe_keyspaces() throws (1:InvalidRequestException ire), /** get the cluster name */ string describe_cluster_name(), /** get the thrift api version */ string describe_version(), /** get the token ring: a map of ranges to host addresses, represented as a set of TokenRange instead of a map from range to list of endpoints, because you can't use Thrift structs as map keys: https://issues.apache.org/jira/browse/THRIFT-162 for the same reason, we can't return a set here, even though order is neither important nor predictable. */ list describe_ring(1:required string keyspace) throws (1:InvalidRequestException ire), /** returns the partitioner used by this cluster */ string describe_partitioner(), /** returns the snitch used by this cluster */ string describe_snitch(), /** describe specified keyspace */ KsDef describe_keyspace(1:required string keyspace) throws (1:NotFoundException nfe, 2:InvalidRequestException ire), /** experimental API for hadoop/parallel query support. may change violently and without warning. returns list of token strings such that first subrange is (list[0], list[1]], next is (list[1], list[2]], etc. */ list describe_splits(1:required string cfName, 2:required string start_token, 3:required string end_token, 4:required i32 keys_per_split) throws (1:InvalidRequestException ire), /** adds a column family. returns the new schema id. */ string system_add_column_family(1:required CfDef cf_def) throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), /** drops a column family. returns the new schema id. */ string system_drop_column_family(1:required string column_family) throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), /** adds a keyspace and any column families that are part of it. returns the new schema id. */ string system_add_keyspace(1:required KsDef ks_def) throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), /** drops a keyspace and any column families that are part of it. returns the new schema id. */ string system_drop_keyspace(1:required string keyspace) throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), /** updates properties of a keyspace. returns the new schema id. */ string system_update_keyspace(1:required KsDef ks_def) throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), /** updates properties of a column family. returns the new schema id. */ string system_update_column_family(1:required CfDef cf_def) throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), /** * Executes a CQL (Cassandra Query Language) statement and returns a * CqlResult containing the results. */ CqlResult execute_cql_query(1:required binary query, 2:required Compression compression) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te, 4:SchemaDisagreementException sde) /** * Prepare a CQL (Cassandra Query Language) statement by compiling and returning * - the type of CQL statement * - an id token of the compiled CQL stored on the server side. * - a count of the discovered bound markers in the statement */ CqlPreparedResult prepare_cql_query(1:required binary query, 2:required Compression compression) throws (1:InvalidRequestException ire) /** * Executes a prepared CQL (Cassandra Query Language) statement by passing an id token and a list of variables * to bind and returns a CqlResult containing the results. */ CqlResult execute_prepared_cql_query(1:required i32 itemId, 2:required list values) throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te, 4:SchemaDisagreementException sde) } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/GlobalSuppressions.cs000066400000000000000000000007501420101504100315730ustar00rootroot00000000000000// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Performance", "CA1822", Justification = "", Scope = "module")] [assembly: SuppressMessage("Style", "IDE0090", Justification = "", Scope = "module")] thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Impl/000077500000000000000000000000001420101504100263055ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Impl/Thrift5253/000077500000000000000000000000001420101504100300645ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Impl/Thrift5253/MyService.cs000066400000000000000000000050361420101504100323250ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Threading.Tasks; using Thrift5253; namespace Thrift.PublicInterfaces.Compile.Tests.Impl.Thrift5253 { class MyServiceImpl : MyService.IAsync { public Task AsyncProcessor_(AsyncProcessor input, CancellationToken cancellationToken = default) { return Task.FromResult(new AsyncProcessor() { Foo = input.Foo }); } public Task Broken(BrokenArgs input, CancellationToken cancellationToken = default) { return Task.FromResult(new BrokenResult() { Foo = input.Foo }); } public Task Client_(Client input, CancellationToken cancellationToken = default) { _ = cancellationToken; return Task.FromResult(new Client() { Foo = input.Foo }); } public Task IAsync_(IAsync input, CancellationToken cancellationToken = default) { return Task.FromResult(new IAsync() { Foo = input.Foo }); } public Task InternalStructs_(InternalStructs input, CancellationToken cancellationToken = default) { return Task.FromResult(new InternalStructs() { Foo = input.Foo }); } public Task TestAsync(CancellationToken cancellationToken = default) { return Task.CompletedTask; } public Task TestXsync(CancellationToken cancellationToken = default) { return Task.CompletedTask; } public Task Works(WorksArrrgs input, CancellationToken cancellationToken = default) { return Task.FromResult(new WorksRslt() { Foo = input.Foo }); } } } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/000077500000000000000000000000001420101504100275405ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs000066400000000000000000000032611420101504100324640ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("The Apache Software Foundation")] [assembly: AssemblyProduct("Thrift")] [assembly: AssemblyCopyright("The Apache Software Foundation")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("d0d3706b-fed5-4cf5-b984-04f448de9d7b")]Thrift.PublicInterfaces.Compile.Tests.csproj000066400000000000000000000105041420101504100357200ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests 0.16.0 Thrift version $(ThriftVersion) net6.0 $(ThriftVersion).0 Thrift.PublicInterfaces.Compile.Tests Thrift.PublicInterfaces.Compile.Tests false false false false enable thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5253.thrift000066400000000000000000000033341420101504100304100ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5253 using Result in result name generates wrong IAsync interface namespace * Thrift5253 // this works struct WorksArrrgs { 1: i32 foo } struct WorksRslt { 1: i32 foo } // this does not struct BrokenResult{ 1: i32 foo } struct BrokenArgs { 1: i32 foo } struct InternalStructs { 1: optional i32 foo } struct AsyncProcessor { 1: optional i32 foo } struct Client { 1: optional i32 foo } struct IAsync { 1: optional i32 foo } struct ReservedMemberName { 1: optional i32 Isset } service MyService{ BrokenResult Broken( 1 : BrokenArgs foo) WorksRslt Works( 1 : WorksArrrgs foo) InternalStructs InternalStructs( 1: InternalStructs foo) AsyncProcessor AsyncProcessor ( 1: AsyncProcessor foo) Client Client ( 1: Client foo) IAsync IAsync ( 1: IAsync foo) // inconsistent treatment of methods ending in "Async" void TestXsync() void TestAsync() } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.enum.thrift000066400000000000000000000016471420101504100313530ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code namespace * Thrift5320.enums enum Task { Zero, More } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.exception.thrift000066400000000000000000000017061420101504100324010ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code namespace * Thrift5320.exceptions exception Task { 1: Task left 2: Task right } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.struct.thrift000066400000000000000000000016771420101504100317360ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code namespace * Thrift5320.structs struct Task { 1: Task left 2: Task right } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.thrift000066400000000000000000000022551420101504100304040ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code namespace * Thrift5320.Task include "Thrift5320.enum.thrift" include "Thrift5320.exception.thrift" include "Thrift5320.struct.thrift" enum Foobar { Task = 0 } service Task { Thrift5320.enum.Task Task( 1 : Thrift5320.struct.Task foo, 2: Foobar bar ) throws ( 1: Thrift5320.exception.Task error ) } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.objs.thrift000066400000000000000000000016651420101504100313540ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5382 Netstd default list/set enums values are generated incorrectly namespace * Thrift5382.objs enum FoobarEnum { Val_1 = 0, Val_2 = 1 } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.thrift000066400000000000000000000024351420101504100304140ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5382 Netstd default list/set enums values are generated incorrectly namespace * Thrift5382 include "Thrift5382.objs.thrift" struct RequestModel { // Breaks 1: optional set data_1 = [ FoobarEnum.Val_1, FoobarEnum.Val_2 ], // Breaks 2: optional list data_2 = [ FoobarEnum.Val_1, FoobarEnum.Val_2 ], // Works 3: optional Thrift5382.objs.FoobarEnum data_3 = FoobarEnum.Val_1 } service Test { void CallMe( 1 : RequestModel foo, ) } thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.enum.thrift000066400000000000000000000021621420101504100325560ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcases for // - THRIFT-5091 Netstd generator produces uncompileable code for struct names ending with "_result" or "_args" // - THRIFT-5444 netstd generator produces uncompileable code for enums ending with "_result" or "_args" namespace * name_conflicts_enum enum some_result { foo, bar, baz } enum some_args { foo, bar, baz } // EOF thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.thrift000066400000000000000000000032741420101504100316200ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcases for // - THRIFT-5091 Netstd generator produces uncompileable code for struct names ending with "_result" or "_args" // - THRIFT-5444 netstd generator produces uncompileable code for enums ending with "_result" or "_args" // - THRIFT-5445 "cancellationToken" cannot be used as argument name namespace * name_conflicts include "name_conflicts.enum.thrift" struct some_struct_args { 1: name_conflicts.enum.some_args some_args 2: name_conflicts.enum.some_result some_result 3: required i32 cancellationToken } exception some_error_result { 1: name_conflicts.enum.some_args some_args 2: name_conflicts.enum.some_result some_result 3: optional i32 cancellationToken } service some_service { name_conflicts.enum.some_result some_method( 1: name_conflicts.enum.some_args some_args 2: some_struct_args more_args 3: i32 cancellationToken ) throws ( 1: some_error_result cancellationToken ) } // EOF optional_required_default.thrift000066400000000000000000000133551420101504100340070ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. // Testcase for THRIFT-5216 generate DeepCopy methods namespace netstd OptReqDefTest enum Distance { foo = 0, bar = 1, baz = 2 } struct RaceDetails { // this is really the max field index used here, intentionally placed at the beginning 666: required Distance triplesix // without default values 1: optional Distance opt_one 2: optional double opt_two 3: optional i16 opt_three 4: optional string opt_four 5: optional binary opt_five 6: optional list opt_six 7: optional set opt_seven 8: optional map opt_eight 11: required Distance req_one 12: required double req_two 13: required i16 req_three 14: required string req_four 15: required binary req_five 16: required list req_six 17: required set req_seven 18: required map req_eight 21: Distance def_one 22: double def_two 23: i16 def_three 24: string def_four 25: binary def_five 26: list def_six 27: set def_seven 28: map def_eight // having default values 31: optional Distance opt_one_with_value = Distance.bar 32: optional double opt_two_with_value = 2.22 33: optional i16 opt_three_with_value = 3 34: optional string opt_four_with_value = "four" 35: optional binary opt_five_with_value = "five\t" 36: optional list opt_six_with_value = [6] 37: optional set opt_seven_with_value = [7] 38: optional map opt_eight_with_value = { 8 : 8 } 41: required Distance req_one_with_value = Distance.bar 42: required double req_two_with_value = 2.22 43: required i16 req_three_with_value = 3 44: required string req_four_with_value = "four" 45: required binary req_five_with_value = "five" 46: required list req_six_with_value = [6] 47: required set req_seven_with_value = [7] 48: required map req_eight_with_value = { 8 : 8 } 51: Distance def_one_with_value = Distance.bar 52: double def_two_with_value = 2.22 53: i16 def_three_with_value = 3 54: string def_four_with_value = "four" 55: binary def_five_with_value = "five" 56: list def_six_with_value = [6] 57: set def_seven_with_value = [7] 58: map def_eight_with_value = { 8 : 8 } 90: optional bool last_of_the_mohicans // some more complicated ones, including recursion 300: required list far_list 301: optional set far_set 302: map far_map 310: required set> far_set_list 311: optional list>> far_list_map_set 312: map far_map_dist_to_rds 320: required RaceDetails req_nested 321: optional RaceDetails opt_nested 322: RaceDetails def_nested 330: required jack req_union 331: optional jack opt_union 332: jack def_union } union jack { 1: list stars 2: list stripes 310: set> far_set_list 311: list>> far_list_map_set 312: map far_map_dist_to_rds 320: jack nested_union 321: RaceDetails nested_struct 401: optional Distance opt_one 402: optional double opt_two 403: optional i16 opt_three 404: optional string opt_four 405: optional binary opt_five 406: optional list opt_six 407: optional set opt_seven 408: optional map opt_eight } typedef RaceDetails RaceDetails2 typedef list RDs exception CrashBoomBang { 1 : i32 MyErrorCode } service foobar { set>> DoItNow( 1 : list>> rd, 2: i32 mitDefault = 42) throws (1: CrashBoomBang cbb) } service deprecate_everything { void Foo( ) ( deprecated = "This method has neither 'x' nor \"y\"" ) void Bar( ) ( deprecated = "Fails to deliver 中文 колбаса" ) void Baz( ) ( deprecated = "Need this to work with tabs (\t) or Umlauts (äöüÄÖÜß) too" ) void Deprecated() ( deprecated ) // no comment } thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/000077500000000000000000000000001420101504100205745ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Collections/000077500000000000000000000000001420101504100230525ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Collections/TCollectionsTests.cs000066400000000000000000000235271420101504100270370ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography.Xml; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; using Thrift.Collections; namespace Thrift.Tests.Collections { // ReSharper disable once InconsistentNaming [TestClass] public class TCollectionsTests { //TODO: Add tests for IEnumerable with objects and primitive values inside [TestMethod] public void TCollection_List_Equals_Primitive_Test() { var collection1 = new List {1,2,3}; var collection2 = new List {1,2,3}; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_List_Equals_Primitive_Different_Test() { var collection1 = new List { 1, 2, 3 }; var collection2 = new List { 1, 2 }; Assert.IsFalse(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); collection2.Add(4); Assert.IsFalse(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_List_Equals_Objects_Test() { var collection1 = new List { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } }; var collection2 = new List { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } }; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_List_List_Equals_Objects_Test() { var collection1 = new List> { new List { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } }; var collection2 = new List> { new List { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } }; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); // SequenceEqual() calls Equals() of the inner list instead of SequenceEqual() } [TestMethod] public void TCollection_List_Equals_OneAndTheSameObject_Test() { var collection1 = new List { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } }; var collection2 = collection1; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_Set_Equals_Primitive_Test() { var collection1 = new THashSet {1,2,3}; var collection2 = new THashSet {1,2,3}; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_Set_Equals_Primitive_Different_Test() { var collection1 = new THashSet { 1, 2, 3 }; var collection2 = new THashSet { 1, 2 }; Assert.IsFalse(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); collection2.Add(4); Assert.IsFalse(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_Set_Equals_Objects_Test() { var collection1 = new THashSet { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } }; var collection2 = new THashSet { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } }; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_Set_Set_Equals_Objects_Test() { var collection1 = new THashSet> { new THashSet { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } }; var collection2 = new THashSet> { new THashSet { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } }; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); // SequenceEqual() calls Equals() of the inner list instead of SequenceEqual() } [TestMethod] public void TCollection_Set_Equals_OneAndTheSameObject_Test() { var collection1 = new THashSet { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } }; var collection2 = collection1; // references to one and the same collection Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_Map_Equals_Primitive_Test() { var collection1 = new Dictionary { [1] = 1, [2] = 2, [3] = 3 }; var collection2 = new Dictionary { [1] = 1, [2] = 2, [3] = 3 }; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_Map_Equals_Primitive_Different_Test() { var collection1 = new Dictionary { [1] = 1, [2] = 2, [3] = 3 }; var collection2 = new Dictionary { [1] = 1, [2] = 2 }; Assert.IsFalse(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); collection2[3] = 3; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); collection2[3] = 4; Assert.IsFalse(TCollections.Equals(collection1, collection2)); } [TestMethod] public void TCollection_Map_Equals_Objects_Test() { var collection1 = new Dictionary { [1] = new ExampleClass { X = 1 }, [-1] = new ExampleClass { X = 2 } }; var collection2 = new Dictionary { [1] = new ExampleClass { X = 1 }, [-1] = new ExampleClass { X = 2 } }; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } [TestMethod] public void TCollection_Map_Map_Equals_Objects_Test() { var collection1 = new Dictionary> { [0] = new Dictionary { [1] = new ExampleClass { X = 1 }, [-1] = new ExampleClass { X = 2 } } }; var collection2 = new Dictionary> { [0] = new Dictionary { [1] = new ExampleClass { X = 1 }, [-1] = new ExampleClass { X = 2 } } }; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsFalse(collection1.SequenceEqual(collection2)); // SequenceEqual() calls Equals() of the inner list instead of SequenceEqual() } [TestMethod] public void TCollection_Map_Equals_OneAndTheSameObject_Test() { var collection1 = new Dictionary { [1] = new ExampleClass { X = 1 }, [-1] = new ExampleClass { X = 2 } }; var collection2 = collection1; Assert.IsTrue(TCollections.Equals(collection1, collection2)); Assert.IsTrue(collection1.SequenceEqual(collection2)); } private class ExampleClass { public int X { get; set; } // all Thrift-generated classes override Equals(), we do just the same public override bool Equals(object? that) { if (that is not ExampleClass other) return false; if (ReferenceEquals(this, other)) return true; return this.X == other.X; } // overriding Equals() requires GetHashCode() as well public override int GetHashCode() { int hashcode = 157; unchecked { hashcode = (hashcode * 397) + X.GetHashCode(); } return hashcode; } } } } thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Collections/THashSetTests.cs000066400000000000000000000040621420101504100261110ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; using Thrift.Collections; namespace Thrift.Tests.Collections { // ReSharper disable once InconsistentNaming [TestClass] public class THashSetTests { [TestMethod] public void THashSet_Equals_Primitive_Test() { const int value = 1; var hashSet = new THashSet {value}; Assert.IsTrue(hashSet.Contains(value)); hashSet.Remove(value); Assert.IsTrue(hashSet.Count == 0); hashSet.Add(value); Assert.IsTrue(hashSet.Contains(value)); hashSet.Clear(); Assert.IsTrue(hashSet.Count == 0); var newArr = new int[1]; hashSet.Add(value); hashSet.CopyTo(newArr, 0); Assert.IsTrue(newArr.Contains(value)); var en = hashSet.GetEnumerator(); en.MoveNext(); Assert.IsTrue((int)en.Current == value); using (var ien = ((IEnumerable)hashSet).GetEnumerator()) { ien.MoveNext(); Assert.IsTrue(ien.Current == value); } } } } thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/DataModel/000077500000000000000000000000001420101504100224265ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs000066400000000000000000000700061420101504100244700ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; using OptReqDefTest; using Thrift.Collections; #nullable disable // this is just test code, we leave it at that namespace Thrift.Tests.DataModel { // ReSharper disable once InconsistentNaming [TestClass] public class DeepCopyTests { [TestMethod] public void Test_Complex_DeepCopy() { var first = InitializeInstance(new RaceDetails()); VerifyIdenticalContent(first, InitializeInstance(new RaceDetails())); var second = first.DeepCopy(); VerifyIdenticalContent(first, second); ModifyInstance(second,0); VerifyDifferentContent(first, second); VerifyIdenticalContent(first, InitializeInstance(new RaceDetails())); var third = second.DeepCopy(); VerifyIdenticalContent(second, third); ModifyInstance(third,0); VerifyDifferentContent(second, third); VerifyIdenticalContent(first, InitializeInstance(new RaceDetails())); } private RaceDetails MakeNestedRaceDetails(int nesting) { if (++nesting > 1) return null; var instance = new RaceDetails(); InitializeInstance(instance,nesting); return instance; } private jack MakeNestedUnion(int nesting) { if (++nesting > 1) return null; var details = new RaceDetails(); InitializeInstance(details,nesting); return new jack.nested_struct(details); } private RaceDetails InitializeInstance(RaceDetails instance, int nesting = 0) { // at init, we intentionally leave all non-required fields unset Assert.IsFalse(instance.__isset.opt_one); Assert.IsFalse(instance.__isset.opt_two); Assert.IsFalse(instance.__isset.opt_three); Assert.IsFalse(instance.__isset.opt_four); Assert.IsFalse(instance.__isset.opt_five); Assert.IsFalse(instance.__isset.opt_six); Assert.IsFalse(instance.__isset.opt_seven); Assert.IsFalse(instance.__isset.opt_eight); // set all required to null/default instance.Req_one = default; instance.Req_two = default; instance.Req_three = default; instance.Req_four = default; instance.Req_five = default; instance.Req_six = default; instance.Req_seven = default;; instance.Req_eight = default; // leave non-required fields unset again Assert.IsFalse(instance.__isset.def_one); Assert.IsFalse(instance.__isset.def_two); Assert.IsFalse(instance.__isset.def_three); Assert.IsFalse(instance.__isset.def_four); Assert.IsFalse(instance.__isset.def_five); Assert.IsFalse(instance.__isset.def_six); Assert.IsFalse(instance.__isset.def_seven); Assert.IsFalse(instance.__isset.def_eight); // these should have IDL defaults set Assert.IsTrue(instance.__isset.opt_one_with_value); Assert.IsTrue(instance.__isset.opt_two_with_value); Assert.IsTrue(instance.__isset.opt_three_with_value); Assert.IsTrue(instance.__isset.opt_four_with_value); Assert.IsTrue(instance.__isset.opt_five_with_value); Assert.IsTrue(instance.__isset.opt_six_with_value); Assert.IsTrue(instance.__isset.opt_seven_with_value); Assert.IsTrue(instance.__isset.opt_eight_with_value); Assert.AreEqual(instance.Req_one_with_value, (Distance)1); Assert.AreEqual(instance.Req_two_with_value, 2.22); Assert.AreEqual(instance.Req_three_with_value, 3); Assert.AreEqual(instance.Req_four_with_value, "four"); Assert.AreEqual("five", Encoding.UTF8.GetString(instance.Req_five_with_value)); Assert.IsTrue(instance.Req_six_with_value.Count == 1); Assert.AreEqual(instance.Req_six_with_value[0], 6 ); Assert.IsTrue(instance.Req_seven_with_value.Count == 1); Assert.IsTrue(instance.Req_seven_with_value.Contains(7)); Assert.IsTrue(instance.Req_eight_with_value.Count == 1); Assert.IsTrue(instance.Req_eight_with_value[8] == 8); Assert.IsTrue(instance.__isset.def_one_with_value); Assert.IsTrue(instance.__isset.def_two_with_value); Assert.IsTrue(instance.__isset.def_three_with_value); Assert.IsTrue(instance.__isset.def_four_with_value); Assert.IsTrue(instance.__isset.def_five_with_value); Assert.IsTrue(instance.__isset.def_six_with_value); Assert.IsTrue(instance.__isset.def_seven_with_value); Assert.IsTrue(instance.__isset.def_eight_with_value); instance.Last_of_the_mohicans = true; if (nesting < 2) { instance.Far_list = new List() { Distance.foo, Distance.bar, Distance.baz }; instance.Far_set = new THashSet() { Distance.foo, Distance.bar, Distance.baz }; instance.Far_map = new Dictionary() { [Distance.foo] = Distance.foo, [Distance.bar] = Distance.bar, [Distance.baz] = Distance.baz }; instance.Far_set_list = new THashSet>() { new List() { Distance.foo } }; instance.Far_list_map_set = new List>>() { new Dictionary>() { [1] = new THashSet() { Distance.baz } } }; instance.Far_map_dist_to_rds = new Dictionary>() { [Distance.bar] = new List() { MakeNestedRaceDetails(nesting) } }; instance.Req_nested = MakeNestedRaceDetails(nesting); Assert.IsFalse(instance.__isset.opt_nested); Assert.IsFalse(instance.__isset.def_nested); instance.Req_union = MakeNestedUnion(nesting); Assert.IsFalse(instance.__isset.opt_union); Assert.IsFalse(instance.__isset.def_union); } instance.Triplesix = (Distance)666; return instance; } private void ModifyInstance(RaceDetails instance, int level) { if ((instance == null) || (++level > 4)) return; instance.Opt_one = ModifyValue(instance.Opt_one); instance.Opt_two = ModifyValue(instance.Opt_two); instance.Opt_three = ModifyValue(instance.Opt_three); instance.Opt_four = ModifyValue(instance.Opt_four); instance.Opt_five = ModifyValue(instance.Opt_five); instance.Opt_six = ModifyValue(instance.Opt_six); instance.Opt_seven = ModifyValue(instance.Opt_seven); instance.Opt_eight = ModifyValue(instance.Opt_eight); instance.Req_one = ModifyValue(instance.Req_one); instance.Req_two = ModifyValue(instance.Req_two); instance.Req_three = ModifyValue(instance.Req_three); instance.Req_four = ModifyValue(instance.Req_four); instance.Req_five = ModifyValue(instance.Req_five); instance.Req_six = ModifyValue(instance.Req_six); instance.Req_seven = ModifyValue(instance.Req_seven); instance.Req_eight = ModifyValue(instance.Req_eight); instance.Def_one = ModifyValue(instance.Def_one); instance.Def_two = ModifyValue(instance.Def_two); instance.Def_three = ModifyValue(instance.Def_three); instance.Def_four = ModifyValue(instance.Def_four); instance.Def_five = ModifyValue(instance.Def_five); instance.Def_six = ModifyValue(instance.Def_six); instance.Def_seven = ModifyValue(instance.Def_seven); instance.Def_eight = ModifyValue(instance.Def_eight); instance.Opt_one_with_value = ModifyValue(instance.Opt_one_with_value); instance.Opt_two_with_value = ModifyValue(instance.Opt_two_with_value); instance.Opt_three_with_value = ModifyValue(instance.Opt_three_with_value); instance.Opt_four_with_value = ModifyValue(instance.Opt_four_with_value); instance.Opt_five_with_value = ModifyValue(instance.Opt_five_with_value); instance.Opt_six_with_value = ModifyValue(instance.Opt_six_with_value); instance.Opt_seven_with_value = ModifyValue(instance.Opt_seven_with_value); instance.Opt_eight_with_value = ModifyValue(instance.Opt_eight_with_value); instance.Req_one_with_value = ModifyValue(instance.Req_one_with_value); instance.Req_two_with_value = ModifyValue(instance.Req_two_with_value); instance.Req_three_with_value = ModifyValue(instance.Req_three_with_value); instance.Req_four_with_value = ModifyValue(instance.Req_four_with_value); instance.Req_five_with_value = ModifyValue(instance.Req_five_with_value); instance.Req_six_with_value = ModifyValue(instance.Req_six_with_value); instance.Req_seven_with_value = ModifyValue(instance.Req_seven_with_value); instance.Req_eight_with_value = ModifyValue(instance.Req_eight_with_value); instance.Def_one_with_value = ModifyValue(instance.Def_one_with_value); instance.Def_two_with_value = ModifyValue(instance.Def_two_with_value); instance.Def_three_with_value = ModifyValue(instance.Def_three_with_value); instance.Def_four_with_value = ModifyValue(instance.Def_four_with_value); instance.Def_five_with_value = ModifyValue(instance.Def_five_with_value); instance.Def_six_with_value = ModifyValue(instance.Def_six_with_value); instance.Def_seven_with_value = ModifyValue(instance.Def_seven_with_value); instance.Def_eight_with_value = ModifyValue(instance.Def_eight_with_value); instance.Last_of_the_mohicans = ModifyValue(instance.Last_of_the_mohicans); instance.Far_list = ModifyValue(instance.Far_list); instance.Far_set = ModifyValue(instance.Far_set); instance.Far_map = ModifyValue(instance.Far_map); instance.Far_set_list = ModifyValue(instance.Far_set_list); instance.Far_list_map_set = ModifyValue(instance.Far_list_map_set); instance.Far_map_dist_to_rds = ModifyValue(instance.Far_map_dist_to_rds, level); instance.Req_nested = ModifyValue(instance.Req_nested, level); instance.Opt_nested = ModifyValue(instance.Opt_nested, level); instance.Def_nested = ModifyValue(instance.Def_nested, level); instance.Req_union = ModifyValue(instance.Req_union, level); instance.Opt_union = ModifyValue(instance.Opt_union, level); instance.Def_union = ModifyValue(instance.Def_union, level); instance.Triplesix = ModifyValue(instance.Triplesix); } private jack ModifyValue(jack value, int level) { if (++level > 4) return value; if (value == null) value = MakeNestedUnion(0); Debug.Assert(value.As_nested_struct != null); ModifyInstance(value.As_nested_struct, level); return value; } private RaceDetails ModifyValue(RaceDetails value, int level) { if (++level > 4) return value; if (value == null) value = new RaceDetails(); ModifyInstance(value,level); return value; } private Dictionary> ModifyValue(Dictionary> value, int level) { if (value == null) value = new Dictionary>(); if (++level > 4) return value; var details = new RaceDetails(); InitializeInstance(details); value[Distance.foo] = new List() { details }; if (value.TryGetValue(Distance.bar, out var list) && (list.Count > 0)) { ModifyInstance(list[0], level); list.Add(null); } value[Distance.baz] = null; return value; } private static List>> ModifyValue(List>> value) { if (value == null) value = new List>>(); if (value.Count == 0) value.Add(new Dictionary>()); else value.Add(null); sbyte key = (sbyte)(value[0].Count + 10); if (value[0].Count == 0) value[0].Add(key, new THashSet()); else value[0].Add(key, null); foreach (var entry in value) { if (entry != null) { foreach (var pair in entry) { if (pair.Value != null) { if (pair.Value.Contains(Distance.baz)) pair.Value.Remove(Distance.baz); else pair.Value.Add(Distance.baz); } } } } return value; } private static THashSet> ModifyValue(THashSet> value) { if (value == null) value = new THashSet>(); if (value.Count == 0) value.Add(new List()); else value.Add(null); foreach (var entry in value) if( entry != null) entry.Add(Distance.baz); return value; } private static Dictionary ModifyValue(Dictionary value) { if (value == null) value = new Dictionary(); value[Distance.foo] = value.ContainsKey(Distance.foo) ? ++value[Distance.foo] : Distance.foo; value[Distance.bar] = value.ContainsKey(Distance.bar) ? ++value[Distance.bar] : Distance.bar; value[Distance.baz] = value.ContainsKey(Distance.baz) ? ++value[Distance.baz] : Distance.baz; return value; } private static THashSet ModifyValue(THashSet value) { if (value == null) value = new THashSet(); if (value.Contains(Distance.foo)) value.Remove(Distance.foo); else value.Add(Distance.foo); if (value.Contains(Distance.bar)) value.Remove(Distance.bar); else value.Add(Distance.bar); if (value.Contains(Distance.baz)) value.Remove(Distance.baz); else value.Add(Distance.baz); return value; } private static List ModifyValue(List value) { if (value == null) value = new List(); value.Add(Distance.foo); value.Add(Distance.bar); value.Add(Distance.baz); return value; } private static bool ModifyValue(bool value) { return !value; } private static Dictionary ModifyValue(Dictionary value) { if (value == null) value = new Dictionary(); value.Add((sbyte)(value.Count + 10), (short)value.Count); return value; } private static THashSet ModifyValue(THashSet value) { if (value == null) value = new THashSet(); value.Add(value.Count+100); return value; } private static List ModifyValue(List value) { if (value == null) value = new List(); value.Add(value.Count); return value; } private static byte[] ModifyValue(byte[] value) { if (value == null) value = new byte[1] { 0 }; if (value.Length > 0) value[0] = (value[0] < 0xFF) ? ++value[0] : (byte)0; return value; } private static string ModifyValue(string value) { return value + "1"; } private static double ModifyValue(double value) { return value + 1.1; } private static short ModifyValue(short value) { return ++value; } private static Distance ModifyValue(Distance value) { return ++value; } private static void VerifyDifferentContent(RaceDetails first, RaceDetails second) { Assert.AreNotEqual(first, second); Assert.AreNotEqual(first.Opt_two, second.Opt_two); Assert.AreNotEqual(first.Opt_three, second.Opt_three); Assert.AreNotEqual(first.Opt_four, second.Opt_four); Assert.IsFalse(TCollections.Equals(first.Opt_five, second.Opt_five)); Assert.IsFalse(TCollections.Equals(first.Opt_six, second.Opt_six)); Assert.IsFalse(TCollections.Equals(first.Opt_seven, second.Opt_seven)); Assert.IsFalse(TCollections.Equals(first.Opt_eight, second.Opt_eight)); Assert.AreNotEqual(first.Req_one, second.Req_one); Assert.AreNotEqual(first.Req_two, second.Req_two); Assert.AreNotEqual(first.Req_three, second.Req_three); Assert.AreNotEqual(first.Req_four, second.Req_four); Assert.IsFalse(TCollections.Equals(first.Req_five, second.Req_five)); Assert.IsFalse(TCollections.Equals(first.Req_six, second.Req_six)); Assert.IsFalse(TCollections.Equals(first.Req_seven, second.Req_seven)); Assert.IsFalse(TCollections.Equals(first.Req_eight, second.Req_eight)); Assert.AreNotEqual(first.Def_one, second.Def_one); Assert.AreNotEqual(first.Def_two, second.Def_two); Assert.AreNotEqual(first.Def_three, second.Def_three); Assert.AreNotEqual(first.Def_four, second.Def_four); Assert.IsFalse(TCollections.Equals(first.Def_five, second.Def_five)); Assert.IsFalse(TCollections.Equals(first.Def_six, second.Def_six)); Assert.IsFalse(TCollections.Equals(first.Def_seven, second.Def_seven)); Assert.IsFalse(TCollections.Equals(first.Def_eight, second.Def_eight)); Assert.AreNotEqual(first.Opt_one_with_value, second.Opt_one_with_value); Assert.AreNotEqual(first.Opt_two_with_value, second.Opt_two_with_value); Assert.AreNotEqual(first.Opt_three_with_value, second.Opt_three_with_value); Assert.AreNotEqual(first.Opt_four_with_value, second.Opt_four_with_value); Assert.IsFalse(TCollections.Equals(first.Opt_five_with_value, second.Opt_five_with_value)); Assert.IsFalse(TCollections.Equals(first.Opt_six_with_value, second.Opt_six_with_value)); Assert.IsFalse(TCollections.Equals(first.Opt_seven_with_value, second.Opt_seven_with_value)); Assert.IsFalse(TCollections.Equals(first.Opt_eight_with_value, second.Opt_eight_with_value)); Assert.AreNotEqual(first.Req_one_with_value, second.Req_one_with_value); Assert.AreNotEqual(first.Req_two_with_value, second.Req_two_with_value); Assert.AreNotEqual(first.Req_three_with_value, second.Req_three_with_value); Assert.AreNotEqual(first.Req_four_with_value, second.Req_four_with_value); Assert.IsFalse(TCollections.Equals(first.Req_five_with_value, second.Req_five_with_value)); Assert.IsFalse(TCollections.Equals(first.Req_six_with_value, second.Req_six_with_value)); Assert.IsFalse(TCollections.Equals(first.Req_seven_with_value, second.Req_seven_with_value)); Assert.IsFalse(TCollections.Equals(first.Req_eight_with_value, second.Req_eight_with_value)); Assert.AreNotEqual(first.Def_one_with_value, second.Def_one_with_value); Assert.AreNotEqual(first.Def_two_with_value, second.Def_two_with_value); Assert.AreNotEqual(first.Def_three_with_value, second.Def_three_with_value); Assert.AreNotEqual(first.Def_four_with_value, second.Def_four_with_value); Assert.IsFalse(TCollections.Equals(first.Def_five_with_value, second.Def_five_with_value)); Assert.IsFalse(TCollections.Equals(first.Def_six_with_value, second.Def_six_with_value)); Assert.IsFalse(TCollections.Equals(first.Def_seven_with_value, second.Def_seven_with_value)); Assert.IsFalse(TCollections.Equals(first.Def_eight_with_value, second.Def_eight_with_value)); Assert.AreNotEqual(first.Last_of_the_mohicans, second.Last_of_the_mohicans); Assert.IsFalse(TCollections.Equals(first.Far_list, second.Far_list)); Assert.IsFalse(TCollections.Equals(first.Far_set, second.Far_set)); Assert.IsFalse(TCollections.Equals(first.Far_map, second.Far_map)); Assert.IsFalse(TCollections.Equals(first.Far_set_list, second.Far_set_list)); Assert.IsFalse(TCollections.Equals(first.Far_list_map_set, second.Far_list_map_set)); Assert.IsFalse(TCollections.Equals(first.Far_map_dist_to_rds, second.Far_map_dist_to_rds)); Assert.AreNotEqual(first.Req_nested, second.Req_nested); Assert.AreNotEqual(first.Opt_nested, second.Opt_nested); Assert.AreNotEqual(first.Def_nested, second.Def_nested); Assert.AreNotEqual(first.Req_union, second.Req_union); Assert.AreNotEqual(first.Opt_union, second.Opt_union); Assert.AreNotEqual(first.Def_union, second.Def_union); Assert.AreNotEqual(first.Triplesix, second.Triplesix); } private static void VerifyIdenticalContent(RaceDetails first, RaceDetails second) { Assert.AreEqual(first, second); Assert.AreEqual(first.Opt_two, second.Opt_two); Assert.AreEqual(first.Opt_three, second.Opt_three); Assert.AreEqual(first.Opt_four, second.Opt_four); Assert.IsTrue(TCollections.Equals(first.Opt_five, second.Opt_five)); Assert.IsTrue(TCollections.Equals(first.Opt_six, second.Opt_six)); Assert.IsTrue(TCollections.Equals(first.Opt_seven, second.Opt_seven)); Assert.IsTrue(TCollections.Equals(first.Opt_eight, second.Opt_eight)); Assert.AreEqual(first.Req_one, second.Req_one); Assert.AreEqual(first.Req_two, second.Req_two); Assert.AreEqual(first.Req_three, second.Req_three); Assert.AreEqual(first.Req_four, second.Req_four); Assert.IsTrue(TCollections.Equals(first.Req_five, second.Req_five)); Assert.IsTrue(TCollections.Equals(first.Req_six, second.Req_six)); Assert.IsTrue(TCollections.Equals(first.Req_seven, second.Req_seven)); Assert.IsTrue(TCollections.Equals(first.Req_eight, second.Req_eight)); Assert.AreEqual(first.Def_one, second.Def_one); Assert.AreEqual(first.Def_two, second.Def_two); Assert.AreEqual(first.Def_three, second.Def_three); Assert.AreEqual(first.Def_four, second.Def_four); Assert.IsTrue(TCollections.Equals(first.Def_five, second.Def_five)); Assert.IsTrue(TCollections.Equals(first.Def_six, second.Def_six)); Assert.IsTrue(TCollections.Equals(first.Def_seven, second.Def_seven)); Assert.IsTrue(TCollections.Equals(first.Def_eight, second.Def_eight)); Assert.AreEqual(first.Opt_one_with_value, second.Opt_one_with_value); Assert.AreEqual(first.Opt_two_with_value, second.Opt_two_with_value); Assert.AreEqual(first.Opt_three_with_value, second.Opt_three_with_value); Assert.AreEqual(first.Opt_four_with_value, second.Opt_four_with_value); Assert.IsTrue(TCollections.Equals(first.Opt_five_with_value, second.Opt_five_with_value)); Assert.IsTrue(TCollections.Equals(first.Opt_six_with_value, second.Opt_six_with_value)); Assert.IsTrue(TCollections.Equals(first.Opt_seven_with_value, second.Opt_seven_with_value)); Assert.IsTrue(TCollections.Equals(first.Opt_eight_with_value, second.Opt_eight_with_value)); Assert.AreEqual(first.Req_one_with_value, second.Req_one_with_value); Assert.AreEqual(first.Req_two_with_value, second.Req_two_with_value); Assert.AreEqual(first.Req_three_with_value, second.Req_three_with_value); Assert.AreEqual(first.Req_four_with_value, second.Req_four_with_value); Assert.IsTrue(TCollections.Equals(first.Req_five_with_value, second.Req_five_with_value)); Assert.IsTrue(TCollections.Equals(first.Req_six_with_value, second.Req_six_with_value)); Assert.IsTrue(TCollections.Equals(first.Req_seven_with_value, second.Req_seven_with_value)); Assert.IsTrue(TCollections.Equals(first.Req_eight_with_value, second.Req_eight_with_value)); Assert.AreEqual(first.Def_one_with_value, second.Def_one_with_value); Assert.AreEqual(first.Def_two_with_value, second.Def_two_with_value); Assert.AreEqual(first.Def_three_with_value, second.Def_three_with_value); Assert.AreEqual(first.Def_four_with_value, second.Def_four_with_value); Assert.IsTrue(TCollections.Equals(first.Def_five_with_value, second.Def_five_with_value)); Assert.IsTrue(TCollections.Equals(first.Def_six_with_value, second.Def_six_with_value)); Assert.IsTrue(TCollections.Equals(first.Def_seven_with_value, second.Def_seven_with_value)); Assert.IsTrue(TCollections.Equals(first.Def_eight_with_value, second.Def_eight_with_value)); Assert.AreEqual(first.Last_of_the_mohicans, second.Last_of_the_mohicans); Assert.IsTrue(TCollections.Equals(first.Far_list, second.Far_list)); Assert.IsTrue(TCollections.Equals(first.Far_set, second.Far_set)); Assert.IsTrue(TCollections.Equals(first.Far_map, second.Far_map)); Assert.IsTrue(TCollections.Equals(first.Far_set_list, second.Far_set_list)); Assert.IsTrue(TCollections.Equals(first.Far_list_map_set, second.Far_list_map_set)); Assert.IsTrue(TCollections.Equals(first.Far_map_dist_to_rds, second.Far_map_dist_to_rds)); Assert.AreEqual(first.Req_nested, second.Req_nested); Assert.AreEqual(first.Opt_nested, second.Opt_nested); Assert.AreEqual(first.Def_nested, second.Def_nested); Assert.AreEqual(first.Req_union, second.Req_union); Assert.AreEqual(first.Opt_union, second.Opt_union); Assert.AreEqual(first.Def_union, second.Def_union); Assert.AreEqual(first.Triplesix, second.Triplesix); } } } thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs000066400000000000000000000064171420101504100255330ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; using OptReqDefTest; using Thrift.Collections; namespace Thrift.Tests.DataModel { // ReSharper disable once InconsistentNaming [TestClass] public class Thrift_5238 { private void CheckInstance(RaceDetails instance) { // object Assert.IsTrue(instance.__isset.def_nested); Assert.IsTrue(instance.__isset.opt_nested); Assert.IsNull(instance.Def_nested); Assert.IsNull(instance.Opt_nested); // string Assert.IsTrue(instance.__isset.def_four); Assert.IsTrue(instance.__isset.opt_four); Assert.IsNull(instance.Req_four); Assert.IsNull(instance.Def_four); Assert.IsNull(instance.Opt_four); // byte[] Assert.IsTrue(instance.__isset.def_five); Assert.IsTrue(instance.__isset.opt_five); Assert.IsNull(instance.Req_five); Assert.IsNull(instance.Def_five); Assert.IsNull(instance.Opt_five); // list<> Assert.IsTrue(instance.__isset.def_six); Assert.IsTrue(instance.__isset.opt_six); Assert.IsNull(instance.Req_six); Assert.IsNull(instance.Opt_six); Assert.IsNull(instance.Def_six); } [TestMethod] public void Thrift_5238_ProperNullChecks() { var instance = new OptReqDefTest.RaceDetails(); // object instance.Def_nested = null; instance.Opt_nested = null; // string instance.Req_four = null; instance.Def_four = null; instance.Opt_four = null; // byte[] instance.Req_five = null; instance.Def_five = null; instance.Opt_five = null; // list<> instance.Req_six = null; instance.Opt_six = null; instance.Def_six = null; // test the setup CheckInstance(instance); // validate proper null checks , any of these throws if not instance.ToString(); instance.GetHashCode(); // validate proper null checks , any of these throws if not var copy = instance.DeepCopy(); CheckInstance(copy); } } } thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Protocols/000077500000000000000000000000001420101504100225605ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Protocols/TJsonProtocolHelperTests.cs000066400000000000000000000164251420101504100300610ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using Thrift.Protocol; using Thrift.Protocol.Entities; using Thrift.Protocol.Utilities; namespace Thrift.Tests.Protocols { [TestClass] public class TJSONProtocolHelperTests { [TestMethod] public void GetTypeNameForTypeId_Test() { // input/output var sets = new List> { new Tuple(TType.Bool, TJSONProtocolConstants.TypeNames.NameBool), new Tuple(TType.Byte, TJSONProtocolConstants.TypeNames.NameByte), new Tuple(TType.I16, TJSONProtocolConstants.TypeNames.NameI16), new Tuple(TType.I32, TJSONProtocolConstants.TypeNames.NameI32), new Tuple(TType.I64, TJSONProtocolConstants.TypeNames.NameI64), new Tuple(TType.Double, TJSONProtocolConstants.TypeNames.NameDouble), new Tuple(TType.String, TJSONProtocolConstants.TypeNames.NameString), new Tuple(TType.Struct, TJSONProtocolConstants.TypeNames.NameStruct), new Tuple(TType.Map, TJSONProtocolConstants.TypeNames.NameMap), new Tuple(TType.Set, TJSONProtocolConstants.TypeNames.NameSet), new Tuple(TType.List, TJSONProtocolConstants.TypeNames.NameList), }; foreach (var t in sets) { Assert.IsTrue(TJSONProtocolHelper.GetTypeNameForTypeId(t.Item1) == t.Item2, $"Wrong mapping of TypeName {t.Item2} to TType: {t.Item1}"); } } [TestMethod] [ExpectedException(typeof(TProtocolException))] public void GetTypeNameForTypeId_TStop_Test() { TJSONProtocolHelper.GetTypeNameForTypeId(TType.Stop); } [TestMethod] [ExpectedException(typeof(TProtocolException))] public void GetTypeNameForTypeId_NonExistingTType_Test() { TJSONProtocolHelper.GetTypeNameForTypeId((TType)100); } [TestMethod] public void GetTypeIdForTypeName_Test() { // input/output var sets = new List> { new Tuple(TType.Bool, TJSONProtocolConstants.TypeNames.NameBool), new Tuple(TType.Byte, TJSONProtocolConstants.TypeNames.NameByte), new Tuple(TType.I16, TJSONProtocolConstants.TypeNames.NameI16), new Tuple(TType.I32, TJSONProtocolConstants.TypeNames.NameI32), new Tuple(TType.I64, TJSONProtocolConstants.TypeNames.NameI64), new Tuple(TType.Double, TJSONProtocolConstants.TypeNames.NameDouble), new Tuple(TType.String, TJSONProtocolConstants.TypeNames.NameString), new Tuple(TType.Struct, TJSONProtocolConstants.TypeNames.NameStruct), new Tuple(TType.Map, TJSONProtocolConstants.TypeNames.NameMap), new Tuple(TType.Set, TJSONProtocolConstants.TypeNames.NameSet), new Tuple(TType.List, TJSONProtocolConstants.TypeNames.NameList), }; foreach (var t in sets) { Assert.IsTrue(TJSONProtocolHelper.GetTypeIdForTypeName(t.Item2) == t.Item1, $"Wrong mapping of TypeName {t.Item2} to TType: {t.Item1}"); } } [TestMethod] [ExpectedException(typeof(TProtocolException))] public void GetTypeIdForTypeName_TStopTypeName_Test() { TJSONProtocolHelper.GetTypeIdForTypeName(new []{(byte)TType.Stop, (byte)TType.Stop}); } [TestMethod] [ExpectedException(typeof(TProtocolException))] public void GetTypeIdForTypeName_NonExistingTypeName_Test() { TJSONProtocolHelper.GetTypeIdForTypeName(new byte[]{100}); } [TestMethod] [ExpectedException(typeof(TProtocolException))] public void GetTypeIdForTypeName_EmptyName_Test() { TJSONProtocolHelper.GetTypeIdForTypeName(new byte[] {}); } [TestMethod] public void IsJsonNumeric_Test() { // input/output var correctJsonNumeric = "+-.0123456789Ee"; var incorrectJsonNumeric = "AaBcDd/*\\"; var sets = correctJsonNumeric.Select(ch => new Tuple((byte) ch, true)).ToList(); sets.AddRange(incorrectJsonNumeric.Select(ch => new Tuple((byte) ch, false))); foreach (var t in sets) { Assert.IsTrue(TJSONProtocolHelper.IsJsonNumeric(t.Item1) == t.Item2, $"Wrong mapping of Char {t.Item1} to bool: {t.Item2}"); } } [TestMethod] public void ToHexVal_Test() { // input/output var chars = "0123456789abcdef"; var expectedHexValues = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; var sets = chars.Select((ch, i) => new Tuple(ch, expectedHexValues[i])).ToList(); foreach (var t in sets) { var actualResult = TJSONProtocolHelper.ToHexVal((byte)t.Item1); Assert.IsTrue(actualResult == t.Item2, $"Wrong mapping of char byte {t.Item1} to it expected hex value: {t.Item2}. Actual hex value: {actualResult}"); } } [TestMethod] [ExpectedException(typeof(TProtocolException))] public void ToHexVal_WrongInputChar_Test() { TJSONProtocolHelper.ToHexVal((byte)'s'); } [TestMethod] public void ToHexChar_Test() { // input/output var hexValues = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; var expectedChars = "0123456789abcdef"; var sets = hexValues.Select((hv, i) => new Tuple(hv, expectedChars[i])).ToList(); foreach (var t in sets) { var actualResult = TJSONProtocolHelper.ToHexChar(t.Item1); Assert.IsTrue(actualResult == t.Item2, $"Wrong mapping of hex value {t.Item1} to it expected char: {t.Item2}. Actual hex value: {actualResult}"); } } } }thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Protocols/TJsonProtocolTests.cs000066400000000000000000000050571420101504100267200ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Thrift.Protocol; using Thrift.Protocol.Entities; using Thrift.Transport; using Thrift.Transport.Client; namespace Thrift.Tests.Protocols { // ReSharper disable once InconsistentNaming [TestClass] public class TJSONProtocolTests { [TestMethod] public void TJSONProtocol_Can_Create_Instance_Test() { var httpClientTransport = new THttpTransport( new Uri("http://localhost"), null, null, null); var result = new TJSONProtocolWrapper(httpClientTransport); Assert.IsNotNull(result); Assert.IsNotNull(result.WrappedContext); Assert.IsNotNull(result.WrappedReader); Assert.IsNotNull(result.Transport); Assert.IsTrue(result.WrappedRecursionDepth == 0); Assert.IsTrue(result.WrappedRecursionLimit == TConfiguration.DEFAULT_RECURSION_DEPTH); Assert.IsTrue(result.Transport.Equals(httpClientTransport)); Assert.IsTrue(result.WrappedContext.GetType().Name.Equals("JSONBaseContext", StringComparison.OrdinalIgnoreCase)); Assert.IsTrue(result.WrappedReader.GetType().Name.Equals("LookaheadReader", StringComparison.OrdinalIgnoreCase)); } private class TJSONProtocolWrapper : TJsonProtocol { public TJSONProtocolWrapper(TTransport trans) : base(trans) { } public object WrappedContext => Context; public object WrappedReader => Reader; public int WrappedRecursionDepth => RecursionDepth; public int WrappedRecursionLimit => RecursionLimit; } } } thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj000066400000000000000000000034431420101504100243630ustar00rootroot00000000000000 net6.0 0.16.0.0 enable thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Transports/000077500000000000000000000000001420101504100227535ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Tests/Thrift.Tests/Transports/THttpTransportTests.cs000066400000000000000000000026501420101504100273100ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Net.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; using Thrift.Transport.Client; namespace Thrift.Tests.Transports { [TestClass] public class THttpTransportTests { [TestMethod] public void THttpTransport_Uses_Configured_ConnectionTimeout_Test() { var client = new HttpClient(); var httpClientTransport = new THttpTransport(client, null) { ConnectTimeout = 5000 }; Assert.IsTrue(client.Timeout.TotalMilliseconds == 5000); Assert.IsTrue(httpClientTransport.ConnectTimeout == 5000); } } } thrift-0.16.0/lib/netstd/Thrift.sln000066400000000000000000000156141420101504100171160ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29905.134 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{ED5A45B0-07D1-4507-96B7-83FBD3D031CA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "Thrift\Thrift.csproj", "{5B501D21-D428-408D-AB5C-32D6F5355294}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.IntegrationTests", "Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj", "{837F4084-AAD7-45F5-BC96-10E05A669DB4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.Tests", "Tests\Thrift.Tests\Thrift.Tests.csproj", "{0790D388-1A3C-4423-8CF2-C97074A8B68B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.PublicInterfaces.Compile.Tests", "Tests\Thrift.PublicInterfaces.Compile.Tests\Thrift.PublicInterfaces.Compile.Tests.csproj", "{A6AE021D-61CB-4D84-A103-0B663C62AE2C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{BF7B896B-8BB6-447C-84F8-26871882A14A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift.Benchmarks", "Benchmarks\Thrift.Benchmarks\Thrift.Benchmarks.csproj", "{D0559DFF-6632-446C-9EFC-C750DA20B1D9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5B501D21-D428-408D-AB5C-32D6F5355294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Debug|Any CPU.Build.0 = Debug|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Debug|x64.ActiveCfg = Debug|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Debug|x64.Build.0 = Debug|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Debug|x86.ActiveCfg = Debug|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Debug|x86.Build.0 = Debug|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Release|Any CPU.ActiveCfg = Release|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Release|Any CPU.Build.0 = Release|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Release|x64.ActiveCfg = Release|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Release|x64.Build.0 = Release|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Release|x86.ActiveCfg = Release|Any CPU {5B501D21-D428-408D-AB5C-32D6F5355294}.Release|x86.Build.0 = Release|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Debug|x64.ActiveCfg = Debug|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Debug|x64.Build.0 = Debug|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Debug|x86.ActiveCfg = Debug|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Debug|x86.Build.0 = Debug|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Release|Any CPU.Build.0 = Release|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Release|x64.ActiveCfg = Release|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Release|x64.Build.0 = Release|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Release|x86.ActiveCfg = Release|Any CPU {837F4084-AAD7-45F5-BC96-10E05A669DB4}.Release|x86.Build.0 = Release|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Debug|Any CPU.Build.0 = Debug|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Debug|x64.ActiveCfg = Debug|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Debug|x64.Build.0 = Debug|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Debug|x86.ActiveCfg = Debug|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Debug|x86.Build.0 = Debug|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Release|Any CPU.ActiveCfg = Release|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Release|Any CPU.Build.0 = Release|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Release|x64.ActiveCfg = Release|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Release|x64.Build.0 = Release|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Release|x86.ActiveCfg = Release|Any CPU {0790D388-1A3C-4423-8CF2-C97074A8B68B}.Release|x86.Build.0 = Release|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Debug|Any CPU.Build.0 = Debug|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Debug|x64.ActiveCfg = Debug|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Debug|x64.Build.0 = Debug|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Debug|x86.ActiveCfg = Debug|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Debug|x86.Build.0 = Debug|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Release|Any CPU.ActiveCfg = Release|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Release|Any CPU.Build.0 = Release|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Release|x64.ActiveCfg = Release|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Release|x64.Build.0 = Release|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Release|x86.ActiveCfg = Release|Any CPU {A6AE021D-61CB-4D84-A103-0B663C62AE2C}.Release|x86.Build.0 = Release|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Debug|x64.ActiveCfg = Debug|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Debug|x64.Build.0 = Debug|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Debug|x86.ActiveCfg = Debug|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Debug|x86.Build.0 = Debug|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Release|Any CPU.Build.0 = Release|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Release|x64.ActiveCfg = Release|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Release|x64.Build.0 = Release|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Release|x86.ActiveCfg = Release|Any CPU {D0559DFF-6632-446C-9EFC-C750DA20B1D9}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {837F4084-AAD7-45F5-BC96-10E05A669DB4} = {ED5A45B0-07D1-4507-96B7-83FBD3D031CA} {0790D388-1A3C-4423-8CF2-C97074A8B68B} = {ED5A45B0-07D1-4507-96B7-83FBD3D031CA} {A6AE021D-61CB-4D84-A103-0B663C62AE2C} = {ED5A45B0-07D1-4507-96B7-83FBD3D031CA} {D0559DFF-6632-446C-9EFC-C750DA20B1D9} = {BF7B896B-8BB6-447C-84F8-26871882A14A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FD20BC4A-0109-41D8-8C0C-893E784D7EF9} EndGlobalSection EndGlobal thrift-0.16.0/lib/netstd/Thrift/000077500000000000000000000000001420101504100163715ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/.editorconfig000066400000000000000000000001441420101504100210450ustar00rootroot00000000000000[*.cs] # CS1591: missing XML comment for public element dotnet_diagnostic.CS1591.severity = silent thrift-0.16.0/lib/netstd/Thrift/Collections/000077500000000000000000000000001420101504100206475ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Collections/TCollections.cs000066400000000000000000000071761420101504100236130ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Collections; using System.Collections.Generic; namespace Thrift.Collections { // ReSharper disable once InconsistentNaming public static class TCollections { /// /// This will return true if the two collections are value-wise the same. /// If the collection contains a collection, the collections will be compared using this method. /// public static bool Equals(IEnumerable first, IEnumerable second) { if (first == null && second == null) { return true; } if (first == null || second == null) { return false; } // for dictionaries, we need to compare keys and values separately // because KeyValuePair.Equals() will not do what we want var fdict = first as IDictionary; var sdict = second as IDictionary; if ((fdict != null) || (sdict != null)) { if ((fdict == null) || (sdict == null)) return false; return TCollections.Equals(fdict.Keys, sdict.Keys) && TCollections.Equals(fdict.Values, sdict.Values); } var fiter = first.GetEnumerator(); var siter = second.GetEnumerator(); var fnext = fiter.MoveNext(); var snext = siter.MoveNext(); while (fnext && snext) { var fenum = fiter.Current as IEnumerable; var senum = siter.Current as IEnumerable; if (fenum != null && senum != null) { if (!Equals(fenum, senum)) { return false; } } else if (fenum == null ^ senum == null) { return false; } else if (!Equals(fiter.Current, siter.Current)) { return false; } fnext = fiter.MoveNext(); snext = siter.MoveNext(); } return fnext == snext; } /// /// This returns a hashcode based on the value of the enumerable. /// public static int GetHashCode(IEnumerable enumerable) { if (enumerable == null) { return 0; } var hashcode = 0; foreach (var obj in enumerable) { var objHash = (obj is IEnumerable enum2) ? GetHashCode(enum2) : obj.GetHashCode(); unchecked { hashcode = (hashcode * 397) ^ (objHash); } } return hashcode; } } } thrift-0.16.0/lib/netstd/Thrift/Collections/THashSet.cs000066400000000000000000000043051420101504100226630ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Collections; using System.Collections.Generic; namespace Thrift.Collections { // ReSharper disable once InconsistentNaming public class THashSet : ICollection { private readonly HashSet Items; public THashSet() { Items = new HashSet(); } public THashSet(int capacity) { #if NET5_0_OR_GREATER Items = new HashSet(capacity); #elif NETFRAMEWORK || NETSTANDARD Items = new HashSet(/*capacity not supported*/); #else #error Unknown platform #endif } public int Count => Items.Count; public bool IsReadOnly => false; public void Add(T item) { Items.Add(item); } public void Clear() { Items.Clear(); } public bool Contains(T item) { return Items.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { Items.CopyTo(array, arrayIndex); } IEnumerator IEnumerable.GetEnumerator() { return Items.GetEnumerator(); } public IEnumerator GetEnumerator() { return ((IEnumerable) Items).GetEnumerator(); } public bool Remove(T item) { return Items.Remove(item); } } } thrift-0.16.0/lib/netstd/Thrift/GlobalSuppressions.cs000066400000000000000000000030531420101504100225570ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. using System.Diagnostics.CodeAnalysis; // suppress certain messages for compatibility reasons with older C# versions we want to support [assembly: SuppressMessage("Style", "IDE0057", Justification = "compatibility", Scope = "module")] [assembly: SuppressMessage("Style", "IDE0066", Justification = "compatibility", Scope = "module")] [assembly: SuppressMessage("Style", "IDE0090", Justification = "compatibility", Scope = "module")] [assembly: SuppressMessage("Style", "IDE0063", Justification = "compatibility", Scope = "module")] thrift-0.16.0/lib/netstd/Thrift/Processor/000077500000000000000000000000001420101504100203505ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Processor/ITAsyncProcessor.cs000066400000000000000000000020601420101504100241070ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Threading; using System.Threading.Tasks; using Thrift.Protocol; namespace Thrift.Processor { public interface ITAsyncProcessor { Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken = default); } } thrift-0.16.0/lib/netstd/Thrift/Processor/ITProcessorFactory.cs000066400000000000000000000020541420101504100244440ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using Thrift.Server; using Thrift.Transport; namespace Thrift.Processor { // ReSharper disable once InconsistentNaming public interface ITProcessorFactory { ITAsyncProcessor GetAsyncProcessor(TTransport trans, TServer baseServer = null); } }thrift-0.16.0/lib/netstd/Thrift/Processor/TMultiplexedProcessor.cs000066400000000000000000000127471420101504100252320ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol; using Thrift.Protocol.Entities; namespace Thrift.Processor { // ReSharper disable once InconsistentNaming public class TMultiplexedProcessor : ITAsyncProcessor { //TODO: Localization private readonly Dictionary _serviceProcessorMap = new Dictionary(); public async Task ProcessAsync(TProtocol iprot, TProtocol oprot) { return await ProcessAsync(iprot, oprot, CancellationToken.None); } public async Task ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); try { var message = await iprot.ReadMessageBeginAsync(cancellationToken); if ((message.Type != TMessageType.Call) && (message.Type != TMessageType.Oneway)) { await FailAsync(oprot, message, TApplicationException.ExceptionType.InvalidMessageType, "Message exType CALL or ONEWAY expected", cancellationToken); return false; } // Extract the service name var index = message.Name.IndexOf(TMultiplexedProtocol.Separator, StringComparison.Ordinal); if (index < 0) { await FailAsync(oprot, message, TApplicationException.ExceptionType.InvalidProtocol, $"Service name not found in message name: {message.Name}. Did you forget to use a TMultiplexProtocol in your client?", cancellationToken); return false; } // Create a new TMessage, something that can be consumed by any TProtocol var serviceName = message.Name.Substring(0, index); if (!_serviceProcessorMap.TryGetValue(serviceName, out ITAsyncProcessor actualProcessor)) { await FailAsync(oprot, message, TApplicationException.ExceptionType.InternalError, $"Service name not found: {serviceName}. Did you forget to call RegisterProcessor()?", cancellationToken); return false; } // Create a new TMessage, removing the service name var newMessage = new TMessage( message.Name.Substring(serviceName.Length + TMultiplexedProtocol.Separator.Length), message.Type, message.SeqID); // Dispatch processing to the stored processor return await actualProcessor.ProcessAsync(new StoredMessageProtocol(iprot, newMessage), oprot, cancellationToken); } catch (IOException) { return false; // similar to all other processors } } public void RegisterProcessor(string serviceName, ITAsyncProcessor processor) { if (_serviceProcessorMap.ContainsKey(serviceName)) { throw new InvalidOperationException( $"Processor map already contains processor with name: '{serviceName}'"); } _serviceProcessorMap.Add(serviceName, processor); } private static async Task FailAsync(TProtocol oprot, TMessage message, TApplicationException.ExceptionType extype, string etxt, CancellationToken cancellationToken) { var appex = new TApplicationException(extype, etxt); var newMessage = new TMessage(message.Name, TMessageType.Exception, message.SeqID); await oprot.WriteMessageBeginAsync(newMessage, cancellationToken); await appex.WriteAsync(oprot, cancellationToken); await oprot.WriteMessageEndAsync(cancellationToken); await oprot.Transport.FlushAsync(cancellationToken); } private class StoredMessageProtocol : TProtocolDecorator { readonly TMessage _msgBegin; public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin) : base(protocol) { _msgBegin = messageBegin; } public override ValueTask ReadMessageBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return new ValueTask(_msgBegin); } } } } thrift-0.16.0/lib/netstd/Thrift/Processor/TSingletonProcessorFactory.cs000066400000000000000000000025151420101504100262200ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using Thrift.Server; using Thrift.Transport; namespace Thrift.Processor { // ReSharper disable once InconsistentNaming public class TSingletonProcessorFactory : ITProcessorFactory { private readonly ITAsyncProcessor _asyncProcessor; public TSingletonProcessorFactory(ITAsyncProcessor asyncProcessor) { _asyncProcessor = asyncProcessor; } public ITAsyncProcessor GetAsyncProcessor(TTransport trans, TServer baseServer = null) { return _asyncProcessor; } } }thrift-0.16.0/lib/netstd/Thrift/Properties/000077500000000000000000000000001420101504100205255ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Properties/AssemblyInfo.cs000066400000000000000000000043131420101504100234500ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Thrift")] [assembly: AssemblyDescription("C# .NET Core bindings for the Apache Thrift RPC system")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("The Apache Software Foundation")] [assembly: AssemblyProduct("Thrift")] [assembly: AssemblyCopyright("The Apache Software Foundation")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] //@TODO where to put License information? // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a exType in this assembly from // COM, set the ComVisible attribute to true on that exType. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("df3f8ef0-e0a3-4c86-a65b-8ec84e016b1d")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("0.16.0.0")] [assembly: AssemblyFileVersion("0.16.0.0")] thrift-0.16.0/lib/netstd/Thrift/Protocol/000077500000000000000000000000001420101504100201725ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/000077500000000000000000000000001420101504100217565ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TField.cs000066400000000000000000000024101420101504100234510ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public struct TField { public TField(string name, TType type, short id) { Name = name; Type = type; ID = id; } public string Name { get; set; } public TType Type { get; set; } // ReSharper disable once InconsistentNaming - do not rename - it used for generation public short ID { get; set; } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TList.cs000066400000000000000000000021731420101504100233470ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public struct TList { public TList(TType elementType, int count) { ElementType = elementType; Count = count; } public TType ElementType { get; set; } public int Count { get; set; } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TMap.cs000066400000000000000000000023131420101504100231450ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public struct TMap { public TMap(TType keyType, TType valueType, int count) { KeyType = keyType; ValueType = valueType; Count = count; } public TType KeyType { get; set; } public TType ValueType { get; set; } public int Count { get; set; } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TMessage.cs000066400000000000000000000024421420101504100240170ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public struct TMessage { public TMessage(string name, TMessageType type, int seqid) { Name = name; Type = type; SeqID = seqid; } public string Name { get; set; } public TMessageType Type { get; set; } // ReSharper disable once InconsistentNaming - do not rename - it used for generation public int SeqID { get; set; } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TMessageType.cs000066400000000000000000000017561420101504100246700ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public enum TMessageType { Call = 1, Reply = 2, Exception = 3, Oneway = 4 } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TSet.cs000066400000000000000000000023371420101504100231710ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public struct TSet { public TSet(TType elementType, int count) { ElementType = elementType; Count = count; } public TSet(TList list) : this(list.ElementType, list.Count) { } public TType ElementType { get; set; } public int Count { get; set; } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TStruct.cs000066400000000000000000000020351420101504100237150ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public readonly struct TStruct { public TStruct(string name) { Name = name; } public string Name { get; } } } thrift-0.16.0/lib/netstd/Thrift/Protocol/Entities/TType.cs000066400000000000000000000022171420101504100233540ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Entities { // ReSharper disable once InconsistentNaming public enum TType : byte { Stop = 0, Void = 1, Bool = 2, Byte = 3, Double = 4, I16 = 6, I32 = 8, I64 = 10, String = 11, Struct = 12, Map = 13, Set = 14, List = 15 } }thrift-0.16.0/lib/netstd/Thrift/Protocol/TBase.cs000066400000000000000000000024351420101504100215230ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Threading; using System.Threading.Tasks; #pragma warning disable IDE1006 // some interfaces here are intentionally not I-prefixed namespace Thrift.Protocol { public interface TUnionBase { Task WriteAsync(TProtocol tProtocol, CancellationToken cancellationToken = default); } // ReSharper disable once InconsistentNaming public interface TBase : TUnionBase { Task ReadAsync(TProtocol tProtocol, CancellationToken cancellationToken = default); } } thrift-0.16.0/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs000066400000000000000000000426751420101504100236310ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Buffers.Binary; using System.Text; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; using Thrift.Transport; namespace Thrift.Protocol { // ReSharper disable once InconsistentNaming public class TBinaryProtocol : TProtocol { protected const uint VersionMask = 0xffff0000; protected const uint Version1 = 0x80010000; protected bool StrictRead; protected bool StrictWrite; // minimize memory allocations by means of an preallocated bytes buffer // The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long) private readonly byte[] PreAllocatedBuffer = new byte[128]; public TBinaryProtocol(TTransport trans) : this(trans, false, true) { } public TBinaryProtocol(TTransport trans, bool strictRead, bool strictWrite) : base(trans) { StrictRead = strictRead; StrictWrite = strictWrite; } public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (StrictWrite) { var version = Version1 | (uint) message.Type; await WriteI32Async((int) version, cancellationToken); await WriteStringAsync(message.Name, cancellationToken); await WriteI32Async(message.SeqID, cancellationToken); } else { await WriteStringAsync(message.Name, cancellationToken); await WriteByteAsync((sbyte) message.Type, cancellationToken); await WriteI32Async(message.SeqID, cancellationToken); } } public override Task WriteMessageEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override Task WriteStructEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteByteAsync((sbyte) field.Type, cancellationToken); await WriteI16Async(field.ID, cancellationToken); } public override Task WriteFieldEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteFieldStopAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteByteAsync((sbyte) TType.Stop, cancellationToken); } public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); PreAllocatedBuffer[0] = (byte)map.KeyType; PreAllocatedBuffer[1] = (byte)map.ValueType; await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken); await WriteI32Async(map.Count, cancellationToken); } public override Task WriteMapEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteByteAsync((sbyte) list.ElementType, cancellationToken); await WriteI32Async(list.Count, cancellationToken); } public override Task WriteListEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteByteAsync((sbyte) set.ElementType, cancellationToken); await WriteI32Async(set.Count, cancellationToken); } public override Task WriteSetEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteByteAsync(b ? (sbyte) 1 : (sbyte) 0, cancellationToken); } public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); PreAllocatedBuffer[0] = (byte)b; await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); } public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); BinaryPrimitives.WriteInt16BigEndian(PreAllocatedBuffer, i16); await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken); } public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); BinaryPrimitives.WriteInt32BigEndian(PreAllocatedBuffer, i32); await Trans.WriteAsync(PreAllocatedBuffer, 0, 4, cancellationToken); } public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); BinaryPrimitives.WriteInt64BigEndian(PreAllocatedBuffer, i64); await Trans.WriteAsync(PreAllocatedBuffer, 0, 8, cancellationToken); } public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteI64Async(BitConverter.DoubleToInt64Bits(d), cancellationToken); } public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteI32Async(bytes.Length, cancellationToken); await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken); } public override async ValueTask ReadMessageBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var message = new TMessage(); var size = await ReadI32Async(cancellationToken); if (size < 0) { var version = (uint) size & VersionMask; if (version != Version1) { throw new TProtocolException(TProtocolException.BAD_VERSION, $"Bad version in ReadMessageBegin: {version}"); } message.Type = (TMessageType) (size & 0x000000ff); message.Name = await ReadStringAsync(cancellationToken); message.SeqID = await ReadI32Async(cancellationToken); } else { if (StrictRead) { throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in ReadMessageBegin, old client?"); } message.Name = (size > 0) ? await ReadStringBodyAsync(size, cancellationToken) : string.Empty; message.Type = (TMessageType) await ReadByteAsync(cancellationToken); message.SeqID = await ReadI32Async(cancellationToken); } return message; } public override Task ReadMessageEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override ValueTask ReadStructBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return new ValueTask(AnonymousStruct); } public override Task ReadStructEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadFieldBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var type = (TType)await ReadByteAsync(cancellationToken); if (type == TType.Stop) { return StopField; } return new TField { Type = type, ID = await ReadI16Async(cancellationToken) }; } public override Task ReadFieldEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadMapBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var map = new TMap { KeyType = (TType) await ReadByteAsync(cancellationToken), ValueType = (TType) await ReadByteAsync(cancellationToken), Count = await ReadI32Async(cancellationToken) }; CheckReadBytesAvailable(map); return map; } public override Task ReadMapEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadListBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var list = new TList { ElementType = (TType) await ReadByteAsync(cancellationToken), Count = await ReadI32Async(cancellationToken) }; CheckReadBytesAvailable(list); return list; } public override Task ReadListEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadSetBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var set = new TSet { ElementType = (TType) await ReadByteAsync(cancellationToken), Count = await ReadI32Async(cancellationToken) }; CheckReadBytesAvailable(set); return set; } public override Task ReadSetEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadBoolAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return await ReadByteAsync(cancellationToken) == 1; } public override async ValueTask ReadByteAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 1, cancellationToken); return (sbyte)PreAllocatedBuffer[0]; } public override async ValueTask ReadI16Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 2, cancellationToken); var result = BinaryPrimitives.ReadInt16BigEndian(PreAllocatedBuffer); return result; } public override async ValueTask ReadI32Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 4, cancellationToken); var result = BinaryPrimitives.ReadInt32BigEndian(PreAllocatedBuffer); return result; } public override async ValueTask ReadI64Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 8, cancellationToken); return BinaryPrimitives.ReadInt64BigEndian(PreAllocatedBuffer); } public override async ValueTask ReadDoubleAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var d = await ReadI64Async(cancellationToken); return BitConverter.Int64BitsToDouble(d); } public override async ValueTask ReadBinaryAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var size = await ReadI32Async(cancellationToken); Transport.CheckReadBytesAvailable(size); var buf = new byte[size]; await Trans.ReadAllAsync(buf, 0, size, cancellationToken); return buf; } public override async ValueTask ReadStringAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var size = await ReadI32Async(cancellationToken); return size > 0 ? await ReadStringBodyAsync(size, cancellationToken) : string.Empty; } private async ValueTask ReadStringBodyAsync(int size, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (size <= PreAllocatedBuffer.Length) { await Trans.ReadAllAsync(PreAllocatedBuffer, 0, size, cancellationToken); return Encoding.UTF8.GetString(PreAllocatedBuffer, 0, size); } Transport.CheckReadBytesAvailable(size); var buf = new byte[size]; await Trans.ReadAllAsync(buf, 0, size, cancellationToken); return Encoding.UTF8.GetString(buf, 0, buf.Length); } // Return the minimum number of bytes a type will consume on the wire public override int GetMinSerializedSize(TType type) { switch (type) { case TType.Stop: return 0; case TType.Void: return 0; case TType.Bool: return sizeof(byte); case TType.Byte: return sizeof(byte); case TType.Double: return sizeof(double); case TType.I16: return sizeof(short); case TType.I32: return sizeof(int); case TType.I64: return sizeof(long); case TType.String: return sizeof(int); // string length case TType.Struct: return 0; // empty struct case TType.Map: return sizeof(int); // element count case TType.Set: return sizeof(int); // element count case TType.List: return sizeof(int); // element count default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); } } public class Factory : TProtocolFactory { protected bool StrictRead; protected bool StrictWrite; public Factory() : this(false, true) { } public Factory(bool strictRead, bool strictWrite) { StrictRead = strictRead; StrictWrite = strictWrite; } public override TProtocol GetProtocol(TTransport trans) { return new TBinaryProtocol(trans, StrictRead, StrictWrite); } } } } thrift-0.16.0/lib/netstd/Thrift/Protocol/TCompactProtocol.cs000066400000000000000000000761031420101504100237640ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; using Thrift.Transport; namespace Thrift.Protocol { // ReSharper disable once InconsistentNaming public class TCompactProtocol : TProtocol { private const byte ProtocolId = 0x82; private const byte Version = 1; private const byte VersionMask = 0x1f; // 0001 1111 private const byte TypeMask = 0xE0; // 1110 0000 private const byte TypeBits = 0x07; // 0000 0111 private const int TypeShiftAmount = 5; private const byte NoTypeOverride = 0xFF; // ReSharper disable once InconsistentNaming private static readonly byte[] TTypeToCompactType = new byte[16]; private static readonly TType[] CompactTypeToTType = new TType[13]; /// /// Used to keep track of the last field for the current and previous structs, so we can do the delta stuff. /// private readonly Stack _lastField = new Stack(15); /// /// If we encounter a boolean field begin, save the TField here so it can have the value incorporated. /// private TField? _booleanField; /// /// If we Read a field header, and it's a boolean field, save the boolean value here so that ReadBool can use it. /// private bool? _boolValue; private short _lastFieldId; // minimize memory allocations by means of an preallocated bytes buffer // The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long) private readonly byte[] PreAllocatedBuffer = new byte[128]; private struct VarInt { public byte[] bytes; public int count; } // minimize memory allocations by means of an preallocated VarInt buffer private VarInt PreAllocatedVarInt = new VarInt() { bytes = new byte[10], // see Int64ToVarInt() count = 0 }; public TCompactProtocol(TTransport trans) : base(trans) { TTypeToCompactType[(int) TType.Stop] = Types.Stop; TTypeToCompactType[(int) TType.Bool] = Types.BooleanTrue; TTypeToCompactType[(int) TType.Byte] = Types.Byte; TTypeToCompactType[(int) TType.I16] = Types.I16; TTypeToCompactType[(int) TType.I32] = Types.I32; TTypeToCompactType[(int) TType.I64] = Types.I64; TTypeToCompactType[(int) TType.Double] = Types.Double; TTypeToCompactType[(int) TType.String] = Types.Binary; TTypeToCompactType[(int) TType.List] = Types.List; TTypeToCompactType[(int) TType.Set] = Types.Set; TTypeToCompactType[(int) TType.Map] = Types.Map; TTypeToCompactType[(int) TType.Struct] = Types.Struct; CompactTypeToTType[Types.Stop] = TType.Stop; CompactTypeToTType[Types.BooleanTrue] = TType.Bool; CompactTypeToTType[Types.BooleanFalse] = TType.Bool; CompactTypeToTType[Types.Byte] = TType.Byte; CompactTypeToTType[Types.I16] = TType.I16; CompactTypeToTType[Types.I32] = TType.I32; CompactTypeToTType[Types.I64] = TType.I64; CompactTypeToTType[Types.Double] = TType.Double; CompactTypeToTType[Types.Binary] = TType.String; CompactTypeToTType[Types.List] = TType.List; CompactTypeToTType[Types.Set] = TType.Set; CompactTypeToTType[Types.Map] = TType.Map; CompactTypeToTType[Types.Struct] = TType.Struct; } public void Reset() { _lastField.Clear(); _lastFieldId = 0; } public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) { PreAllocatedBuffer[0] = ProtocolId; PreAllocatedBuffer[1] = (byte)((Version & VersionMask) | (((uint)message.Type << TypeShiftAmount) & TypeMask)); await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken); Int32ToVarInt((uint) message.SeqID, ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); await WriteStringAsync(message.Name, cancellationToken); } public override Task WriteMessageEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } /// /// Write a struct begin. This doesn't actually put anything on the wire. We /// use it as an opportunity to put special placeholder markers on the field /// stack so we can get the field id deltas correct. /// public override Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); _lastField.Push(_lastFieldId); _lastFieldId = 0; return Task.CompletedTask; } public override Task WriteStructEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); _lastFieldId = _lastField.Pop(); return Task.CompletedTask; } private async Task WriteFieldBeginInternalAsync(TField field, byte fieldType, CancellationToken cancellationToken) { // if there's a exType override passed in, use that. Otherwise ask GetCompactType(). if (fieldType == NoTypeOverride) fieldType = GetCompactType(field.Type); // check if we can use delta encoding for the field id if (field.ID > _lastFieldId) { var delta = field.ID - _lastFieldId; if (delta <= 15) { // Write them together PreAllocatedBuffer[0] = (byte)((delta << 4) | fieldType); await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); _lastFieldId = field.ID; return; } } // Write them separate PreAllocatedBuffer[0] = fieldType; await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); await WriteI16Async(field.ID, cancellationToken); _lastFieldId = field.ID; } public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) { if (field.Type == TType.Bool) { _booleanField = field; } else { await WriteFieldBeginInternalAsync(field, NoTypeOverride, cancellationToken); } } public override Task WriteFieldEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteFieldStopAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); PreAllocatedBuffer[0] = Types.Stop; await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); } protected async Task WriteCollectionBeginAsync(TType elemType, int size, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Abstract method for writing the start of lists and sets. List and sets on the wire differ only by the exType indicator. */ if (size <= 14) { PreAllocatedBuffer[0] = (byte)((size << 4) | GetCompactType(elemType)); await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); } else { PreAllocatedBuffer[0] = (byte)(0xf0 | GetCompactType(elemType)); await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); Int32ToVarInt((uint) size, ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); } } public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) { await WriteCollectionBeginAsync(list.ElementType, list.Count, cancellationToken); } public override Task WriteListEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await WriteCollectionBeginAsync(set.ElementType, set.Count, cancellationToken); } public override Task WriteSetEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Write a boolean value. Potentially, this could be a boolean field, in which case the field header info isn't written yet. If so, decide what the right exType header is for the value and then Write the field header. Otherwise, Write a single byte. */ if (_booleanField != null) { // we haven't written the field header yet var type = b ? Types.BooleanTrue : Types.BooleanFalse; await WriteFieldBeginInternalAsync(_booleanField.Value, type, cancellationToken); _booleanField = null; } else { // we're not part of a field, so just write the value. PreAllocatedBuffer[0] = b ? Types.BooleanTrue : Types.BooleanFalse; await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); } } public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); PreAllocatedBuffer[0] = (byte)b; await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); } public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Int32ToVarInt(IntToZigzag(i16), ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); } private static void Int32ToVarInt(uint n, ref VarInt varint) { // Write an i32 as a varint. Results in 1 - 5 bytes on the wire. varint.count = 0; Debug.Assert(varint.bytes.Length >= 5); while (true) { if ((n & ~0x7F) == 0) { varint.bytes[varint.count++] = (byte)n; break; } varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80); n >>= 7; } } public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Int32ToVarInt(IntToZigzag(i32), ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); } static private void Int64ToVarInt(ulong n, ref VarInt varint) { // Write an i64 as a varint. Results in 1-10 bytes on the wire. varint.count = 0; Debug.Assert(varint.bytes.Length >= 10); while (true) { if ((n & ~(ulong)0x7FL) == 0) { varint.bytes[varint.count++] = (byte)n; break; } varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80); n >>= 7; } } public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Int64ToVarInt(LongToZigzag(i64), ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); } public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); BinaryPrimitives.WriteInt64LittleEndian(PreAllocatedBuffer, BitConverter.DoubleToInt64Bits(d)); await Trans.WriteAsync(PreAllocatedBuffer, 0, 8, cancellationToken); } public override async Task WriteStringAsync(string str, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var buf = ArrayPool.Shared.Rent(Encoding.UTF8.GetByteCount(str)); try { var numberOfBytes = Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0); Int32ToVarInt((uint)numberOfBytes, ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); await Trans.WriteAsync(buf, 0, numberOfBytes, cancellationToken); } finally { ArrayPool.Shared.Return(buf); } } public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Int32ToVarInt((uint) bytes.Length, ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken); } public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (map.Count == 0) { PreAllocatedBuffer[0] = 0; await Trans.WriteAsync( PreAllocatedBuffer, 0, 1, cancellationToken); } else { Int32ToVarInt((uint) map.Count, ref PreAllocatedVarInt); await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken); PreAllocatedBuffer[0] = (byte)((GetCompactType(map.KeyType) << 4) | GetCompactType(map.ValueType)); await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken); } } public override Task WriteMapEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadMessageBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var protocolId = (byte) await ReadByteAsync(cancellationToken); if (protocolId != ProtocolId) { throw new TProtocolException($"Expected protocol id {ProtocolId:X} but got {protocolId:X}"); } var versionAndType = (byte) await ReadByteAsync(cancellationToken); var version = (byte) (versionAndType & VersionMask); if (version != Version) { throw new TProtocolException($"Expected version {Version} but got {version}"); } var type = (byte) ((versionAndType >> TypeShiftAmount) & TypeBits); var seqid = (int) await ReadVarInt32Async(cancellationToken); var messageName = await ReadStringAsync(cancellationToken); return new TMessage(messageName, (TMessageType) type, seqid); } public override Task ReadMessageEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override ValueTask ReadStructBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); _lastField.Push(_lastFieldId); _lastFieldId = 0; return new ValueTask(AnonymousStruct); } public override Task ReadStructEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Doesn't actually consume any wire data, just removes the last field for this struct from the field stack. */ // consume the last field we Read off the wire. _lastFieldId = _lastField.Pop(); return Task.CompletedTask; } public override async ValueTask ReadFieldBeginAsync(CancellationToken cancellationToken) { // Read a field header off the wire. var type = (byte) await ReadByteAsync(cancellationToken); // if it's a stop, then we can return immediately, as the struct is over. if (type == Types.Stop) { return StopField; } // mask off the 4 MSB of the exType header. it could contain a field id delta. var modifier = (short) ((type & 0xf0) >> 4); var compactType = (byte)(type & 0x0f); short fieldId; if (modifier == 0) { fieldId = await ReadI16Async(cancellationToken); } else { fieldId = (short) (_lastFieldId + modifier); } var ttype = GetTType(compactType); var field = new TField(string.Empty, ttype, fieldId); // if this happens to be a boolean field, the value is encoded in the exType if( ttype == TType.Bool) { _boolValue = (compactType == Types.BooleanTrue); } // push the new field onto the field stack so we can keep the deltas going. _lastFieldId = field.ID; return field; } public override Task ReadFieldEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadMapBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Read a map header off the wire. If the size is zero, skip Reading the key and value exType. This means that 0-length maps will yield TMaps without the "correct" types. */ var size = (int) await ReadVarInt32Async(cancellationToken); var keyAndValueType = size == 0 ? (byte) 0 : (byte) await ReadByteAsync(cancellationToken); var map = new TMap(GetTType((byte) (keyAndValueType >> 4)), GetTType((byte) (keyAndValueType & 0xf)), size); CheckReadBytesAvailable(map); return map; } public override Task ReadMapEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async ValueTask ReadSetBeginAsync(CancellationToken cancellationToken) { /* Read a set header off the wire. If the set size is 0-14, the size will be packed into the element exType header. If it's a longer set, the 4 MSB of the element exType header will be 0xF, and a varint will follow with the true size. */ return new TSet(await ReadListBeginAsync(cancellationToken)); } public override ValueTask ReadBoolAsync(CancellationToken cancellationToken) { /* Read a boolean off the wire. If this is a boolean field, the value should already have been Read during ReadFieldBegin, so we'll just consume the pre-stored value. Otherwise, Read a byte. */ if (_boolValue != null) { var result = _boolValue.Value; _boolValue = null; return new ValueTask(result); } return InternalCall(); async ValueTask InternalCall() { var data = await ReadByteAsync(cancellationToken); return (data == Types.BooleanTrue); } } public override async ValueTask ReadByteAsync(CancellationToken cancellationToken) { // Read a single byte off the wire. Nothing interesting here. await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 1, cancellationToken); return (sbyte)PreAllocatedBuffer[0]; } public override async ValueTask ReadI16Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return (short) ZigzagToInt(await ReadVarInt32Async(cancellationToken)); } public override async ValueTask ReadI32Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return ZigzagToInt(await ReadVarInt32Async(cancellationToken)); } public override async ValueTask ReadI64Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return ZigzagToLong(await ReadVarInt64Async(cancellationToken)); } public override async ValueTask ReadDoubleAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 8, cancellationToken); return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(PreAllocatedBuffer)); } public override async ValueTask ReadStringAsync(CancellationToken cancellationToken) { // read length var length = (int) await ReadVarInt32Async(cancellationToken); if (length == 0) { return string.Empty; } // read and decode data if (length < PreAllocatedBuffer.Length) { await Trans.ReadAllAsync(PreAllocatedBuffer, 0, length, cancellationToken); return Encoding.UTF8.GetString(PreAllocatedBuffer, 0, length); } Transport.CheckReadBytesAvailable(length); var buf = ArrayPool.Shared.Rent(length); try { await Trans.ReadAllAsync(buf, 0, length, cancellationToken); return Encoding.UTF8.GetString(buf, 0, length); } finally { ArrayPool.Shared.Return(buf); } } public override async ValueTask ReadBinaryAsync(CancellationToken cancellationToken) { // read length var length = (int) await ReadVarInt32Async(cancellationToken); if (length == 0) { return Array.Empty(); } // read data Transport.CheckReadBytesAvailable(length); var buf = new byte[length]; await Trans.ReadAllAsync(buf, 0, length, cancellationToken); return buf; } public override async ValueTask ReadListBeginAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Read a list header off the wire. If the list size is 0-14, the size will be packed into the element exType header. If it's a longer list, the 4 MSB of the element exType header will be 0xF, and a varint will follow with the true size. */ var sizeAndType = (byte) await ReadByteAsync(cancellationToken); var size = (sizeAndType >> 4) & 0x0f; if (size == 15) { size = (int) await ReadVarInt32Async(cancellationToken); } var type = GetTType(sizeAndType); var list = new TList(type, size); CheckReadBytesAvailable(list); return list; } public override Task ReadListEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override Task ReadSetEndAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } private static byte GetCompactType(TType ttype) { // Given a TType value, find the appropriate TCompactProtocol.Types constant. return TTypeToCompactType[(int) ttype]; } private async ValueTask ReadVarInt32Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Read an i32 from the wire as a varint. The MSB of each byte is set if there is another byte to follow. This can Read up to 5 bytes. */ uint result = 0; var shift = 0; while (true) { var b = (byte) await ReadByteAsync(cancellationToken); result |= (uint) (b & 0x7f) << shift; if ((b & 0x80) != 0x80) { break; } shift += 7; } return result; } private async ValueTask ReadVarInt64Async(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); /* Read an i64 from the wire as a proper varint. The MSB of each byte is set if there is another byte to follow. This can Read up to 10 bytes. */ var shift = 0; ulong result = 0; while (true) { var b = (byte) await ReadByteAsync(cancellationToken); result |= (ulong) (b & 0x7f) << shift; if ((b & 0x80) != 0x80) { break; } shift += 7; } return result; } private static int ZigzagToInt(uint n) { return (int) (n >> 1) ^ -(int) (n & 1); } private static long ZigzagToLong(ulong n) { return (long) (n >> 1) ^ -(long) (n & 1); } private static TType GetTType(byte type) { // Given a TCompactProtocol.Types constant, convert it to its corresponding TType value. return CompactTypeToTType[type & 0x0f]; } private static ulong LongToZigzag(long n) { // Convert l into a zigzag long. This allows negative numbers to be represented compactly as a varint return (ulong) (n << 1) ^ (ulong) (n >> 63); } private static uint IntToZigzag(int n) { // Convert n into a zigzag int. This allows negative numbers to be represented compactly as a varint return (uint) (n << 1) ^ (uint) (n >> 31); } // Return the minimum number of bytes a type will consume on the wire public override int GetMinSerializedSize(TType type) { switch (type) { case TType.Stop: return 0; case TType.Void: return 0; case TType.Bool: return sizeof(byte); case TType.Double: return 8; // uses fixedLongToBytes() which always writes 8 bytes case TType.Byte: return sizeof(byte); case TType.I16: return sizeof(byte); // zigzag case TType.I32: return sizeof(byte); // zigzag case TType.I64: return sizeof(byte); // zigzag case TType.String: return sizeof(byte); // string length case TType.Struct: return 0; // empty struct case TType.Map: return sizeof(byte); // element count case TType.Set: return sizeof(byte); // element count case TType.List: return sizeof(byte); // element count default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); } } public class Factory : TProtocolFactory { public override TProtocol GetProtocol(TTransport trans) { return new TCompactProtocol(trans); } } /// /// All of the on-wire exType codes. /// private static class Types { public const byte Stop = 0x00; public const byte BooleanTrue = 0x01; public const byte BooleanFalse = 0x02; public const byte Byte = 0x03; public const byte I16 = 0x04; public const byte I32 = 0x05; public const byte I64 = 0x06; public const byte Double = 0x07; public const byte Binary = 0x08; public const byte List = 0x09; public const byte Set = 0x0A; public const byte Map = 0x0B; public const byte Struct = 0x0C; } } } thrift-0.16.0/lib/netstd/Thrift/Protocol/TJSONProtocol.cs000066400000000000000000001157441420101504100231540ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; using Thrift.Protocol.Utilities; using Thrift.Transport; namespace Thrift.Protocol { /// /// JSON protocol implementation for thrift. /// This is a full-featured protocol supporting Write and Read. /// Please see the C++ class header for a detailed description of the /// protocol's wire format. /// Adapted from the Java version. /// // ReSharper disable once InconsistentNaming public class TJsonProtocol : TProtocol { private const long Version = 1; // Temporary buffer used by several methods private readonly byte[] _tempBuffer = new byte[4]; // Current context that we are in protected JSONBaseContext Context; // Stack of nested contexts that we may be in protected Stack ContextStack = new Stack(); // Reader that manages a 1-byte buffer protected LookaheadReader Reader; // Default encoding protected Encoding Utf8Encoding = Encoding.UTF8; /// /// TJsonProtocol Constructor /// public TJsonProtocol(TTransport trans) : base(trans) { Context = new JSONBaseContext(this); Reader = new LookaheadReader(this); } /// /// Push a new JSON context onto the stack. /// protected void PushContext(JSONBaseContext c) { ContextStack.Push(Context); Context = c; } /// /// Pop the last JSON context off the stack /// protected void PopContext() { Context = ContextStack.Pop(); } /// /// Resets the context stack to pristine state. Allows for reusal of the protocol /// even in cases where the protocol instance was in an undefined state due to /// dangling/stale/obsolete contexts /// private void ResetContext() { ContextStack.Clear(); Context = new JSONBaseContext(this); } /// /// Read a byte that must match b[0]; otherwise an exception is thrown. /// Marked protected to avoid synthetic accessor in JSONListContext.Read /// and JSONPairContext.Read /// protected async Task ReadJsonSyntaxCharAsync(byte[] bytes, CancellationToken cancellationToken) { var ch = await Reader.ReadAsync(cancellationToken); if (ch != bytes[0]) { throw new TProtocolException(TProtocolException.INVALID_DATA, $"Unexpected character: {(char) ch}"); } } /// /// Write the bytes in array buf as a JSON characters, escaping as needed /// private async Task WriteJsonStringAsync(byte[] bytes, CancellationToken cancellationToken) { await Context.WriteConditionalDelimiterAsync(cancellationToken); await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); var len = bytes.Length; for (var i = 0; i < len; i++) { if ((bytes[i] & 0x00FF) >= 0x30) { if (bytes[i] == TJSONProtocolConstants.Backslash[0]) { await Trans.WriteAsync(TJSONProtocolConstants.Backslash, cancellationToken); await Trans.WriteAsync(TJSONProtocolConstants.Backslash, cancellationToken); } else { await Trans.WriteAsync(bytes, i, 1, cancellationToken); } } else { _tempBuffer[0] = TJSONProtocolConstants.JsonCharTable[bytes[i]]; if (_tempBuffer[0] == 1) { await Trans.WriteAsync(bytes, i, 1, cancellationToken); } else if (_tempBuffer[0] > 1) { await Trans.WriteAsync(TJSONProtocolConstants.Backslash, cancellationToken); await Trans.WriteAsync(_tempBuffer, 0, 1, cancellationToken); } else { await Trans.WriteAsync(TJSONProtocolConstants.EscSequences, cancellationToken); _tempBuffer[0] = TJSONProtocolHelper.ToHexChar((byte) (bytes[i] >> 4)); _tempBuffer[1] = TJSONProtocolHelper.ToHexChar(bytes[i]); await Trans.WriteAsync(_tempBuffer, 0, 2, cancellationToken); } } } await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); } /// /// Write out number as a JSON value. If the context dictates so, it will be /// wrapped in quotes to output as a JSON string. /// private async Task WriteJsonIntegerAsync(long num, CancellationToken cancellationToken) { await Context.WriteConditionalDelimiterAsync(cancellationToken); var str = num.ToString(); var escapeNum = Context.EscapeNumbers(); if (escapeNum) { await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); } var bytes = Utf8Encoding.GetBytes(str); await Trans.WriteAsync(bytes, cancellationToken); if (escapeNum) { await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); } } /// /// Write out a double as a JSON value. If it is NaN or infinity or if the /// context dictates escaping, Write out as JSON string. /// private async Task WriteJsonDoubleAsync(double num, CancellationToken cancellationToken) { await Context.WriteConditionalDelimiterAsync(cancellationToken); var str = num.ToString("G17", CultureInfo.InvariantCulture); var special = false; switch (str[0]) { case 'N': // NaN case 'I': // Infinity special = true; break; case '-': if (str[1] == 'I') { // -Infinity special = true; } break; } var escapeNum = special || Context.EscapeNumbers(); if (escapeNum) { await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); } await Trans.WriteAsync(Utf8Encoding.GetBytes(str), cancellationToken); if (escapeNum) { await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); } } /// /// Write out contents of byte array b as a JSON string with base-64 encoded /// data /// private async Task WriteJsonBase64Async(byte[] bytes, CancellationToken cancellationToken) { await Context.WriteConditionalDelimiterAsync(cancellationToken); await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); var len = bytes.Length; var off = 0; while (len >= 3) { // Encode 3 bytes at a time TBase64Utils.Encode(bytes, off, 3, _tempBuffer, 0); await Trans.WriteAsync(_tempBuffer, 0, 4, cancellationToken); off += 3; len -= 3; } if (len > 0) { // Encode remainder TBase64Utils.Encode(bytes, off, len, _tempBuffer, 0); await Trans.WriteAsync(_tempBuffer, 0, len + 1, cancellationToken); } await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken); } private async Task WriteJsonObjectStartAsync(CancellationToken cancellationToken) { await Context.WriteConditionalDelimiterAsync(cancellationToken); await Trans.WriteAsync(TJSONProtocolConstants.LeftBrace, cancellationToken); PushContext(new JSONPairContext(this)); } private async Task WriteJsonObjectEndAsync(CancellationToken cancellationToken) { PopContext(); await Trans.WriteAsync(TJSONProtocolConstants.RightBrace, cancellationToken); } private async Task WriteJsonArrayStartAsync(CancellationToken cancellationToken) { await Context.WriteConditionalDelimiterAsync(cancellationToken); await Trans.WriteAsync(TJSONProtocolConstants.LeftBracket, cancellationToken); PushContext(new JSONListContext(this)); } private async Task WriteJsonArrayEndAsync(CancellationToken cancellationToken) { PopContext(); await Trans.WriteAsync(TJSONProtocolConstants.RightBracket, cancellationToken); } public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) { ResetContext(); await WriteJsonArrayStartAsync(cancellationToken); await WriteJsonIntegerAsync(Version, cancellationToken); var b = Utf8Encoding.GetBytes(message.Name); await WriteJsonStringAsync(b, cancellationToken); await WriteJsonIntegerAsync((long) message.Type, cancellationToken); await WriteJsonIntegerAsync(message.SeqID, cancellationToken); } public override async Task WriteMessageEndAsync(CancellationToken cancellationToken) { await WriteJsonArrayEndAsync(cancellationToken); } public override async Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken) { await WriteJsonObjectStartAsync(cancellationToken); } public override async Task WriteStructEndAsync(CancellationToken cancellationToken) { await WriteJsonObjectEndAsync(cancellationToken); } public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) { await WriteJsonIntegerAsync(field.ID, cancellationToken); await WriteJsonObjectStartAsync(cancellationToken); await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(field.Type), cancellationToken); } public override async Task WriteFieldEndAsync(CancellationToken cancellationToken) { await WriteJsonObjectEndAsync(cancellationToken); } public override Task WriteFieldStopAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) { await WriteJsonArrayStartAsync(cancellationToken); await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(map.KeyType), cancellationToken); await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(map.ValueType), cancellationToken); await WriteJsonIntegerAsync(map.Count, cancellationToken); await WriteJsonObjectStartAsync(cancellationToken); } public override async Task WriteMapEndAsync(CancellationToken cancellationToken) { await WriteJsonObjectEndAsync(cancellationToken); await WriteJsonArrayEndAsync(cancellationToken); } public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) { await WriteJsonArrayStartAsync(cancellationToken); await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(list.ElementType), cancellationToken); await WriteJsonIntegerAsync(list.Count, cancellationToken); } public override async Task WriteListEndAsync(CancellationToken cancellationToken) { await WriteJsonArrayEndAsync(cancellationToken); } public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) { await WriteJsonArrayStartAsync(cancellationToken); await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(set.ElementType), cancellationToken); await WriteJsonIntegerAsync(set.Count, cancellationToken); } public override async Task WriteSetEndAsync(CancellationToken cancellationToken) { await WriteJsonArrayEndAsync(cancellationToken); } public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) { await WriteJsonIntegerAsync(b ? 1 : 0, cancellationToken); } public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) { await WriteJsonIntegerAsync(b, cancellationToken); } public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) { await WriteJsonIntegerAsync(i16, cancellationToken); } public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) { await WriteJsonIntegerAsync(i32, cancellationToken); } public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) { await WriteJsonIntegerAsync(i64, cancellationToken); } public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) { await WriteJsonDoubleAsync(d, cancellationToken); } public override async Task WriteStringAsync(string s, CancellationToken cancellationToken) { var b = Utf8Encoding.GetBytes(s); await WriteJsonStringAsync(b, cancellationToken); } public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken) { await WriteJsonBase64Async(bytes, cancellationToken); } /// /// Read in a JSON string, unescaping as appropriate.. Skip Reading from the /// context if skipContext is true. /// private async ValueTask ReadJsonStringAsync(bool skipContext, CancellationToken cancellationToken) { using (var buffer = new MemoryStream()) { var codeunits = new List(); if (!skipContext) { await Context.ReadConditionalDelimiterAsync(cancellationToken); } await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken); while (true) { var ch = await Reader.ReadAsync(cancellationToken); if (ch == TJSONProtocolConstants.Quote[0]) { break; } // escaped? if (ch != TJSONProtocolConstants.EscSequences[0]) { #if NETSTANDARD2_0 await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken); #else var wbuf = new[] { ch }; await buffer.WriteAsync(wbuf.AsMemory(0, 1), cancellationToken); #endif continue; } // distinguish between \uXXXX and \? ch = await Reader.ReadAsync(cancellationToken); if (ch != TJSONProtocolConstants.EscSequences[1]) // control chars like \n { var off = Array.IndexOf(TJSONProtocolConstants.EscapeChars, (char) ch); if (off == -1) { throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected control char"); } ch = TJSONProtocolConstants.EscapeCharValues[off]; #if NETSTANDARD2_0 await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken); #else var wbuf = new[] { ch }; await buffer.WriteAsync( wbuf.AsMemory(0, 1), cancellationToken); #endif continue; } // it's \uXXXX await Trans.ReadAllAsync(_tempBuffer, 0, 4, cancellationToken); var wch = (short) ((TJSONProtocolHelper.ToHexVal(_tempBuffer[0]) << 12) + (TJSONProtocolHelper.ToHexVal(_tempBuffer[1]) << 8) + (TJSONProtocolHelper.ToHexVal(_tempBuffer[2]) << 4) + TJSONProtocolHelper.ToHexVal(_tempBuffer[3])); if (char.IsHighSurrogate((char) wch)) { if (codeunits.Count > 0) { throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected low surrogate char"); } codeunits.Add((char) wch); } else if (char.IsLowSurrogate((char) wch)) { if (codeunits.Count == 0) { throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected high surrogate char"); } codeunits.Add((char) wch); var tmp = Utf8Encoding.GetBytes(codeunits.ToArray()); #if NETSTANDARD2_0 await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken); #else await buffer.WriteAsync(tmp.AsMemory(0, tmp.Length), cancellationToken); #endif codeunits.Clear(); } else { var tmp = Utf8Encoding.GetBytes(new[] { (char)wch }); #if NETSTANDARD2_0 await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken); #else await buffer.WriteAsync(tmp.AsMemory( 0, tmp.Length), cancellationToken); #endif } } if (codeunits.Count > 0) { throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected low surrogate char"); } return buffer.ToArray(); } } /// /// Read in a sequence of characters that are all valid in JSON numbers. Does /// not do a complete regex check to validate that this is actually a number. /// private async ValueTask ReadJsonNumericCharsAsync(CancellationToken cancellationToken) { var strbld = new StringBuilder(); while (true) { //TODO: workaround for primitive types with TJsonProtocol, think - how to rewrite into more easy form without exceptions try { var ch = await Reader.PeekAsync(cancellationToken); if (!TJSONProtocolHelper.IsJsonNumeric(ch)) { break; } var c = (char)await Reader.ReadAsync(cancellationToken); strbld.Append(c); } catch (TTransportException) { break; } } return strbld.ToString(); } /// /// Read in a JSON number. If the context dictates, Read in enclosing quotes. /// private async ValueTask ReadJsonIntegerAsync(CancellationToken cancellationToken) { await Context.ReadConditionalDelimiterAsync(cancellationToken); if (Context.EscapeNumbers()) { await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken); } var str = await ReadJsonNumericCharsAsync(cancellationToken); if (Context.EscapeNumbers()) { await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken); } try { return long.Parse(str); } catch (FormatException) { throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data"); } } /// /// Read in a JSON double value. Throw if the value is not wrapped in quotes /// when expected or if wrapped in quotes when not expected. /// private async ValueTask ReadJsonDoubleAsync(CancellationToken cancellationToken) { await Context.ReadConditionalDelimiterAsync(cancellationToken); if (await Reader.PeekAsync(cancellationToken) == TJSONProtocolConstants.Quote[0]) { var arr = await ReadJsonStringAsync(true, cancellationToken); var dub = double.Parse(Utf8Encoding.GetString(arr, 0, arr.Length), CultureInfo.InvariantCulture); if (!Context.EscapeNumbers() && !double.IsNaN(dub) && !double.IsInfinity(dub)) { // Throw exception -- we should not be in a string in this case throw new TProtocolException(TProtocolException.INVALID_DATA, "Numeric data unexpectedly quoted"); } return dub; } if (Context.EscapeNumbers()) { // This will throw - we should have had a quote if escapeNum == true await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken); } try { return double.Parse(await ReadJsonNumericCharsAsync(cancellationToken), CultureInfo.InvariantCulture); } catch (FormatException) { throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data"); } } /// /// Read in a JSON string containing base-64 encoded data and decode it. /// private async ValueTask ReadJsonBase64Async(CancellationToken cancellationToken) { var b = await ReadJsonStringAsync(false, cancellationToken); var len = b.Length; var off = 0; var size = 0; // reduce len to ignore fill bytes while ((len > 0) && (b[len - 1] == '=')) { --len; } // read & decode full byte triplets = 4 source bytes while (len > 4) { // Decode 4 bytes at a time TBase64Utils.Decode(b, off, 4, b, size); // NB: decoded in place off += 4; len -= 4; size += 3; } // Don't decode if we hit the end or got a single leftover byte (invalid // base64 but legal for skip of regular string exType) if (len > 1) { // Decode remainder TBase64Utils.Decode(b, off, len, b, size); // NB: decoded in place size += len - 1; } // Sadly we must copy the byte[] (any way around this?) var result = new byte[size]; Array.Copy(b, 0, result, 0, size); return result; } private async Task ReadJsonObjectStartAsync(CancellationToken cancellationToken) { await Context.ReadConditionalDelimiterAsync(cancellationToken); await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.LeftBrace, cancellationToken); PushContext(new JSONPairContext(this)); } private async Task ReadJsonObjectEndAsync(CancellationToken cancellationToken) { await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.RightBrace, cancellationToken); PopContext(); } private async Task ReadJsonArrayStartAsync(CancellationToken cancellationToken) { await Context.ReadConditionalDelimiterAsync(cancellationToken); await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.LeftBracket, cancellationToken); PushContext(new JSONListContext(this)); } private async Task ReadJsonArrayEndAsync(CancellationToken cancellationToken) { await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.RightBracket, cancellationToken); PopContext(); } public override async ValueTask ReadMessageBeginAsync(CancellationToken cancellationToken) { var message = new TMessage(); ResetContext(); await ReadJsonArrayStartAsync(cancellationToken); if (await ReadJsonIntegerAsync(cancellationToken) != Version) { throw new TProtocolException(TProtocolException.BAD_VERSION, "Message contained bad version."); } var buf = await ReadJsonStringAsync(false, cancellationToken); message.Name = Utf8Encoding.GetString(buf, 0, buf.Length); message.Type = (TMessageType) await ReadJsonIntegerAsync(cancellationToken); message.SeqID = (int) await ReadJsonIntegerAsync(cancellationToken); return message; } public override async Task ReadMessageEndAsync(CancellationToken cancellationToken) { await ReadJsonArrayEndAsync(cancellationToken); } public override async ValueTask ReadStructBeginAsync(CancellationToken cancellationToken) { await ReadJsonObjectStartAsync(cancellationToken); return AnonymousStruct; } public override async Task ReadStructEndAsync(CancellationToken cancellationToken) { await ReadJsonObjectEndAsync(cancellationToken); } public override async ValueTask ReadFieldBeginAsync(CancellationToken cancellationToken) { var ch = await Reader.PeekAsync(cancellationToken); if (ch == TJSONProtocolConstants.RightBrace[0]) { return StopField; } var field = new TField() { ID = (short)await ReadJsonIntegerAsync(cancellationToken) }; await ReadJsonObjectStartAsync(cancellationToken); field.Type = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); return field; } public override async Task ReadFieldEndAsync(CancellationToken cancellationToken) { await ReadJsonObjectEndAsync(cancellationToken); } public override async ValueTask ReadMapBeginAsync(CancellationToken cancellationToken) { var map = new TMap(); await ReadJsonArrayStartAsync(cancellationToken); map.KeyType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); map.ValueType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); map.Count = (int) await ReadJsonIntegerAsync(cancellationToken); CheckReadBytesAvailable(map); await ReadJsonObjectStartAsync(cancellationToken); return map; } public override async Task ReadMapEndAsync(CancellationToken cancellationToken) { await ReadJsonObjectEndAsync(cancellationToken); await ReadJsonArrayEndAsync(cancellationToken); } public override async ValueTask ReadListBeginAsync(CancellationToken cancellationToken) { var list = new TList(); await ReadJsonArrayStartAsync(cancellationToken); list.ElementType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); list.Count = (int) await ReadJsonIntegerAsync(cancellationToken); CheckReadBytesAvailable(list); return list; } public override async Task ReadListEndAsync(CancellationToken cancellationToken) { await ReadJsonArrayEndAsync(cancellationToken); } public override async ValueTask ReadSetBeginAsync(CancellationToken cancellationToken) { var set = new TSet(); await ReadJsonArrayStartAsync(cancellationToken); set.ElementType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken)); set.Count = (int) await ReadJsonIntegerAsync(cancellationToken); CheckReadBytesAvailable(set); return set; } public override async Task ReadSetEndAsync(CancellationToken cancellationToken) { await ReadJsonArrayEndAsync(cancellationToken); } public override async ValueTask ReadBoolAsync(CancellationToken cancellationToken) { return await ReadJsonIntegerAsync(cancellationToken) != 0; } public override async ValueTask ReadByteAsync(CancellationToken cancellationToken) { return (sbyte) await ReadJsonIntegerAsync(cancellationToken); } public override async ValueTask ReadI16Async(CancellationToken cancellationToken) { return (short) await ReadJsonIntegerAsync(cancellationToken); } public override async ValueTask ReadI32Async(CancellationToken cancellationToken) { return (int) await ReadJsonIntegerAsync(cancellationToken); } public override async ValueTask ReadI64Async(CancellationToken cancellationToken) { return await ReadJsonIntegerAsync(cancellationToken); } public override async ValueTask ReadDoubleAsync(CancellationToken cancellationToken) { return await ReadJsonDoubleAsync(cancellationToken); } public override async ValueTask ReadStringAsync(CancellationToken cancellationToken) { var buf = await ReadJsonStringAsync(false, cancellationToken); return Utf8Encoding.GetString(buf, 0, buf.Length); } public override async ValueTask ReadBinaryAsync(CancellationToken cancellationToken) { return await ReadJsonBase64Async(cancellationToken); } // Return the minimum number of bytes a type will consume on the wire public override int GetMinSerializedSize(TType type) { switch (type) { case TType.Stop: return 0; case TType.Void: return 0; case TType.Bool: return 1; // written as int case TType.Byte: return 1; case TType.Double: return 1; case TType.I16: return 1; case TType.I32: return 1; case TType.I64: return 1; case TType.String: return 2; // empty string case TType.Struct: return 2; // empty struct case TType.Map: return 2; // empty map case TType.Set: return 2; // empty set case TType.List: return 2; // empty list default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); } } /// /// Factory for JSON protocol objects /// public class Factory : TProtocolFactory { public override TProtocol GetProtocol(TTransport trans) { return new TJsonProtocol(trans); } } /// /// Base class for tracking JSON contexts that may require /// inserting/Reading additional JSON syntax characters /// This base context does nothing. /// protected class JSONBaseContext { protected TJsonProtocol Proto; public JSONBaseContext(TJsonProtocol proto) { Proto = proto; } public virtual Task WriteConditionalDelimiterAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public virtual Task ReadConditionalDelimiterAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public virtual bool EscapeNumbers() { return false; } } /// /// Context for JSON lists. Will insert/Read commas before each item except /// for the first one /// protected class JSONListContext : JSONBaseContext { private bool _first = true; public JSONListContext(TJsonProtocol protocol) : base(protocol) { } public override async Task WriteConditionalDelimiterAsync(CancellationToken cancellationToken) { if (_first) { _first = false; } else { await Proto.Trans.WriteAsync(TJSONProtocolConstants.Comma, cancellationToken); } } public override async Task ReadConditionalDelimiterAsync(CancellationToken cancellationToken) { if (_first) { _first = false; } else { await Proto.ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Comma, cancellationToken); } } } /// /// Context for JSON records. Will insert/Read colons before the value portion /// of each record pair, and commas before each key except the first. In /// addition, will indicate that numbers in the key position need to be /// escaped in quotes (since JSON keys must be strings). /// // ReSharper disable once InconsistentNaming protected class JSONPairContext : JSONBaseContext { private bool _colon = true; private bool _first = true; public JSONPairContext(TJsonProtocol proto) : base(proto) { } public override async Task WriteConditionalDelimiterAsync(CancellationToken cancellationToken) { if (_first) { _first = false; _colon = true; } else { await Proto.Trans.WriteAsync(_colon ? TJSONProtocolConstants.Colon : TJSONProtocolConstants.Comma, cancellationToken); _colon = !_colon; } } public override async Task ReadConditionalDelimiterAsync(CancellationToken cancellationToken) { if (_first) { _first = false; _colon = true; } else { await Proto.ReadJsonSyntaxCharAsync(_colon ? TJSONProtocolConstants.Colon : TJSONProtocolConstants.Comma, cancellationToken); _colon = !_colon; } } public override bool EscapeNumbers() { return _colon; } } /// /// Holds up to one byte from the transport /// protected class LookaheadReader { private readonly byte[] _data = new byte[1]; private bool _hasData; protected TJsonProtocol Proto; public LookaheadReader(TJsonProtocol proto) { Proto = proto; } /// /// Return and consume the next byte to be Read, either taking it from the /// data buffer if present or getting it from the transport otherwise. /// public async ValueTask ReadAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_hasData) { _hasData = false; } else { // find more easy way to avoid exception on reading primitive types await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken); } return _data[0]; } /// /// Return the next byte to be Read without consuming, filling the data /// buffer if it has not been filled alReady. /// public async ValueTask PeekAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (!_hasData) { // find more easy way to avoid exception on reading primitive types await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken); _hasData = true; } return _data[0]; } } } } thrift-0.16.0/lib/netstd/Thrift/Protocol/TMultiplexedProtocol.cs000066400000000000000000000071131420101504100246650ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; namespace Thrift.Protocol { /** * TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift * client to communicate with a multiplexing Thrift server, by prepending the service name * to the function name during function calls. * * NOTE: THIS IS NOT TO BE USED BY SERVERS. * On the server, use TMultiplexedProcessor to handle requests from a multiplexing client. * * This example uses a single socket transport to invoke two services: * * TSocketTransport transport = new TSocketTransport("localhost", 9090); * transport.open(); * * TBinaryProtocol protocol = new TBinaryProtocol(transport); * * TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator"); * Calculator.Client service = new Calculator.Client(mp); * * TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport"); * WeatherReport.Client service2 = new WeatherReport.Client(mp2); * * System.out.println(service.add(2,2)); * System.out.println(service2.getTemperature()); * */ //TODO: implementation of TProtocol // ReSharper disable once InconsistentNaming public class TMultiplexedProtocol : TProtocolDecorator { /** Used to delimit the service name from the function name */ public const string Separator = ":"; private readonly string _serviceName; /** * Wrap the specified protocol, allowing it to be used to communicate with a * multiplexing server. The serviceName is required as it is * prepended to the message header so that the multiplexing server can broker * the function call to the proper service. * * Args: * protocol Your communication protocol of choice, e.g. TBinaryProtocol * serviceName The service name of the service communicating via this protocol. */ public TMultiplexedProtocol(TProtocol protocol, string serviceName) : base(protocol) { _serviceName = serviceName; } public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) { switch (message.Type) { case TMessageType.Call: case TMessageType.Oneway: await base.WriteMessageBeginAsync(new TMessage($"{_serviceName}{Separator}{message.Name}", message.Type, message.SeqID), cancellationToken); break; default: await base.WriteMessageBeginAsync(message, cancellationToken); break; } } } } thrift-0.16.0/lib/netstd/Thrift/Protocol/TProtocol.cs000066400000000000000000000172241420101504100224540ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Text; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; using Thrift.Transport; namespace Thrift.Protocol { // ReSharper disable once InconsistentNaming public abstract class TProtocol : IDisposable { private bool _isDisposed; protected int RecursionDepth; protected TTransport Trans; protected static readonly TStruct AnonymousStruct = new TStruct(string.Empty); protected static readonly TField StopField = new TField() { Type = TType.Stop }; protected TProtocol(TTransport trans) { Trans = trans; RecursionLimit = trans.Configuration.RecursionLimit; RecursionDepth = 0; } public TTransport Transport => Trans; protected int RecursionLimit { get; set; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void IncrementRecursionDepth() { if (RecursionDepth < RecursionLimit) { ++RecursionDepth; } else { throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded"); } } public void DecrementRecursionDepth() { --RecursionDepth; } protected virtual void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { (Trans as IDisposable)?.Dispose(); } } _isDisposed = true; } protected void CheckReadBytesAvailable(TSet set) { Transport.CheckReadBytesAvailable(set.Count * GetMinSerializedSize(set.ElementType)); } protected void CheckReadBytesAvailable(TList list) { Transport.CheckReadBytesAvailable(list.Count * GetMinSerializedSize(list.ElementType)); } protected void CheckReadBytesAvailable(TMap map) { var elmSize = GetMinSerializedSize(map.KeyType) + GetMinSerializedSize(map.ValueType); Transport.CheckReadBytesAvailable(map.Count * elmSize); } // Returns the minimum amount of bytes needed to store the smallest possible instance of TType. public abstract int GetMinSerializedSize(TType type); public abstract Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken = default); public abstract Task WriteMessageEndAsync(CancellationToken cancellationToken = default); public abstract Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken = default); public abstract Task WriteStructEndAsync(CancellationToken cancellationToken = default); public abstract Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken = default); public abstract Task WriteFieldEndAsync(CancellationToken cancellationToken = default); public abstract Task WriteFieldStopAsync(CancellationToken cancellationToken = default); public abstract Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken = default); public abstract Task WriteMapEndAsync(CancellationToken cancellationToken = default); public abstract Task WriteListBeginAsync(TList list, CancellationToken cancellationToken = default); public abstract Task WriteListEndAsync(CancellationToken cancellationToken = default); public abstract Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken = default); public abstract Task WriteSetEndAsync(CancellationToken cancellationToken = default); public abstract Task WriteBoolAsync(bool b, CancellationToken cancellationToken = default); public abstract Task WriteByteAsync(sbyte b, CancellationToken cancellationToken = default); public abstract Task WriteI16Async(short i16, CancellationToken cancellationToken = default); public abstract Task WriteI32Async(int i32, CancellationToken cancellationToken = default); public abstract Task WriteI64Async(long i64, CancellationToken cancellationToken = default); public abstract Task WriteDoubleAsync(double d, CancellationToken cancellationToken = default); public virtual async Task WriteStringAsync(string s, CancellationToken cancellationToken = default) { var bytes = Encoding.UTF8.GetBytes(s); await WriteBinaryAsync(bytes, cancellationToken); } public abstract Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken = default); public abstract ValueTask ReadMessageBeginAsync(CancellationToken cancellationToken = default); public abstract Task ReadMessageEndAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadStructBeginAsync(CancellationToken cancellationToken = default); public abstract Task ReadStructEndAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadFieldBeginAsync(CancellationToken cancellationToken = default); public abstract Task ReadFieldEndAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadMapBeginAsync(CancellationToken cancellationToken = default); public abstract Task ReadMapEndAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadListBeginAsync(CancellationToken cancellationToken = default); public abstract Task ReadListEndAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadSetBeginAsync(CancellationToken cancellationToken = default); public abstract Task ReadSetEndAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadBoolAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadByteAsync(CancellationToken cancellationToken = default); public abstract ValueTask ReadI16Async(CancellationToken cancellationToken = default); public abstract ValueTask ReadI32Async(CancellationToken cancellationToken = default); public abstract ValueTask ReadI64Async(CancellationToken cancellationToken = default); public abstract ValueTask ReadDoubleAsync(CancellationToken cancellationToken = default); public virtual async ValueTask ReadStringAsync(CancellationToken cancellationToken = default) { var buf = await ReadBinaryAsync(cancellationToken); return Encoding.UTF8.GetString(buf, 0, buf.Length); } public abstract ValueTask ReadBinaryAsync(CancellationToken cancellationToken = default); } } thrift-0.16.0/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs000066400000000000000000000233311420101504100243130ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; namespace Thrift.Protocol { // ReSharper disable once InconsistentNaming /// /// TProtocolDecorator forwards all requests to an enclosed TProtocol instance, /// providing a way to author concise concrete decorator subclasses.While it has /// no abstract methods, it is marked abstract as a reminder that by itself, /// it does not modify the behaviour of the enclosed TProtocol. /// public abstract class TProtocolDecorator : TProtocol { private readonly TProtocol _wrappedProtocol; protected TProtocolDecorator(TProtocol protocol) : base(protocol.Transport) { _wrappedProtocol = protocol ?? throw new ArgumentNullException(nameof(protocol)); } public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken) { await _wrappedProtocol.WriteMessageBeginAsync(message, cancellationToken); } public override async Task WriteMessageEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.WriteMessageEndAsync(cancellationToken); } public override async Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken) { await _wrappedProtocol.WriteStructBeginAsync(@struct, cancellationToken); } public override async Task WriteStructEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.WriteStructEndAsync(cancellationToken); } public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken) { await _wrappedProtocol.WriteFieldBeginAsync(field, cancellationToken); } public override async Task WriteFieldEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.WriteFieldEndAsync(cancellationToken); } public override async Task WriteFieldStopAsync(CancellationToken cancellationToken) { await _wrappedProtocol.WriteFieldStopAsync(cancellationToken); } public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken) { await _wrappedProtocol.WriteMapBeginAsync(map, cancellationToken); } public override async Task WriteMapEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.WriteMapEndAsync(cancellationToken); } public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken) { await _wrappedProtocol.WriteListBeginAsync(list, cancellationToken); } public override async Task WriteListEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.WriteListEndAsync(cancellationToken); } public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken) { await _wrappedProtocol.WriteSetBeginAsync(set, cancellationToken); } public override async Task WriteSetEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.WriteSetEndAsync(cancellationToken); } public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken) { await _wrappedProtocol.WriteBoolAsync(b, cancellationToken); } public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken) { await _wrappedProtocol.WriteByteAsync(b, cancellationToken); } public override async Task WriteI16Async(short i16, CancellationToken cancellationToken) { await _wrappedProtocol.WriteI16Async(i16, cancellationToken); } public override async Task WriteI32Async(int i32, CancellationToken cancellationToken) { await _wrappedProtocol.WriteI32Async(i32, cancellationToken); } public override async Task WriteI64Async(long i64, CancellationToken cancellationToken) { await _wrappedProtocol.WriteI64Async(i64, cancellationToken); } public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken) { await _wrappedProtocol.WriteDoubleAsync(d, cancellationToken); } public override async Task WriteStringAsync(string s, CancellationToken cancellationToken) { await _wrappedProtocol.WriteStringAsync(s, cancellationToken); } public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken) { await _wrappedProtocol.WriteBinaryAsync(bytes, cancellationToken); } public override async ValueTask ReadMessageBeginAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken); } public override async Task ReadMessageEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.ReadMessageEndAsync(cancellationToken); } public override async ValueTask ReadStructBeginAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadStructBeginAsync(cancellationToken); } public override async Task ReadStructEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.ReadStructEndAsync(cancellationToken); } public override async ValueTask ReadFieldBeginAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadFieldBeginAsync(cancellationToken); } public override async Task ReadFieldEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.ReadFieldEndAsync(cancellationToken); } public override async ValueTask ReadMapBeginAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadMapBeginAsync(cancellationToken); } public override async Task ReadMapEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.ReadMapEndAsync(cancellationToken); } public override async ValueTask ReadListBeginAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadListBeginAsync(cancellationToken); } public override async Task ReadListEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.ReadListEndAsync(cancellationToken); } public override async ValueTask ReadSetBeginAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadSetBeginAsync(cancellationToken); } public override async Task ReadSetEndAsync(CancellationToken cancellationToken) { await _wrappedProtocol.ReadSetEndAsync(cancellationToken); } public override async ValueTask ReadBoolAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadBoolAsync(cancellationToken); } public override async ValueTask ReadByteAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadByteAsync(cancellationToken); } public override async ValueTask ReadI16Async(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadI16Async(cancellationToken); } public override async ValueTask ReadI32Async(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadI32Async(cancellationToken); } public override async ValueTask ReadI64Async(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadI64Async(cancellationToken); } public override async ValueTask ReadDoubleAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadDoubleAsync(cancellationToken); } public override async ValueTask ReadStringAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadStringAsync(cancellationToken); } public override async ValueTask ReadBinaryAsync(CancellationToken cancellationToken) { return await _wrappedProtocol.ReadBinaryAsync(cancellationToken); } // Returns the minimum amount of bytes needed to store the smallest possible instance of TType. public override int GetMinSerializedSize(TType type) { return _wrappedProtocol.GetMinSerializedSize(type); } } } thrift-0.16.0/lib/netstd/Thrift/Protocol/TProtocolException.cs000066400000000000000000000036311420101504100243300ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // ReSharper disable InconsistentNaming using System; namespace Thrift.Protocol { public class TProtocolException : TException { // do not rename public constants - they used in generated files public const int UNKNOWN = 0; public const int INVALID_DATA = 1; public const int NEGATIVE_SIZE = 2; public const int SIZE_LIMIT = 3; public const int BAD_VERSION = 4; public const int NOT_IMPLEMENTED = 5; public const int DEPTH_LIMIT = 6; protected int Type = UNKNOWN; public TProtocolException() { } public TProtocolException(int type, Exception inner = null) : base(string.Empty, inner) { Type = type; } public TProtocolException(int type, string message, Exception inner = null) : base(message, inner) { Type = type; } public TProtocolException(string message, Exception inner = null) : base(message, inner) { } public int GetExceptionType() { return Type; } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/TProtocolFactory.cs000066400000000000000000000017771420101504100240120ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using Thrift.Transport; namespace Thrift.Protocol { // ReSharper disable once InconsistentNaming public abstract class TProtocolFactory { public abstract TProtocol GetProtocol(TTransport trans); } } thrift-0.16.0/lib/netstd/Thrift/Protocol/ToString.cs000066400000000000000000000047521420101504100223020ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections; using System.Collections.Generic; using System.Text; using Thrift.Protocol; namespace Thrift.Protocol { public static class ToStringExtensions { public static void ToString(this object self, StringBuilder sb, bool first = true) { if (!first) sb.Append(", "); bool first_child = true; if (self is string) // string is IEnumerable { sb.Append('"'); sb.Append(self); sb.Append('"'); } else if (self is IDictionary) { sb.Append("{ "); foreach (DictionaryEntry pair in (self as IDictionary)) { if (first_child) first_child = false; else sb.Append(','); sb.Append("{ "); pair.Key.ToString(sb); sb.Append(", "); pair.Value.ToString(sb); sb.Append('}'); } sb.Append('}'); } else if (self is IEnumerable) { sb.Append("{ "); foreach (var elm in (self as IEnumerable)) { elm.ToString(sb, first_child); first_child = false; } sb.Append('}'); } else if (self is TBase) { sb.Append((self as TBase).ToString()); } else { sb.Append(self != null? self.ToString() : ""); } } } } thrift-0.16.0/lib/netstd/Thrift/Protocol/Utilities/000077500000000000000000000000001420101504100221455ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Protocol/Utilities/TBase64Utils.cs000066400000000000000000000104161420101504100246670ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; namespace Thrift.Protocol.Utilities { // ReSharper disable once InconsistentNaming internal static class TBase64Utils { //TODO: Constants //TODO: Check for args //TODO: Unitests internal const string EncodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; private static readonly int[] DecodeTable = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; internal static void Encode(byte[] src, int srcOff, int len, byte[] dst, int dstOff) { if (src == null) { throw new ArgumentNullException(nameof(src)); } dst[dstOff] = (byte) EncodeTable[(src[srcOff] >> 2) & 0x3F]; if (len == 3) { dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)]; dst[dstOff + 2] = (byte) EncodeTable[((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)]; dst[dstOff + 3] = (byte) EncodeTable[src[srcOff + 2] & 0x3F]; } else if (len == 2) { dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)]; dst[dstOff + 2] = (byte) EncodeTable[(src[srcOff + 1] << 2) & 0x3C]; } else { // len == 1 dst[dstOff + 1] = (byte) EncodeTable[(src[srcOff] << 4) & 0x30]; } } internal static void Decode(byte[] src, int srcOff, int len, byte[] dst, int dstOff) { if (src == null) { throw new ArgumentNullException(nameof(src)); } dst[dstOff] = (byte) ((DecodeTable[src[srcOff] & 0x0FF] << 2) | (DecodeTable[src[srcOff + 1] & 0x0FF] >> 4)); if (len > 2) { dst[dstOff + 1] = (byte) (((DecodeTable[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) | (DecodeTable[src[srcOff + 2] & 0x0FF] >> 2)); if (len > 3) { dst[dstOff + 2] = (byte) (((DecodeTable[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) | DecodeTable[src[srcOff + 3] & 0x0FF]); } } } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs000066400000000000000000000065031420101504100271540ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Protocol.Utilities { // ReSharper disable once InconsistentNaming public static class TJSONProtocolConstants { //TODO Check for performance for reusing ImmutableArray from System.Collections.Immutable (https://blogs.msdn.microsoft.com/dotnet/2013/06/24/please-welcome-immutablearrayt/) // can be possible to get better performance and also better GC public static readonly byte[] Comma = {(byte) ','}; public static readonly byte[] Colon = {(byte) ':'}; public static readonly byte[] LeftBrace = {(byte) '{'}; public static readonly byte[] RightBrace = {(byte) '}'}; public static readonly byte[] LeftBracket = {(byte) '['}; public static readonly byte[] RightBracket = {(byte) ']'}; public static readonly byte[] Quote = {(byte) '"'}; public static readonly byte[] Backslash = {(byte) '\\'}; public static readonly byte[] JsonCharTable = { 0, 0, 0, 0, 0, 0, 0, 0, (byte) 'b', (byte) 't', (byte) 'n', 0, (byte) 'f', (byte) 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, (byte) '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; public static readonly char[] EscapeChars = "\"\\/bfnrt".ToCharArray(); public static readonly byte[] EscapeCharValues = {(byte) '"', (byte) '\\', (byte) '/', (byte) '\b', (byte) '\f', (byte) '\n', (byte) '\r', (byte) '\t'}; public static readonly byte[] EscSequences = {(byte) '\\', (byte) 'u', (byte) '0', (byte) '0'}; public static class TypeNames { public static readonly byte[] NameBool = { (byte)'t', (byte)'f' }; public static readonly byte[] NameByte = { (byte)'i', (byte)'8' }; public static readonly byte[] NameI16 = { (byte)'i', (byte)'1', (byte)'6' }; public static readonly byte[] NameI32 = { (byte)'i', (byte)'3', (byte)'2' }; public static readonly byte[] NameI64 = { (byte)'i', (byte)'6', (byte)'4' }; public static readonly byte[] NameDouble = { (byte)'d', (byte)'b', (byte)'l' }; public static readonly byte[] NameStruct = { (byte)'r', (byte)'e', (byte)'c' }; public static readonly byte[] NameString = { (byte)'s', (byte)'t', (byte)'r' }; public static readonly byte[] NameMap = { (byte)'m', (byte)'a', (byte)'p' }; public static readonly byte[] NameList = { (byte)'l', (byte)'s', (byte)'t' }; public static readonly byte[] NameSet = { (byte)'s', (byte)'e', (byte)'t' }; } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs000066400000000000000000000142351420101504100264200ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using Thrift.Protocol.Entities; namespace Thrift.Protocol.Utilities { // ReSharper disable once InconsistentNaming public static class TJSONProtocolHelper { public static byte[] GetTypeNameForTypeId(TType typeId) { switch (typeId) { case TType.Bool: return TJSONProtocolConstants.TypeNames.NameBool; case TType.Byte: return TJSONProtocolConstants.TypeNames.NameByte; case TType.I16: return TJSONProtocolConstants.TypeNames.NameI16; case TType.I32: return TJSONProtocolConstants.TypeNames.NameI32; case TType.I64: return TJSONProtocolConstants.TypeNames.NameI64; case TType.Double: return TJSONProtocolConstants.TypeNames.NameDouble; case TType.String: return TJSONProtocolConstants.TypeNames.NameString; case TType.Struct: return TJSONProtocolConstants.TypeNames.NameStruct; case TType.Map: return TJSONProtocolConstants.TypeNames.NameMap; case TType.Set: return TJSONProtocolConstants.TypeNames.NameSet; case TType.List: return TJSONProtocolConstants.TypeNames.NameList; default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType"); } } public static TType GetTypeIdForTypeName(byte[] name) { var result = TType.Stop; if (name.Length > 1) { switch (name[0]) { case (byte) 'd': result = TType.Double; break; case (byte) 'i': switch (name[1]) { case (byte) '8': result = TType.Byte; break; case (byte) '1': result = TType.I16; break; case (byte) '3': result = TType.I32; break; case (byte) '6': result = TType.I64; break; } break; case (byte) 'l': result = TType.List; break; case (byte) 'm': result = TType.Map; break; case (byte) 'r': result = TType.Struct; break; case (byte) 's': if (name[1] == (byte) 't') { result = TType.String; } else if (name[1] == (byte) 'e') { result = TType.Set; } break; case (byte) 't': result = TType.Bool; break; } } if (result == TType.Stop) { throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType"); } return result; } /// /// Return true if the given byte could be a valid part of a JSON number. /// public static bool IsJsonNumeric(byte b) { switch (b) { case (byte)'+': case (byte)'-': case (byte)'.': case (byte)'0': case (byte)'1': case (byte)'2': case (byte)'3': case (byte)'4': case (byte)'5': case (byte)'6': case (byte)'7': case (byte)'8': case (byte)'9': case (byte)'E': case (byte)'e': return true; default: return false; } } /// /// Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its /// corresponding hex value /// public static byte ToHexVal(byte ch) { if (ch >= '0' && ch <= '9') { return (byte)((char)ch - '0'); } if (ch >= 'a' && ch <= 'f') { ch += 10; return (byte)((char)ch - 'a'); } throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected hex character"); } /// /// Convert a byte containing a hex value to its corresponding hex character /// public static byte ToHexChar(byte val) { val &= 0x0F; if (val < 10) { return (byte)((char)val + '0'); } val -= 10; return (byte)((char)val + 'a'); } } }thrift-0.16.0/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs000066400000000000000000000113261420101504100252620ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Threading; using System.Threading.Tasks; using Thrift.Protocol.Entities; namespace Thrift.Protocol.Utilities { // ReSharper disable once InconsistentNaming public static class TProtocolUtil { public static async Task SkipAsync(TProtocol protocol, TType type, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); protocol.IncrementRecursionDepth(); try { switch (type) { case TType.Bool: await protocol.ReadBoolAsync(cancellationToken); break; case TType.Byte: await protocol.ReadByteAsync(cancellationToken); break; case TType.I16: await protocol.ReadI16Async(cancellationToken); break; case TType.I32: await protocol.ReadI32Async(cancellationToken); break; case TType.I64: await protocol.ReadI64Async(cancellationToken); break; case TType.Double: await protocol.ReadDoubleAsync(cancellationToken); break; case TType.String: // Don't try to decode the string, just skip it. await protocol.ReadBinaryAsync(cancellationToken); break; case TType.Struct: await protocol.ReadStructBeginAsync(cancellationToken); while (true) { var field = await protocol.ReadFieldBeginAsync(cancellationToken); if (field.Type == TType.Stop) { break; } await SkipAsync(protocol, field.Type, cancellationToken); await protocol.ReadFieldEndAsync(cancellationToken); } await protocol.ReadStructEndAsync(cancellationToken); break; case TType.Map: var map = await protocol.ReadMapBeginAsync(cancellationToken); for (var i = 0; i < map.Count; i++) { await SkipAsync(protocol, map.KeyType, cancellationToken); await SkipAsync(protocol, map.ValueType, cancellationToken); } await protocol.ReadMapEndAsync(cancellationToken); break; case TType.Set: var set = await protocol.ReadSetBeginAsync(cancellationToken); for (var i = 0; i < set.Count; i++) { await SkipAsync(protocol, set.ElementType, cancellationToken); } await protocol.ReadSetEndAsync(cancellationToken); break; case TType.List: var list = await protocol.ReadListBeginAsync(cancellationToken); for (var i = 0; i < list.Count; i++) { await SkipAsync(protocol, list.ElementType, cancellationToken); } await protocol.ReadListEndAsync(cancellationToken); break; default: throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d")); } } finally { protocol.DecrementRecursionDepth(); } } } } thrift-0.16.0/lib/netstd/Thrift/Server/000077500000000000000000000000001420101504100176375ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Server/TServer.cs000066400000000000000000000063741420101504100215720ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Thrift.Protocol; using Thrift.Transport; using Thrift.Processor; namespace Thrift.Server { // ReSharper disable once InconsistentNaming public abstract class TServer { protected readonly ILogger Logger; protected TProtocolFactory InputProtocolFactory; protected TTransportFactory InputTransportFactory; protected ITProcessorFactory ProcessorFactory; protected TProtocolFactory OutputProtocolFactory; protected TTransportFactory OutputTransportFactory; protected ITServerEventHandler ServerEventHandler; protected TServerTransport ServerTransport; protected TServer(ITProcessorFactory processorFactory, TServerTransport serverTransport, TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory, ILogger logger = null) { ProcessorFactory = processorFactory ?? throw new ArgumentNullException(nameof(processorFactory)); ServerTransport = serverTransport; InputTransportFactory = inputTransportFactory ?? new TTransportFactory(); OutputTransportFactory = outputTransportFactory ?? new TTransportFactory(); InputProtocolFactory = inputProtocolFactory ?? throw new ArgumentNullException(nameof(inputProtocolFactory)); OutputProtocolFactory = outputProtocolFactory ?? throw new ArgumentNullException(nameof(outputProtocolFactory)); Logger = logger; // null is absolutely legal } public void SetEventHandler(ITServerEventHandler seh) { ServerEventHandler = seh; } public ITServerEventHandler GetEventHandler() { return ServerEventHandler; } // Log delegation? deprecated, use ILogger protected void LogError( string msg) { if (Logger != null) Logger.LogError("{Msg}",msg); // NOTE: Log message template, not string interpolation! } public abstract void Stop(); public virtual void Start() { // do nothing } public virtual Task ServeAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } } } thrift-0.16.0/lib/netstd/Thrift/Server/TServerEventHandler.cs000066400000000000000000000045671420101504100240740ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Threading; using System.Threading.Tasks; using Thrift.Protocol; using Thrift.Transport; namespace Thrift.Server { //TODO: replacement by event? /// /// Interface implemented by server users to handle events from the server /// /// Replaced by ITServerEventHandler // ReSharper disable once InconsistentNaming #pragma warning disable IDE1006 public interface TServerEventHandler : ITServerEventHandler { } #pragma warning restore IDE1006 /// /// Interface implemented by server users to handle events from the server /// public interface ITServerEventHandler { /// /// Called before the server begins */ /// Task PreServeAsync(CancellationToken cancellationToken); /// /// Called when a new client has connected and is about to being processing */ /// Task CreateContextAsync(TProtocol input, TProtocol output, CancellationToken cancellationToken); /// /// Called when a client has finished request-handling to delete server context */ /// Task DeleteContextAsync(object serverContext, TProtocol input, TProtocol output, CancellationToken cancellationToken); /// /// Called when a client is about to call the processor */ /// Task ProcessContextAsync(object serverContext, TTransport transport, CancellationToken cancellationToken); } } thrift-0.16.0/lib/netstd/Thrift/Server/TSimpleAsyncServer.cs000066400000000000000000000211441420101504100237320ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Threading; using Thrift.Protocol; using Thrift.Transport; using Thrift.Processor; using System.Threading.Tasks; using Microsoft.Extensions.Logging; namespace Thrift.Server { // ReSharper disable once InconsistentNaming public class TSimpleAsyncServer : TServer { private volatile bool stop = false; private CancellationToken ServerCancellationToken; public TSimpleAsyncServer(ITProcessorFactory itProcessorFactory, TServerTransport serverTransport, TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory, ILogger logger) : base(itProcessorFactory, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory, logger) { } public TSimpleAsyncServer(ITProcessorFactory itProcessorFactory, TServerTransport serverTransport, TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory, ILoggerFactory loggerFactory) : this(itProcessorFactory, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory, loggerFactory.CreateLogger()) { } public TSimpleAsyncServer(ITAsyncProcessor processor, TServerTransport serverTransport, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory, ILoggerFactory loggerFactory) : this(new TSingletonProcessorFactory(processor), serverTransport, null, // defaults to TTransportFactory() null, // defaults to TTransportFactory() inputProtocolFactory, outputProtocolFactory, loggerFactory.CreateLogger(nameof(TSimpleAsyncServer))) { } public override async Task ServeAsync(CancellationToken cancellationToken) { ServerCancellationToken = cancellationToken; try { try { ServerTransport.Listen(); } catch (TTransportException ttx) { LogError("Error, could not listen on ServerTransport: " + ttx); return; } //Fire the preServe server event when server is up but before any client connections if (ServerEventHandler != null) await ServerEventHandler.PreServeAsync(cancellationToken); while (!(stop || ServerCancellationToken.IsCancellationRequested)) { try { using (TTransport client = await ServerTransport.AcceptAsync(cancellationToken)) { await ExecuteAsync(client); } } catch (TaskCanceledException) { stop = true; } catch (TTransportException ttx) { if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted) { LogError(ttx.ToString()); } } } if (stop) { try { ServerTransport.Close(); } catch (TTransportException ttx) { LogError("TServerTransport failed on close: " + ttx.Message); } stop = false; } } finally { ServerCancellationToken = default; } } /// /// Loops on processing a client forever /// client will be a TTransport instance /// /// private async Task ExecuteAsync(TTransport client) { var cancellationToken = ServerCancellationToken; var processor = ProcessorFactory.GetAsyncProcessor(client, this); TTransport inputTransport = null; TTransport outputTransport = null; TProtocol inputProtocol = null; TProtocol outputProtocol = null; object connectionContext = null; try { try { inputTransport = InputTransportFactory.GetTransport(client); outputTransport = OutputTransportFactory.GetTransport(client); inputProtocol = InputProtocolFactory.GetProtocol(inputTransport); outputProtocol = OutputProtocolFactory.GetProtocol(outputTransport); //Recover event handler (if any) and fire createContext server event when a client connects if (ServerEventHandler != null) connectionContext = await ServerEventHandler.CreateContextAsync(inputProtocol, outputProtocol, cancellationToken); //Process client requests until client disconnects while (!(stop || cancellationToken.IsCancellationRequested)) { if (!await inputTransport.PeekAsync(cancellationToken)) break; //Fire processContext server event //N.B. This is the pattern implemented in C++ and the event fires provisionally. //That is to say it may be many minutes between the event firing and the client request //actually arriving or the client may hang up without ever makeing a request. if (ServerEventHandler != null) await ServerEventHandler.ProcessContextAsync(connectionContext, inputTransport, cancellationToken); //Process client request (blocks until transport is readable) if (!await processor.ProcessAsync(inputProtocol, outputProtocol, cancellationToken)) break; } } catch (TTransportException) { //Usually a client disconnect, expected } catch (Exception x) { //Unexpected LogError("Error: " + x); } //Fire deleteContext server event after client disconnects if (ServerEventHandler != null) await ServerEventHandler.DeleteContextAsync(connectionContext, inputProtocol, outputProtocol, cancellationToken); } finally { //Close transports inputTransport?.Close(); outputTransport?.Close(); // disposable stuff should be disposed inputProtocol?.Dispose(); outputProtocol?.Dispose(); inputTransport?.Dispose(); outputTransport?.Dispose(); } } public override void Stop() { stop = true; ServerTransport?.Close(); } } } thrift-0.16.0/lib/netstd/Thrift/Server/TThreadPoolAsyncServer.cs000066400000000000000000000301171420101504100245420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ using System; using System.Threading; using Thrift.Protocol; using Thrift.Transport; using Thrift.Processor; using System.Threading.Tasks; using Microsoft.Extensions.Logging; namespace Thrift.Server { /// /// Server that uses C# built-in ThreadPool to spawn threads when handling requests. /// public class TThreadPoolAsyncServer : TServer { private const int DEFAULT_MIN_THREADS = -1; // use .NET ThreadPool defaults private const int DEFAULT_MAX_THREADS = -1; // use .NET ThreadPool defaults private volatile bool stop = false; private CancellationToken ServerCancellationToken; public struct Configuration { public int MinWorkerThreads; public int MaxWorkerThreads; public int MinIOThreads; public int MaxIOThreads; public Configuration(int min = DEFAULT_MIN_THREADS, int max = DEFAULT_MAX_THREADS) { MinWorkerThreads = min; MaxWorkerThreads = max; MinIOThreads = min; MaxIOThreads = max; } public Configuration(int minWork, int maxWork, int minIO, int maxIO) { MinWorkerThreads = minWork; MaxWorkerThreads = maxWork; MinIOThreads = minIO; MaxIOThreads = maxIO; } } public TThreadPoolAsyncServer(ITAsyncProcessor processor, TServerTransport serverTransport, ILogger logger = null) : this(new TSingletonProcessorFactory(processor), serverTransport, null, null, // defaults to TTransportFactory() new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), new Configuration(), logger) { } public TThreadPoolAsyncServer(ITAsyncProcessor processor, TServerTransport serverTransport, TTransportFactory transportFactory, TProtocolFactory protocolFactory) : this(new TSingletonProcessorFactory(processor), serverTransport, transportFactory, transportFactory, protocolFactory, protocolFactory, new Configuration()) { } public TThreadPoolAsyncServer(ITProcessorFactory processorFactory, TServerTransport serverTransport, TTransportFactory transportFactory, TProtocolFactory protocolFactory) : this(processorFactory, serverTransport, transportFactory, transportFactory, protocolFactory, protocolFactory, new Configuration()) { } public TThreadPoolAsyncServer(ITProcessorFactory processorFactory, TServerTransport serverTransport, TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory, int minThreadPoolThreads, int maxThreadPoolThreads, ILogger logger = null) : this(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory, new Configuration(minThreadPoolThreads, maxThreadPoolThreads), logger) { } public TThreadPoolAsyncServer(ITProcessorFactory processorFactory, TServerTransport serverTransport, TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory, Configuration threadConfig, ILogger logger = null) : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory, logger) { lock (typeof(TThreadPoolAsyncServer)) { if ((threadConfig.MaxWorkerThreads > 0) || (threadConfig.MaxIOThreads > 0)) { ThreadPool.GetMaxThreads(out int work, out int comm); if (threadConfig.MaxWorkerThreads > 0) work = threadConfig.MaxWorkerThreads; if (threadConfig.MaxIOThreads > 0) comm = threadConfig.MaxIOThreads; if (!ThreadPool.SetMaxThreads(work, comm)) throw new Exception("Error: could not SetMaxThreads in ThreadPool"); } if ((threadConfig.MinWorkerThreads > 0) || (threadConfig.MinIOThreads > 0)) { ThreadPool.GetMinThreads(out int work, out int comm); if (threadConfig.MinWorkerThreads > 0) work = threadConfig.MinWorkerThreads; if (threadConfig.MinIOThreads > 0) comm = threadConfig.MinIOThreads; if (!ThreadPool.SetMinThreads(work, comm)) throw new Exception("Error: could not SetMinThreads in ThreadPool"); } } } /// /// Use new ThreadPool thread for each new client connection. /// public override async Task ServeAsync(CancellationToken cancellationToken) { ServerCancellationToken = cancellationToken; try { try { ServerTransport.Listen(); } catch (TTransportException ttx) { LogError("Error, could not listen on ServerTransport: " + ttx); return; } //Fire the preServe server event when server is up but before any client connections if (ServerEventHandler != null) await ServerEventHandler.PreServeAsync(cancellationToken); while (!(stop || ServerCancellationToken.IsCancellationRequested)) { try { TTransport client = await ServerTransport.AcceptAsync(cancellationToken); _ = Task.Run(async () => await ExecuteAsync(client), cancellationToken); // intentionally ignoring retval } catch (TaskCanceledException) { stop = true; } catch (TTransportException ttx) { if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted) { LogError(ttx.ToString()); } } } if (stop) { try { ServerTransport.Close(); } catch (TTransportException ttx) { LogError("TServerTransport failed on close: " + ttx.Message); } stop = false; } } finally { ServerCancellationToken = default; } } /// /// Loops on processing a client forever /// client will be a TTransport instance /// /// private async Task ExecuteAsync(TTransport client) { var cancellationToken = ServerCancellationToken; using (client) { ITAsyncProcessor processor = ProcessorFactory.GetAsyncProcessor(client, this); TTransport inputTransport = null; TTransport outputTransport = null; TProtocol inputProtocol = null; TProtocol outputProtocol = null; object connectionContext = null; try { try { inputTransport = InputTransportFactory.GetTransport(client); outputTransport = OutputTransportFactory.GetTransport(client); inputProtocol = InputProtocolFactory.GetProtocol(inputTransport); outputProtocol = OutputProtocolFactory.GetProtocol(outputTransport); //Recover event handler (if any) and fire createContext server event when a client connects if (ServerEventHandler != null) connectionContext = await ServerEventHandler.CreateContextAsync(inputProtocol, outputProtocol, cancellationToken); //Process client requests until client disconnects while (!(stop || cancellationToken.IsCancellationRequested)) { if (!await inputTransport.PeekAsync(cancellationToken)) break; //Fire processContext server event //N.B. This is the pattern implemented in C++ and the event fires provisionally. //That is to say it may be many minutes between the event firing and the client request //actually arriving or the client may hang up without ever makeing a request. if (ServerEventHandler != null) await ServerEventHandler.ProcessContextAsync(connectionContext, inputTransport, cancellationToken); //Process client request (blocks until transport is readable) if (!await processor.ProcessAsync(inputProtocol, outputProtocol, cancellationToken)) break; } } catch (TTransportException) { //Usually a client disconnect, expected } catch (Exception x) { //Unexpected LogError("Error: " + x); } //Fire deleteContext server event after client disconnects if (ServerEventHandler != null) await ServerEventHandler.DeleteContextAsync(connectionContext, inputProtocol, outputProtocol, cancellationToken); } finally { //Close transports inputTransport?.Close(); outputTransport?.Close(); // disposable stuff should be disposed inputProtocol?.Dispose(); outputProtocol?.Dispose(); inputTransport?.Dispose(); outputTransport?.Dispose(); } } } public override void Stop() { stop = true; ServerTransport?.Close(); } } } thrift-0.16.0/lib/netstd/Thrift/TApplicationException.cs000066400000000000000000000125071420101504100231730ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Threading; using System.Threading.Tasks; using Thrift.Protocol; using Thrift.Protocol.Entities; using Thrift.Protocol.Utilities; namespace Thrift { // ReSharper disable once InconsistentNaming public class TApplicationException : TException { public enum ExceptionType { Unknown, UnknownMethod, InvalidMessageType, WrongMethodName, BadSequenceId, MissingResult, InternalError, ProtocolError, InvalidTransform, InvalidProtocol, UnsupportedClientType } private const int MessageTypeFieldId = 1; private const int ExTypeFieldId = 2; public ExceptionType Type { get; private set; } public TApplicationException() { } public TApplicationException(ExceptionType type) { Type = type; } public TApplicationException(ExceptionType type, string message) : base(message, null) // TApplicationException is serializable, but we never serialize InnerException { Type = type; } public static async ValueTask ReadAsync(TProtocol inputProtocol, CancellationToken cancellationToken) { string message = null; var type = ExceptionType.Unknown; await inputProtocol.ReadStructBeginAsync(cancellationToken); while (true) { var field = await inputProtocol.ReadFieldBeginAsync(cancellationToken); if (field.Type == TType.Stop) { break; } switch (field.ID) { case MessageTypeFieldId: if (field.Type == TType.String) { message = await inputProtocol.ReadStringAsync(cancellationToken); } else { await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken); } break; case ExTypeFieldId: if (field.Type == TType.I32) { type = (ExceptionType) await inputProtocol.ReadI32Async(cancellationToken); } else { await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken); } break; default: await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken); break; } await inputProtocol.ReadFieldEndAsync(cancellationToken); } await inputProtocol.ReadStructEndAsync(cancellationToken); return new TApplicationException(type, message); } public async Task WriteAsync(TProtocol outputProtocol, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); const string messageTypeFieldName = "message"; const string exTypeFieldName = "exType"; const string structApplicationExceptionName = "TApplicationException"; var struc = new TStruct(structApplicationExceptionName); var field = new TField(); await outputProtocol.WriteStructBeginAsync(struc, cancellationToken); if (!string.IsNullOrEmpty(Message)) { field.Name = messageTypeFieldName; field.Type = TType.String; field.ID = MessageTypeFieldId; await outputProtocol.WriteFieldBeginAsync(field, cancellationToken); await outputProtocol.WriteStringAsync(Message, cancellationToken); await outputProtocol.WriteFieldEndAsync(cancellationToken); } field.Name = exTypeFieldName; field.Type = TType.I32; field.ID = ExTypeFieldId; await outputProtocol.WriteFieldBeginAsync(field, cancellationToken); await outputProtocol.WriteI32Async((int) Type, cancellationToken); await outputProtocol.WriteFieldEndAsync(cancellationToken); await outputProtocol.WriteFieldStopAsync(cancellationToken); await outputProtocol.WriteStructEndAsync(cancellationToken); } } } thrift-0.16.0/lib/netstd/Thrift/TBaseClient.cs000066400000000000000000000055331420101504100210630ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Threading; using System.Threading.Tasks; using Thrift.Protocol; namespace Thrift { // ReSharper disable once InconsistentNaming /// /// TBaseClient. /// Base client for generated clients. /// Do not change this class without checking generated code (namings, etc.) /// public abstract class TBaseClient { private readonly TProtocol _inputProtocol; private readonly TProtocol _outputProtocol; private bool _isDisposed; private int _seqId; public readonly Guid ClientId = Guid.NewGuid(); protected TBaseClient(TProtocol inputProtocol, TProtocol outputProtocol) { _inputProtocol = inputProtocol ?? throw new ArgumentNullException(nameof(inputProtocol)); _outputProtocol = outputProtocol ?? throw new ArgumentNullException(nameof(outputProtocol)); } public TProtocol InputProtocol => _inputProtocol; public TProtocol OutputProtocol => _outputProtocol; public int SeqId { get { return ++_seqId; } } public virtual async Task OpenTransportAsync() { await OpenTransportAsync(CancellationToken.None); } public virtual async Task OpenTransportAsync(CancellationToken cancellationToken) { if (!_inputProtocol.Transport.IsOpen) { await _inputProtocol.Transport.OpenAsync(cancellationToken); } if (!_outputProtocol.Transport.IsOpen) { await _outputProtocol.Transport.OpenAsync(cancellationToken); } } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { _inputProtocol?.Dispose(); _outputProtocol?.Dispose(); } } _isDisposed = true; } } } thrift-0.16.0/lib/netstd/Thrift/TConfiguration.cs000066400000000000000000000026731420101504100216630ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Text; namespace Thrift { public class TConfiguration { public const int DEFAULT_MAX_MESSAGE_SIZE = 100 * 1024 * 1024; public const int DEFAULT_MAX_FRAME_SIZE = 16384000; // this value is used consistently across all Thrift libraries public const int DEFAULT_RECURSION_DEPTH = 64; public int MaxMessageSize { get; set; } = DEFAULT_MAX_MESSAGE_SIZE; public int MaxFrameSize { get; set; } = DEFAULT_MAX_FRAME_SIZE; public int RecursionLimit { get; set; } = DEFAULT_RECURSION_DEPTH; // TODO(JensG): add connection and i/o timeouts } } thrift-0.16.0/lib/netstd/Thrift/TException.cs000066400000000000000000000021121420101504100207760ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; namespace Thrift { // ReSharper disable once InconsistentNaming public class TException : Exception { public TException() { } public TException(string message, Exception inner) : base(message, inner) { } } }thrift-0.16.0/lib/netstd/Thrift/Thrift.csproj000066400000000000000000000103561420101504100210600ustar00rootroot00000000000000 netstandard2.1;netstandard2.0;net5.0;net6.0 Thrift ApacheThrift true true false false false false false false false false true true true thrift.snk false Apache Thrift 0.16.0 0.16.0.0 false http://thrift.apache.org/ Apache Thrift Developers false Apache-2.0 C# .NET Core bindings for the Apache Thrift RPC system Apache Thrift RPC https://github.com/apache/thrift/blob/0.16.0/CHANGES.md Copyright 2022 The Apache Software Foundation $(IntermediateOutputPath)$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension) thrift-0.16.0/lib/netstd/Thrift/Transport/000077500000000000000000000000001420101504100203655ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Transport/Client/000077500000000000000000000000001420101504100216035ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Transport/Client/THttpTransport.cs000066400000000000000000000262701420101504100251210ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport.Client { // ReSharper disable once InconsistentNaming public class THttpTransport : TEndpointTransport { private readonly X509Certificate[] _certificates; private readonly Uri _uri; private int _connectTimeout = 30000; // Timeouts in milliseconds private HttpClient _httpClient; private Stream _inputStream; private MemoryStream _outputStream = new MemoryStream(); private bool _isDisposed; public THttpTransport(Uri uri, TConfiguration config, IDictionary customRequestHeaders = null, string userAgent = null) : this(uri, config, Enumerable.Empty(), customRequestHeaders, userAgent) { } public THttpTransport(Uri uri, TConfiguration config, IEnumerable certificates, IDictionary customRequestHeaders, string userAgent = null) : base(config) { _uri = uri; _certificates = (certificates ?? Enumerable.Empty()).ToArray(); if (!string.IsNullOrEmpty(userAgent)) UserAgent = userAgent; // due to current bug with performance of Dispose in netcore https://github.com/dotnet/corefx/issues/8809 // this can be switched to default way (create client->use->dispose per flush) later _httpClient = CreateClient(customRequestHeaders); ConfigureClient(_httpClient); } /// /// Constructor that takes a HttpClient instance to support using IHttpClientFactory. /// /// As the HttpMessageHandler of the client must be configured at the time of creation, it /// is assumed that the consumer has already added any certificates and configured decompression methods. The /// consumer can use the CreateHttpClientHandler method to get a handler with these set. /// Client configured with the desired message handler, user agent, and URI if not /// specified in the uri parameter. A default user agent will be used if not set. /// Thrift configuration object /// Optional URI to use for requests, if not specified the base address of httpClient /// is used. public THttpTransport(HttpClient httpClient, TConfiguration config, Uri uri = null) : base(config) { _httpClient = httpClient; _uri = uri ?? httpClient.BaseAddress; httpClient.BaseAddress = _uri; var userAgent = _httpClient.DefaultRequestHeaders.UserAgent.ToString(); if (!string.IsNullOrEmpty(userAgent)) UserAgent = userAgent; ConfigureClient(_httpClient); } // According to RFC 2616 section 3.8, the "User-Agent" header may not carry a version number public readonly string UserAgent = "Thrift netstd THttpClient"; public int ConnectTimeout { set { _connectTimeout = value; if(_httpClient != null) _httpClient.Timeout = TimeSpan.FromMilliseconds(_connectTimeout); } get { if (_httpClient == null) return _connectTimeout; return (int)_httpClient.Timeout.TotalMilliseconds; } } public override bool IsOpen => true; public HttpRequestHeaders RequestHeaders => _httpClient.DefaultRequestHeaders; public MediaTypeHeaderValue ContentType { get; set; } public override Task OpenAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override void Close() { if (_inputStream != null) { _inputStream.Dispose(); _inputStream = null; } if (_outputStream != null) { _outputStream.Dispose(); _outputStream = null; } if (_httpClient != null) { _httpClient.Dispose(); _httpClient = null; } } public override async ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_inputStream == null) throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No request has been sent"); CheckReadBytesAvailable(length); try { #if NETSTANDARD2_0 var ret = await _inputStream.ReadAsync(buffer, offset, length, cancellationToken); #else var ret = await _inputStream.ReadAsync(new Memory(buffer, offset, length), cancellationToken); #endif if (ret == -1) { throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "No more data available"); } CountConsumedMessageBytes(ret); return ret; } catch (IOException iox) { throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString()); } } public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); #if NETSTANDARD2_0 await _outputStream.WriteAsync(buffer, offset, length, cancellationToken); #else await _outputStream.WriteAsync(buffer.AsMemory(offset, length), cancellationToken); #endif } /// /// Get a client handler configured with recommended properties to use with the HttpClient constructor /// and an IHttpClientFactory. /// /// An optional array of client certificates to associate with the handler. /// /// A client handler with deflate and gZip compression-decompression algorithms and any client /// certificates passed in via certificates. /// public virtual HttpClientHandler CreateHttpClientHandler(X509Certificate[] certificates = null) { var handler = new HttpClientHandler(); if (certificates != null) handler.ClientCertificates.AddRange(certificates); handler.AutomaticDecompression = System.Net.DecompressionMethods.Deflate | System.Net.DecompressionMethods.GZip; return handler; } private HttpClient CreateClient(IDictionary customRequestHeaders) { var handler = CreateHttpClientHandler(_certificates); var httpClient = new HttpClient(handler); if (customRequestHeaders != null) { foreach (var item in customRequestHeaders) { httpClient.DefaultRequestHeaders.Add(item.Key, item.Value); } } return httpClient; } private void ConfigureClient(HttpClient httpClient) { if (_connectTimeout > 0) { httpClient.Timeout = TimeSpan.FromMilliseconds(_connectTimeout); } httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-thrift")); // Clear any user agent values to avoid drift with the field value httpClient.DefaultRequestHeaders.UserAgent.Clear(); httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd(UserAgent); httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate")); httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip")); } public override async Task FlushAsync(CancellationToken cancellationToken) { try { _outputStream.Seek(0, SeekOrigin.Begin); using (var contentStream = new StreamContent(_outputStream)) { contentStream.Headers.ContentType = ContentType ?? new MediaTypeHeaderValue(@"application/x-thrift"); var response = (await _httpClient.PostAsync(_uri, contentStream, cancellationToken)).EnsureSuccessStatusCode(); _inputStream?.Dispose(); #if NETSTANDARD2_0 || NETSTANDARD2_1 _inputStream = await response.Content.ReadAsStreamAsync(); #else _inputStream = await response.Content.ReadAsStreamAsync(cancellationToken); #endif if (_inputStream.CanSeek) { _inputStream.Seek(0, SeekOrigin.Begin); } } } catch (IOException iox) { throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString()); } catch (HttpRequestException wx) { throw new TTransportException(TTransportException.ExceptionType.Unknown, "Couldn't connect to server: " + wx); } catch (Exception ex) { throw new TTransportException(TTransportException.ExceptionType.Unknown, ex.Message); } finally { _outputStream = new MemoryStream(); ResetConsumedMessageSize(); } } // IDisposable protected override void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { _inputStream?.Dispose(); _outputStream?.Dispose(); _httpClient?.Dispose(); } } _isDisposed = true; } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Client/TMemoryBufferTransport.cs000066400000000000000000000126671420101504100266110ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Diagnostics; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport.Client { // ReSharper disable once InconsistentNaming public class TMemoryBufferTransport : TEndpointTransport { private bool IsDisposed; private byte[] Bytes; private int _bytesUsed; public TMemoryBufferTransport(TConfiguration config, int initialCapacity = 2048) : base(config) { Bytes = new byte[initialCapacity]; } public TMemoryBufferTransport(byte[] buf, TConfiguration config) :base(config) { Bytes = (byte[])buf.Clone(); _bytesUsed = Bytes.Length; UpdateKnownMessageSize(_bytesUsed); } public int Position { get; set; } public int Capacity { get { Debug.Assert(_bytesUsed <= Bytes.Length); return Bytes.Length; } set { Array.Resize(ref Bytes, value); _bytesUsed = value; } } public int Length { get { Debug.Assert(_bytesUsed <= Bytes.Length); return _bytesUsed; } set { if ((Bytes.Length < value) || (Bytes.Length > (10 * value))) Array.Resize(ref Bytes, Math.Max(2048, (int)(value * 1.25))); _bytesUsed = value; } } public void SetLength(int value) { Length = value; Position = Math.Min(Position, value); } public override bool IsOpen => true; public override Task OpenAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override void Close() { /* do nothing */ } public void Seek(int delta, SeekOrigin origin) { int newPos; switch (origin) { case SeekOrigin.Begin: newPos = delta; break; case SeekOrigin.Current: newPos = Position + delta; break; case SeekOrigin.End: newPos = _bytesUsed + delta; break; default: throw new ArgumentException("Unrecognized value",nameof(origin)); } if ((0 > newPos) || (newPos > _bytesUsed)) throw new ArgumentException("Cannot seek outside of the valid range",nameof(origin)); Position = newPos; ResetConsumedMessageSize(); CountConsumedMessageBytes(Position); } public override ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { var count = Math.Min(Length - Position, length); Buffer.BlockCopy(Bytes, Position, buffer, offset, count); Position += count; CountConsumedMessageBytes(count); return new ValueTask(count); } public override Task WriteAsync(byte[] buffer, CancellationToken cancellationToken) { return WriteAsync(buffer, 0, buffer.Length, cancellationToken); } public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { var free = Length - Position; Length = Length + count - free; Buffer.BlockCopy(buffer, offset, Bytes, Position, count); Position += count; return Task.CompletedTask; } public override Task FlushAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ResetConsumedMessageSize(); return Task.CompletedTask; } public byte[] GetBuffer() { var retval = new byte[Length]; Buffer.BlockCopy(Bytes, 0, retval, 0, Length); return retval; } internal bool TryGetBuffer(out ArraySegment bufSegment) { bufSegment = new ArraySegment(Bytes, 0, _bytesUsed); return true; } // IDisposable protected override void Dispose(bool disposing) { if (!IsDisposed) { if (disposing) { // nothing to do } } IsDisposed = true; } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs000066400000000000000000000112141420101504100260340ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.IO.Pipes; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport.Client { // ReSharper disable once InconsistentNaming public class TNamedPipeTransport : TEndpointTransport { private NamedPipeClientStream PipeStream; private readonly int ConnectTimeout; private const int DEFAULT_CONNECT_TIMEOUT = 60 * 1000; // Timeout.Infinite is not a good default public TNamedPipeTransport(string pipe, TConfiguration config, int timeout = DEFAULT_CONNECT_TIMEOUT) : this(".", pipe, config, timeout) { } public TNamedPipeTransport(string server, string pipe, TConfiguration config, int timeout = DEFAULT_CONNECT_TIMEOUT) : base(config) { var serverName = string.IsNullOrWhiteSpace(server) ? server : "."; ConnectTimeout = (timeout > 0) ? timeout : DEFAULT_CONNECT_TIMEOUT; PipeStream = new NamedPipeClientStream(serverName, pipe, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Anonymous); } public override bool IsOpen => PipeStream != null && PipeStream.IsConnected; public override async Task OpenAsync(CancellationToken cancellationToken) { if (IsOpen) { throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen); } await PipeStream.ConnectAsync( ConnectTimeout, cancellationToken); ResetConsumedMessageSize(); } public override void Close() { if (PipeStream != null) { PipeStream.Dispose(); PipeStream = null; } } public override async ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { if (PipeStream == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } CheckReadBytesAvailable(length); #if NETSTANDARD2_0 var numRead = await PipeStream.ReadAsync(buffer, offset, length, cancellationToken); #else var numRead = await PipeStream.ReadAsync(new Memory(buffer, offset, length), cancellationToken); #endif CountConsumedMessageBytes(numRead); return numRead; } public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { if (PipeStream == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } // if necessary, send the data in chunks // there's a system limit around 0x10000 bytes that we hit otherwise // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section." var nBytes = Math.Min(15 * 4096, length); // 16 would exceed the limit while (nBytes > 0) { #if NETSTANDARD2_0 await PipeStream.WriteAsync(buffer, offset, nBytes, cancellationToken); #else await PipeStream.WriteAsync(buffer.AsMemory(offset, nBytes), cancellationToken); #endif offset += nBytes; length -= nBytes; nBytes = Math.Min(nBytes, length); } } public override Task FlushAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ResetConsumedMessageSize(); return Task.CompletedTask; } protected override void Dispose(bool disposing) { if(disposing) { PipeStream?.Dispose(); } } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Client/TSocketTransport.cs000066400000000000000000000111651420101504100254270ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport.Client { // ReSharper disable once InconsistentNaming public class TSocketTransport : TStreamTransport { private bool _isDisposed; public TSocketTransport(TcpClient client, TConfiguration config) : base(config) { TcpClient = client ?? throw new ArgumentNullException(nameof(client)); SetInputOutputStream(); } public TSocketTransport(IPAddress host, int port, TConfiguration config, int timeout = 0) : base(config) { Host = host; Port = port; TcpClient = new TcpClient(); TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout; TcpClient.Client.NoDelay = true; SetInputOutputStream(); } public TSocketTransport(string host, int port, TConfiguration config, int timeout = 0) : base(config) { try { var entry = Dns.GetHostEntry(host); if (entry.AddressList.Length == 0) throw new TTransportException(TTransportException.ExceptionType.Unknown, "unable to resolve host name"); Host = entry.AddressList[0]; Port = port; TcpClient = new TcpClient(host, port); TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout; TcpClient.Client.NoDelay = true; SetInputOutputStream(); } catch (SocketException e) { throw new TTransportException(TTransportException.ExceptionType.Unknown, e.Message, e); } } private void SetInputOutputStream() { if (IsOpen) { InputStream = TcpClient.GetStream(); OutputStream = TcpClient.GetStream(); } } public TcpClient TcpClient { get; private set; } public IPAddress Host { get; } public int Port { get; } public int Timeout { set { if (TcpClient != null) { TcpClient.ReceiveTimeout = TcpClient.SendTimeout = value; } } } public override bool IsOpen { get { return (TcpClient != null) && TcpClient.Connected; } } public override async Task OpenAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (IsOpen) { throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected"); } if (Port <= 0) { throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port"); } if (TcpClient == null) { throw new InvalidOperationException("Invalid or not initialized tcp client"); } await TcpClient.ConnectAsync(Host, Port); SetInputOutputStream(); } public override void Close() { base.Close(); if (TcpClient != null) { TcpClient.Dispose(); TcpClient = null; } } // IDisposable protected override void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { TcpClient?.Dispose(); base.Dispose(disposing); } } _isDisposed = true; } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs000066400000000000000000000076411420101504100254360ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport.Client { // ReSharper disable once InconsistentNaming public class TStreamTransport : TEndpointTransport { private bool _isDisposed; protected TStreamTransport(TConfiguration config) :base(config) { } public TStreamTransport(Stream inputStream, Stream outputStream, TConfiguration config) : base(config) { InputStream = inputStream; OutputStream = outputStream; } protected Stream OutputStream { get; set; } private Stream _InputStream = null; protected Stream InputStream { get => _InputStream; set { _InputStream = value; ResetConsumedMessageSize(); } } public override bool IsOpen => true; public override Task OpenAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override void Close() { if (InputStream != null) { InputStream.Dispose(); InputStream = null; } if (OutputStream != null) { OutputStream.Dispose(); OutputStream = null; } } public override async ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { if (InputStream == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot read from null inputstream"); } #if NETSTANDARD2_0 return await InputStream.ReadAsync(buffer, offset, length, cancellationToken); #else return await InputStream.ReadAsync(new Memory(buffer, offset, length), cancellationToken); #endif } public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { if (OutputStream == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot write to null outputstream"); } #if NETSTANDARD2_0 await OutputStream.WriteAsync(buffer, offset, length, cancellationToken); #else await OutputStream.WriteAsync(buffer.AsMemory(offset, length), cancellationToken); #endif } public override async Task FlushAsync(CancellationToken cancellationToken) { await OutputStream.FlushAsync(cancellationToken); ResetConsumedMessageSize(); } // IDisposable protected override void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { InputStream?.Dispose(); OutputStream?.Dispose(); } } _isDisposed = true; } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Client/TTlsSocketTransport.cs000066400000000000000000000225751420101504100261210ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport.Client { //TODO: check for correct work // ReSharper disable once InconsistentNaming public class TTlsSocketTransport : TStreamTransport { private readonly X509Certificate2 _certificate; private readonly RemoteCertificateValidationCallback _certValidator; private readonly IPAddress _host; private readonly bool _isServer; private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback; private readonly int _port; private readonly SslProtocols _sslProtocols; private readonly string _targetHost; private TcpClient _client; private SslStream _secureStream; private int _timeout; public TTlsSocketTransport(TcpClient client, TConfiguration config, X509Certificate2 certificate, bool isServer = false, RemoteCertificateValidationCallback certValidator = null, LocalCertificateSelectionCallback localCertificateSelectionCallback = null, SslProtocols sslProtocols = SslProtocols.Tls12) : base(config) { _client = client; _certificate = certificate; _certValidator = certValidator; _localCertificateSelectionCallback = localCertificateSelectionCallback; _sslProtocols = sslProtocols; _isServer = isServer; if (isServer && certificate == null) { throw new ArgumentException("TTlsSocketTransport needs certificate to be used for server", nameof(certificate)); } if (IsOpen) { InputStream = client.GetStream(); OutputStream = client.GetStream(); } } public TTlsSocketTransport(IPAddress host, int port, TConfiguration config, string certificatePath, RemoteCertificateValidationCallback certValidator = null, LocalCertificateSelectionCallback localCertificateSelectionCallback = null, SslProtocols sslProtocols = SslProtocols.Tls12) : this(host, port, config, 0, new X509Certificate2(certificatePath), certValidator, localCertificateSelectionCallback, sslProtocols) { } public TTlsSocketTransport(IPAddress host, int port, TConfiguration config, X509Certificate2 certificate = null, RemoteCertificateValidationCallback certValidator = null, LocalCertificateSelectionCallback localCertificateSelectionCallback = null, SslProtocols sslProtocols = SslProtocols.Tls12) : this(host, port, config, 0, certificate, certValidator, localCertificateSelectionCallback, sslProtocols) { } public TTlsSocketTransport(IPAddress host, int port, TConfiguration config, int timeout, X509Certificate2 certificate, RemoteCertificateValidationCallback certValidator = null, LocalCertificateSelectionCallback localCertificateSelectionCallback = null, SslProtocols sslProtocols = SslProtocols.Tls12) : base(config) { _host = host; _port = port; _timeout = timeout; _certificate = certificate; _certValidator = certValidator; _localCertificateSelectionCallback = localCertificateSelectionCallback; _sslProtocols = sslProtocols; InitSocket(); } public TTlsSocketTransport(string host, int port, TConfiguration config, int timeout, X509Certificate2 certificate, RemoteCertificateValidationCallback certValidator = null, LocalCertificateSelectionCallback localCertificateSelectionCallback = null, SslProtocols sslProtocols = SslProtocols.Tls12) : base(config) { try { _targetHost = host; var entry = Dns.GetHostEntry(host); if (entry.AddressList.Length == 0) throw new TTransportException(TTransportException.ExceptionType.Unknown, "unable to resolve host name"); _host = entry.AddressList[0]; _port = port; _timeout = timeout; _certificate = certificate; _certValidator = certValidator; _localCertificateSelectionCallback = localCertificateSelectionCallback; _sslProtocols = sslProtocols; InitSocket(); } catch (SocketException e) { throw new TTransportException(TTransportException.ExceptionType.Unknown, e.Message, e); } } public int Timeout { set { _client.ReceiveTimeout = _client.SendTimeout = _timeout = value; } } public TcpClient TcpClient => _client; public IPAddress Host => _host; public int Port => _port; public override bool IsOpen { get { if (_client == null) { return false; } return _client.Connected; } } private void InitSocket() { _client = new TcpClient(); _client.ReceiveTimeout = _client.SendTimeout = _timeout; _client.Client.NoDelay = true; } private bool DefaultCertificateValidator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslValidationErrors) { return sslValidationErrors == SslPolicyErrors.None; } public override async Task OpenAsync(CancellationToken cancellationToken) { if (IsOpen) { throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected"); } if (_host == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host"); } if (_port <= 0) { throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port"); } if (_client == null) { InitSocket(); } if (_client != null) { await _client.ConnectAsync(_host, _port); await SetupTlsAsync(); } } public async Task SetupTlsAsync() { var validator = _certValidator ?? DefaultCertificateValidator; if (_localCertificateSelectionCallback != null) { _secureStream = new SslStream(_client.GetStream(), false, validator, _localCertificateSelectionCallback); } else { _secureStream = new SslStream(_client.GetStream(), false, validator); } try { if (_isServer) { // Server authentication await _secureStream.AuthenticateAsServerAsync(_certificate, _certValidator != null, _sslProtocols, true); } else { // Client authentication var certs = _certificate != null ? new X509CertificateCollection {_certificate} : new X509CertificateCollection(); var targetHost = _targetHost ?? _host.ToString(); await _secureStream.AuthenticateAsClientAsync(targetHost, certs, _sslProtocols, true); } } catch (Exception) { Close(); throw; } InputStream = _secureStream; OutputStream = _secureStream; } public override void Close() { base.Close(); if (_client != null) { _client.Dispose(); _client = null; } if (_secureStream != null) { _secureStream.Dispose(); _secureStream = null; } } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Layered/000077500000000000000000000000001420101504100217525ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Transport/Layered/TBufferedTransport.cs000066400000000000000000000155531420101504100260750ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Diagnostics; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport { // ReSharper disable once InconsistentNaming public class TBufferedTransport : TLayeredTransport { private readonly int DesiredBufferSize; private readonly Client.TMemoryBufferTransport ReadBuffer; private readonly Client.TMemoryBufferTransport WriteBuffer; private bool IsDisposed; public class Factory : TTransportFactory { public override TTransport GetTransport(TTransport trans) { return new TBufferedTransport(trans); } } //TODO: should support only specified input transport? public TBufferedTransport(TTransport transport, int bufSize = 1024) : base(transport) { if (bufSize <= 0) { throw new ArgumentOutOfRangeException(nameof(bufSize), "Buffer size must be a positive number."); } DesiredBufferSize = bufSize; WriteBuffer = new Client.TMemoryBufferTransport(InnerTransport.Configuration, bufSize); ReadBuffer = new Client.TMemoryBufferTransport(InnerTransport.Configuration, bufSize); Debug.Assert(DesiredBufferSize == ReadBuffer.Capacity); Debug.Assert(DesiredBufferSize == WriteBuffer.Capacity); } public TTransport UnderlyingTransport { get { CheckNotDisposed(); return InnerTransport; } } public override bool IsOpen => !IsDisposed && InnerTransport.IsOpen; public override async Task OpenAsync(CancellationToken cancellationToken) { CheckNotDisposed(); await InnerTransport.OpenAsync(cancellationToken); } public override void Close() { CheckNotDisposed(); InnerTransport.Close(); } public override async ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { CheckNotDisposed(); ValidateBufferArgs(buffer, offset, length); if (!IsOpen) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } // do we have something buffered? var count = ReadBuffer.Length - ReadBuffer.Position; if (count > 0) { return await ReadBuffer.ReadAsync(buffer, offset, length, cancellationToken); } // does the request even fit into the buffer? // Note we test for >= instead of > to avoid nonsense buffering if (length >= ReadBuffer.Capacity) { return await InnerTransport.ReadAsync(buffer, offset, length, cancellationToken); } // buffer a new chunk of bytes from the underlying transport ReadBuffer.Length = ReadBuffer.Capacity; ReadBuffer.TryGetBuffer(out ArraySegment bufSegment); ReadBuffer.Length = await InnerTransport.ReadAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken); ReadBuffer.Position = 0; // deliver the bytes return await ReadBuffer.ReadAsync(buffer, offset, length, cancellationToken); } public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { CheckNotDisposed(); ValidateBufferArgs(buffer, offset, length); if (!IsOpen) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } // enough space left in buffer? var free = WriteBuffer.Capacity - WriteBuffer.Length; if (length > free) { WriteBuffer.TryGetBuffer(out ArraySegment bufSegment); await InnerTransport.WriteAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken); WriteBuffer.SetLength(0); } // do the data even fit into the buffer? // Note we test for < instead of <= to avoid nonsense buffering if (length < WriteBuffer.Capacity) { await WriteBuffer.WriteAsync(buffer, offset, length, cancellationToken); return; } // write thru await InnerTransport.WriteAsync(buffer, offset, length, cancellationToken); } public override async Task FlushAsync(CancellationToken cancellationToken) { CheckNotDisposed(); if (!IsOpen) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } if (WriteBuffer.Length > 0) { WriteBuffer.TryGetBuffer(out ArraySegment bufSegment); await InnerTransport.WriteAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken); WriteBuffer.SetLength(0); } await InnerTransport.FlushAsync(cancellationToken); } public override void CheckReadBytesAvailable(long numBytes) { var buffered = ReadBuffer.Length - ReadBuffer.Position; if (buffered < numBytes) { numBytes -= buffered; InnerTransport.CheckReadBytesAvailable(numBytes); } } private void CheckNotDisposed() { if (IsDisposed) { throw new ObjectDisposedException(nameof(InnerTransport)); } } // IDisposable protected override void Dispose(bool disposing) { if (!IsDisposed) { if (disposing) { ReadBuffer?.Dispose(); WriteBuffer?.Dispose(); InnerTransport?.Dispose(); } } IsDisposed = true; } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Layered/TFramedTransport.cs000066400000000000000000000145411420101504100255450ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Buffers.Binary; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport { // ReSharper disable once InconsistentNaming public class TFramedTransport : TLayeredTransport { private const int HeaderSize = 4; private readonly byte[] HeaderBuf = new byte[HeaderSize]; private readonly Client.TMemoryBufferTransport ReadBuffer; private readonly Client.TMemoryBufferTransport WriteBuffer; private bool IsDisposed; public class Factory : TTransportFactory { public override TTransport GetTransport(TTransport trans) { return new TFramedTransport(trans); } } public TFramedTransport(TTransport transport) : base(transport) { ReadBuffer = new Client.TMemoryBufferTransport(Configuration); WriteBuffer = new Client.TMemoryBufferTransport(Configuration); InitWriteBuffer(); } public override bool IsOpen => !IsDisposed && InnerTransport.IsOpen; public override async Task OpenAsync(CancellationToken cancellationToken) { CheckNotDisposed(); await InnerTransport.OpenAsync(cancellationToken); } public override void Close() { CheckNotDisposed(); InnerTransport.Close(); } public override async ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { CheckNotDisposed(); ValidateBufferArgs(buffer, offset, length); if (!IsOpen) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } // Read another frame of data if we run out of bytes if (ReadBuffer.Position >= ReadBuffer.Length) { await ReadFrameAsync(cancellationToken); } return await ReadBuffer.ReadAsync(buffer, offset, length, cancellationToken); } private async ValueTask ReadFrameAsync(CancellationToken cancellationToken) { UpdateKnownMessageSize(-1); await InnerTransport.ReadAllAsync(HeaderBuf, 0, HeaderSize, cancellationToken); int size = BinaryPrimitives.ReadInt32BigEndian(HeaderBuf); if ((0 > size) || (size > Configuration.MaxFrameSize)) // size must be in the range 0 to allowed max throw new TTransportException(TTransportException.ExceptionType.Unknown, $"Maximum frame size exceeded ({size} bytes)"); UpdateKnownMessageSize(size + HeaderSize); ReadBuffer.SetLength(size); ReadBuffer.Seek(0, SeekOrigin.Begin); ReadBuffer.TryGetBuffer(out ArraySegment bufSegment); await InnerTransport.ReadAllAsync(bufSegment.Array, 0, size, cancellationToken); } public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { CheckNotDisposed(); ValidateBufferArgs(buffer, offset, length); if (!IsOpen) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } if (WriteBuffer.Length > (int.MaxValue - length)) { await FlushAsync(cancellationToken); } await WriteBuffer.WriteAsync(buffer, offset, length, cancellationToken); } public override async Task FlushAsync(CancellationToken cancellationToken) { CheckNotDisposed(); if (!IsOpen) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } WriteBuffer.TryGetBuffer(out ArraySegment bufSegment); int dataLen = bufSegment.Count - HeaderSize; if (dataLen < 0) { throw new InvalidOperationException(); // logic error actually } // Inject message header into the reserved buffer space BinaryPrimitives.WriteInt32BigEndian(bufSegment.Array, dataLen); // Send the entire message at once await InnerTransport.WriteAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken); InitWriteBuffer(); await InnerTransport.FlushAsync(cancellationToken); } private void InitWriteBuffer() { // Reserve space for message header to be put right before sending it out WriteBuffer.SetLength(HeaderSize); WriteBuffer.Seek(0, SeekOrigin.End); } public override void CheckReadBytesAvailable(long numBytes) { var buffered = ReadBuffer.Length - ReadBuffer.Position; if (buffered < numBytes) { numBytes -= buffered; InnerTransport.CheckReadBytesAvailable(numBytes); } } private void CheckNotDisposed() { if (IsDisposed) { throw new ObjectDisposedException(this.GetType().Name); } } // IDisposable protected override void Dispose(bool disposing) { if (!IsDisposed) { if (disposing) { ReadBuffer?.Dispose(); WriteBuffer?.Dispose(); InnerTransport?.Dispose(); } } IsDisposed = true; } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Layered/TLayeredTransport.cs000066400000000000000000000030471420101504100257330ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Text; namespace Thrift.Transport { public abstract class TLayeredTransport : TTransport { public readonly TTransport InnerTransport; public override TConfiguration Configuration { get => InnerTransport.Configuration; } public TLayeredTransport(TTransport transport) { InnerTransport = transport ?? throw new ArgumentNullException(nameof(transport)); } public override void UpdateKnownMessageSize(long size) { InnerTransport.UpdateKnownMessageSize(size); } public override void CheckReadBytesAvailable(long numBytes) { InnerTransport.CheckReadBytesAvailable(numBytes); } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Server/000077500000000000000000000000001420101504100216335ustar00rootroot00000000000000thrift-0.16.0/lib/netstd/Thrift/Transport/Server/NullLogger.cs000066400000000000000000000032151420101504100242350ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using Microsoft.Extensions.Logging; using System; namespace Thrift.Transport.Server { // sometimes we just don't want to log anything internal class NullLogger : IDisposable, ILogger, ILogger { internal class NullScope : IDisposable { public void Dispose() { // nothing to do } } public IDisposable BeginScope(TState state) { return new NullScope(); } public void Dispose() { // nothing to do } public bool IsEnabled(LogLevel logLevel) { return false; // no } public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { // do nothing } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Server/THttpServerTransport.cs000066400000000000000000000127341420101504100263400ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Thrift.Processor; using Thrift.Protocol; using Thrift.Transport.Client; namespace Thrift.Transport.Server { // ReSharper disable once InconsistentNaming public class THttpServerTransport { protected const string ContentType = "application/x-thrift"; /* never used private readonly ILogger _logger; private readonly RequestDelegate _next; */ protected Encoding Encoding = Encoding.UTF8; protected TProtocolFactory InputProtocolFactory; protected TProtocolFactory OutputProtocolFactory; protected TTransportFactory InputTransportFactory; protected TTransportFactory OutputTransportFactory; protected ITAsyncProcessor Processor; protected TConfiguration Configuration; public THttpServerTransport( ITAsyncProcessor processor, TConfiguration config, RequestDelegate next = null, ILoggerFactory loggerFactory = null) : this(processor, config, new TBinaryProtocol.Factory(), null, next, loggerFactory) { } public THttpServerTransport( ITAsyncProcessor processor, TConfiguration config, TProtocolFactory protocolFactory, TTransportFactory transFactory = null, RequestDelegate next = null, ILoggerFactory loggerFactory = null) : this(processor, config, protocolFactory, protocolFactory, transFactory, transFactory, next, loggerFactory) { } public THttpServerTransport( ITAsyncProcessor processor, TConfiguration config, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory, TTransportFactory inputTransFactory = null, TTransportFactory outputTransFactory = null, RequestDelegate next = null, ILoggerFactory loggerFactory = null) { // loggerFactory == null is not illegal anymore Processor = processor ?? throw new ArgumentNullException(nameof(processor)); Configuration = config; // may be null InputProtocolFactory = inputProtocolFactory ?? throw new ArgumentNullException(nameof(inputProtocolFactory)); OutputProtocolFactory = outputProtocolFactory ?? throw new ArgumentNullException(nameof(outputProtocolFactory)); InputTransportFactory = inputTransFactory; OutputTransportFactory = outputTransFactory; // never used _ = next; _ = loggerFactory; /* never used _next = next; _logger = (loggerFactory != null) ? loggerFactory.CreateLogger() : new NullLogger(); */ } public async Task Invoke(HttpContext context) { await ProcessRequestAsync(context, context.RequestAborted); //TODO: check for correct logic } public async Task ProcessRequestAsync(HttpContext context, CancellationToken cancellationToken) { var transport = new TStreamTransport(context.Request.Body, context.Response.Body, Configuration); try { var intrans = (InputTransportFactory != null) ? InputTransportFactory.GetTransport(transport) : transport; var outtrans = (OutputTransportFactory != null) ? OutputTransportFactory.GetTransport(transport) : transport; var input = InputProtocolFactory.GetProtocol(intrans); var output = OutputProtocolFactory.GetProtocol(outtrans); context.Response.ContentType = ContentType; while (await Processor.ProcessAsync(input, output, cancellationToken)) { if (!context.Response.HasStarted) // oneway method called await context.Response.Body.FlushAsync(cancellationToken); } } catch (TTransportException) { if (!context.Response.HasStarted) // if something goes bust, let the client know context.Response.StatusCode = 500; // internal server error } catch (TProtocolException) { if (!context.Response.HasStarted) // if something goes bust, let the client know context.Response.StatusCode = 400; // bad request, e.g. required field missing } finally { transport.Close(); } } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs000066400000000000000000000334471420101504100272670ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using Microsoft.Win32.SafeHandles; using System; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.ComponentModel; using System.Security.AccessControl; using System.Security.Principal; namespace Thrift.Transport.Server { [Flags] public enum NamedPipeClientFlags { None = 0x00, OnlyLocalClients = 0x01 }; // ReSharper disable once InconsistentNaming public class TNamedPipeServerTransport : TServerTransport { /// /// This is the address of the Pipe on the localhost. /// private readonly string _pipeAddress; private bool _asyncMode = true; private volatile bool _isPending = true; private NamedPipeServerStream _stream = null; private readonly bool _onlyLocalClients = false; // compatibility default public TNamedPipeServerTransport(string pipeAddress, TConfiguration config, NamedPipeClientFlags flags) : base(config) { _pipeAddress = pipeAddress; _onlyLocalClients = flags.HasFlag(NamedPipeClientFlags.OnlyLocalClients); } [Obsolete("This CTOR is deprecated, please use the other one instead.")] public TNamedPipeServerTransport(string pipeAddress, TConfiguration config) : base(config) { _pipeAddress = pipeAddress; _onlyLocalClients = false; } public override bool IsOpen() { return true; } public override void Listen() { // nothing to do here } public override void Close() { if (_stream != null) { try { if (_stream.IsConnected) _stream.Disconnect(); _stream.Dispose(); } finally { _stream = null; _isPending = false; } } } public override bool IsClientPending() { return _isPending; } private void EnsurePipeInstance() { if (_stream == null) { const PipeDirection direction = PipeDirection.InOut; const int maxconn = NamedPipeServerStream.MaxAllowedServerInstances; const PipeTransmissionMode mode = PipeTransmissionMode.Byte; const int inbuf = 4096; const int outbuf = 4096; var options = _asyncMode ? PipeOptions.Asynchronous : PipeOptions.None; // TODO: "CreatePipeNative" ist only a workaround, and there are have basically two possible outcomes: // - once NamedPipeServerStream() gets a CTOR that supports pipesec, remove CreatePipeNative() // - if 31190 gets resolved before, use _stream.SetAccessControl(pipesec) instead of CreatePipeNative() // EITHER WAY, // - if CreatePipeNative() finally gets removed, also remove "allow unsafe code" from the project settings try { var handle = CreatePipeNative(_pipeAddress, inbuf, outbuf, _onlyLocalClients); if ((handle != null) && (!handle.IsInvalid)) { _stream = new NamedPipeServerStream(PipeDirection.InOut, _asyncMode, false, handle); handle = null; // we don't own it any longer } else { handle?.Dispose(); _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf/*, pipesec*/); } } catch (NotImplementedException) // Mono still does not support async, fallback to sync { if (_asyncMode) { options &= (~PipeOptions.Asynchronous); _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf); _asyncMode = false; } else { throw; } } } } #region CreatePipeNative workaround [StructLayout(LayoutKind.Sequential)] internal class SECURITY_ATTRIBUTES { internal int nLength = 0; internal IntPtr lpSecurityDescriptor = IntPtr.Zero; internal int bInheritHandle = 0; } private const string Kernel32 = "kernel32.dll"; [DllImport(Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr CreateNamedPipe( string lpName, uint dwOpenMode, uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize, uint nDefaultTimeOut, SECURITY_ATTRIBUTES pipeSecurityDescriptor ); // Workaround: create the pipe via API call // we have to do it this way, since NamedPipeServerStream() for netstd still lacks a few CTORs and/or arguments // and _stream.SetAccessControl(pipesec); only keeps throwing ACCESS_DENIED errors at us // References: // - https://github.com/dotnet/corefx/issues/30170 (closed, continued in 31190) // - https://github.com/dotnet/corefx/issues/31190 System.IO.Pipes.AccessControl package does not work // - https://github.com/dotnet/corefx/issues/24040 NamedPipeServerStream: Provide support for WRITE_DAC // - https://github.com/dotnet/corefx/issues/34400 Have a mechanism for lower privileged user to connect to a privileged user's pipe private static SafePipeHandle CreatePipeNative(string name, int inbuf, int outbuf, bool OnlyLocalClients) { if (! RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return null; // Windows only var pinningHandle = new GCHandle(); try { // owner gets full access, everyone else read/write var pipesec = new PipeSecurity(); using (var currentIdentity = WindowsIdentity.GetCurrent()) { var sidOwner = currentIdentity.Owner; var sidWorld = new SecurityIdentifier(WellKnownSidType.WorldSid, null); pipesec.SetOwner(sidOwner); pipesec.AddAccessRule(new PipeAccessRule(sidOwner, PipeAccessRights.FullControl, AccessControlType.Allow)); pipesec.AddAccessRule(new PipeAccessRule(sidWorld, PipeAccessRights.ReadWrite, AccessControlType.Allow)); } // create a security descriptor and assign it to the security attribs var secAttrs = new SECURITY_ATTRIBUTES(); byte[] sdBytes = pipesec.GetSecurityDescriptorBinaryForm(); pinningHandle = GCHandle.Alloc(sdBytes, GCHandleType.Pinned); unsafe { fixed (byte* pSD = sdBytes) { secAttrs.lpSecurityDescriptor = (IntPtr)pSD; } } // a bunch of constants we will need shortly const uint PIPE_ACCESS_DUPLEX = 0x00000003; const uint FILE_FLAG_OVERLAPPED = 0x40000000; const uint WRITE_DAC = 0x00040000; const uint PIPE_TYPE_BYTE = 0x00000000; const uint PIPE_READMODE_BYTE = 0x00000000; const uint PIPE_UNLIMITED_INSTANCES = 255; const uint PIPE_ACCEPT_REMOTE_CLIENTS = 0x00000000; // Connections from remote clients can be accepted and checked against the security descriptor for the pipe. const uint PIPE_REJECT_REMOTE_CLIENTS = 0x00000008; // Connections from remote clients are automatically rejected. // any extra flags we want to add uint dwPipeModeXtra = (OnlyLocalClients ? PIPE_REJECT_REMOTE_CLIENTS : PIPE_ACCEPT_REMOTE_CLIENTS) ; // create the pipe via API call var rawHandle = CreateNamedPipe( @"\\.\pipe\" + name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | dwPipeModeXtra, PIPE_UNLIMITED_INSTANCES, (uint)inbuf, (uint)outbuf, 5 * 1000, secAttrs ); // make a SafePipeHandle() from it var handle = new SafePipeHandle(rawHandle, true); if (handle.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); // return it (to be packaged) return handle; } finally { if (pinningHandle.IsAllocated) pinningHandle.Free(); } } #endregion protected override async ValueTask AcceptImplementationAsync(CancellationToken cancellationToken) { try { EnsurePipeInstance(); await _stream.WaitForConnectionAsync(cancellationToken); var trans = new ServerTransport(_stream, Configuration); _stream = null; // pass ownership to ServerTransport //_isPending = false; return trans; } catch (TTransportException) { Close(); throw; } catch (TaskCanceledException) { Close(); throw; // let it bubble up } catch (Exception e) { Close(); throw new TTransportException(TTransportException.ExceptionType.NotOpen, e.Message); } } private class ServerTransport : TEndpointTransport { private readonly NamedPipeServerStream PipeStream; public ServerTransport(NamedPipeServerStream stream, TConfiguration config) : base(config) { PipeStream = stream; } public override bool IsOpen => PipeStream != null && PipeStream.IsConnected; public override Task OpenAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.CompletedTask; } public override void Close() { PipeStream?.Dispose(); } public override async ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { if (PipeStream == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } CheckReadBytesAvailable(length); #if NETSTANDARD2_0 var numBytes = await PipeStream.ReadAsync(buffer, offset, length, cancellationToken); #else var numBytes = await PipeStream.ReadAsync(buffer.AsMemory(offset, length), cancellationToken); #endif CountConsumedMessageBytes(numBytes); return numBytes; } public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { if (PipeStream == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen); } // if necessary, send the data in chunks // there's a system limit around 0x10000 bytes that we hit otherwise // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section." var nBytes = Math.Min(15 * 4096, length); // 16 would exceed the limit while (nBytes > 0) { #if NET5_0_OR_GREATER await PipeStream.WriteAsync(buffer.AsMemory(offset, nBytes), cancellationToken); #else await PipeStream.WriteAsync(buffer, offset, nBytes, cancellationToken); #endif offset += nBytes; length -= nBytes; nBytes = Math.Min(nBytes, length); } } public override Task FlushAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ResetConsumedMessageSize(); return Task.CompletedTask; } protected override void Dispose(bool disposing) { if (disposing) { PipeStream?.Dispose(); } } } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Server/TServerSocketTransport.cs000066400000000000000000000121511420101504100266420ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using Thrift.Transport.Client; namespace Thrift.Transport.Server { // ReSharper disable once InconsistentNaming public class TServerSocketTransport : TServerTransport { private readonly int _clientTimeout; private TcpListener _server; public TServerSocketTransport(TcpListener listener, TConfiguration config, int clientTimeout = 0) : base(config) { _server = listener; _clientTimeout = clientTimeout; } public TServerSocketTransport(int port, TConfiguration config, int clientTimeout = 0) : this(null, config, clientTimeout) { try { // Make server socket _server = new TcpListener(IPAddress.Any, port); _server.Server.NoDelay = true; } catch (Exception) { _server = null; throw new TTransportException("Could not create ServerSocket on port " + port + "."); } } public override bool IsOpen() { return (_server != null) && (_server.Server != null) && _server.Server.IsBound; } public int GetPort() { if ((_server != null) && (_server.Server != null) && (_server.Server.LocalEndPoint != null)) { if (_server.Server.LocalEndPoint is IPEndPoint server) { return server.Port; } else { throw new TTransportException("ServerSocket is not a network socket"); } } else { throw new TTransportException("ServerSocket is not open"); } } public override void Listen() { // Make sure not to block on accept if (_server != null) { try { _server.Start(); } catch (SocketException sx) { throw new TTransportException("Could not accept on listening socket: " + sx.Message); } } } public override bool IsClientPending() { return _server.Pending(); } protected override async ValueTask AcceptImplementationAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_server == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket."); } try { TTransport tSocketTransport = null; #if NET6_0_OR_GREATER var tcpClient = await _server.AcceptTcpClientAsync(cancellationToken); #else var tcpClient = await _server.AcceptTcpClientAsync(); #endif try { tSocketTransport = new TSocketTransport(tcpClient, Configuration) { Timeout = _clientTimeout }; return tSocketTransport; } catch (Exception) { if (tSocketTransport != null) { tSocketTransport.Dispose(); } else // Otherwise, clean it up ourselves. { ((IDisposable)tcpClient).Dispose(); } throw; } } catch (Exception ex) { throw new TTransportException(ex.ToString()); } } public override void Close() { if (_server != null) { try { _server.Stop(); } catch (Exception ex) { throw new TTransportException("WARNING: Could not close server socket: " + ex); } _server = null; } } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Server/TServerTransport.cs000066400000000000000000000035231420101504100254740ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport { // ReSharper disable once InconsistentNaming public abstract class TServerTransport { public readonly TConfiguration Configuration; public TServerTransport(TConfiguration config) { Configuration = config ?? new TConfiguration(); } public abstract bool IsOpen(); public abstract void Listen(); public abstract void Close(); public abstract bool IsClientPending(); protected abstract ValueTask AcceptImplementationAsync(CancellationToken cancellationToken = default); public async ValueTask AcceptAsync(CancellationToken cancellationToken = default) { var transport = await AcceptImplementationAsync(cancellationToken); if (transport == null) { throw new TTransportException($"{nameof(AcceptImplementationAsync)} should not return null"); } return transport; } } } thrift-0.16.0/lib/netstd/Thrift/Transport/Server/TTlsServerSocketTransport.cs000066400000000000000000000141331420101504100273270ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Thrift.Transport.Client; namespace Thrift.Transport.Server { // ReSharper disable once InconsistentNaming public class TTlsServerSocketTransport : TServerTransport { private readonly RemoteCertificateValidationCallback _clientCertValidator; private readonly int _clientTimeout = 0; private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback; private readonly X509Certificate2 _serverCertificate; private readonly SslProtocols _sslProtocols; private TcpListener _server; public TTlsServerSocketTransport( TcpListener listener, TConfiguration config, X509Certificate2 certificate, RemoteCertificateValidationCallback clientCertValidator = null, LocalCertificateSelectionCallback localCertificateSelectionCallback = null, SslProtocols sslProtocols = SslProtocols.Tls12) : base(config) { if (!certificate.HasPrivateKey) { throw new TTransportException(TTransportException.ExceptionType.Unknown, "Your server-certificate needs to have a private key"); } _serverCertificate = certificate; _clientCertValidator = clientCertValidator; _localCertificateSelectionCallback = localCertificateSelectionCallback; _sslProtocols = sslProtocols; _server = listener; } public TTlsServerSocketTransport( int port, TConfiguration config, X509Certificate2 certificate, RemoteCertificateValidationCallback clientCertValidator = null, LocalCertificateSelectionCallback localCertificateSelectionCallback = null, SslProtocols sslProtocols = SslProtocols.Tls12) : this(null, config, certificate, clientCertValidator, localCertificateSelectionCallback, sslProtocols) { try { // Create server socket _server = new TcpListener(IPAddress.Any, port); _server.Server.NoDelay = true; } catch (Exception) { _server = null; throw new TTransportException($"Could not create ServerSocket on port {port}."); } } public override bool IsOpen() { return (_server != null) && (_server.Server != null) && _server.Server.IsBound; } public int GetPort() { if ((_server != null) && (_server.Server != null) && (_server.Server.LocalEndPoint != null)) { if (_server.Server.LocalEndPoint is IPEndPoint server) { return server.Port; } else { throw new TTransportException("ServerSocket is not a network socket"); } } else { throw new TTransportException("ServerSocket is not open"); } } public override void Listen() { // Make sure accept is not blocking if (_server != null) { try { _server.Start(); } catch (SocketException sx) { throw new TTransportException($"Could not accept on listening socket: {sx.Message}"); } } } public override bool IsClientPending() { return _server.Pending(); } protected override async ValueTask AcceptImplementationAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_server == null) { throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket."); } try { var client = await _server.AcceptTcpClientAsync(); client.SendTimeout = client.ReceiveTimeout = _clientTimeout; //wrap the client in an SSL Socket passing in the SSL cert var tTlsSocket = new TTlsSocketTransport( client, Configuration, _serverCertificate, true, _clientCertValidator, _localCertificateSelectionCallback, _sslProtocols); await tTlsSocket.SetupTlsAsync(); return tTlsSocket; } catch (Exception ex) { throw new TTransportException(ex.ToString()); } } public override void Close() { if (_server != null) { try { _server.Stop(); } catch (Exception ex) { throw new TTransportException($"WARNING: Could not close server socket: {ex}"); } _server = null; } } } } thrift-0.16.0/lib/netstd/Thrift/Transport/TEndpointTransport.cs000066400000000000000000000075251420101504100245460ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; namespace Thrift.Transport { abstract public class TEndpointTransport : TTransport { protected long MaxMessageSize { get => Configuration.MaxMessageSize; } protected long KnownMessageSize { get; private set; } protected long RemainingMessageSize { get; private set; } private readonly TConfiguration _configuration; public override TConfiguration Configuration { get => _configuration; } public TEndpointTransport( TConfiguration config) { _configuration = config ?? new TConfiguration(); Debug.Assert(Configuration != null); ResetConsumedMessageSize(); } /// /// Resets RemainingMessageSize to the configured maximum /// protected void ResetConsumedMessageSize(long newSize = -1) { // full reset if (newSize < 0) { KnownMessageSize = MaxMessageSize; RemainingMessageSize = MaxMessageSize; return; } // update only: message size can shrink, but not grow Debug.Assert(KnownMessageSize <= MaxMessageSize); if (newSize > KnownMessageSize) throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "MaxMessageSize reached"); KnownMessageSize = newSize; RemainingMessageSize = newSize; } /// /// Updates RemainingMessageSize to reflect then known real message size (e.g. framed transport). /// Will throw if we already consumed too many bytes or if the new size is larger than allowed. /// /// public override void UpdateKnownMessageSize(long size) { var consumed = KnownMessageSize - RemainingMessageSize; ResetConsumedMessageSize(size); CountConsumedMessageBytes(consumed); } /// /// Throws if there are not enough bytes in the input stream to satisfy a read of numBytes bytes of data /// /// public override void CheckReadBytesAvailable(long numBytes) { if (RemainingMessageSize < numBytes) throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "MaxMessageSize reached"); } /// /// Consumes numBytes from the RemainingMessageSize. /// /// protected void CountConsumedMessageBytes(long numBytes) { if (RemainingMessageSize >= numBytes) { RemainingMessageSize -= numBytes; } else { RemainingMessageSize = 0; throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "MaxMessageSize reached"); } } } } thrift-0.16.0/lib/netstd/Thrift/Transport/TTransport.cs000066400000000000000000000130051420101504100230330ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Diagnostics; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Thrift.Transport { //TODO: think about client info // ReSharper disable once InconsistentNaming public abstract class TTransport : IDisposable { //TODO: think how to avoid peek byte private readonly byte[] _peekBuffer = new byte[1]; private bool _hasPeekByte; public abstract bool IsOpen { get; } public abstract TConfiguration Configuration { get; } public abstract void UpdateKnownMessageSize(long size); public abstract void CheckReadBytesAvailable(long numBytes); public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public async ValueTask PeekAsync(CancellationToken cancellationToken) { //If we already have a byte read but not consumed, do nothing. if (_hasPeekByte) { return true; } //If transport closed we can't peek. if (!IsOpen) { return false; } //Try to read one byte. If succeeds we will need to store it for the next read. try { var bytes = await ReadAsync(_peekBuffer, 0, 1, cancellationToken); if (bytes == 0) { return false; } } catch (IOException) { return false; } _hasPeekByte = true; return true; } public abstract Task OpenAsync(CancellationToken cancellationToken = default); public abstract void Close(); protected static void ValidateBufferArgs(byte[] buffer, int offset, int length) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } #if DEBUG // let it fail with OutOfRange in RELEASE mode if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset), "Buffer offset must be >= 0"); } if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length), "Buffer length must be >= 0"); } if (offset + length > buffer.Length) { throw new ArgumentOutOfRangeException(nameof(buffer), "Not enough data"); } #endif } public abstract ValueTask ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken); public virtual async ValueTask ReadAllAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ValidateBufferArgs(buffer, offset, length); if (length <= 0) return 0; // If we previously peeked a byte, we need to use that first. var totalBytes = 0; if (_hasPeekByte) { buffer[offset++] = _peekBuffer[0]; _hasPeekByte = false; if (1 == length) { return 1; // we're done } ++totalBytes; } var remaining = length - totalBytes; Debug.Assert(remaining > 0); // any other possible cases should have been handled already while (true) { var numBytes = await ReadAsync(buffer, offset, remaining, cancellationToken); totalBytes += numBytes; if (totalBytes >= length) { return totalBytes; // we're done } if (numBytes <= 0) { throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "Cannot read, Remote side has closed"); } remaining -= numBytes; offset += numBytes; } } public virtual async Task WriteAsync(byte[] buffer, CancellationToken cancellationToken) { await WriteAsync(buffer, 0, buffer.Length, CancellationToken.None); } public virtual async Task WriteAsync(byte[] buffer, int offset, int length) { await WriteAsync(buffer, offset, length, CancellationToken.None); } public abstract Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken); public abstract Task FlushAsync(CancellationToken cancellationToken); protected abstract void Dispose(bool disposing); } } thrift-0.16.0/lib/netstd/Thrift/Transport/TTransportException.cs000066400000000000000000000034001420101504100247100ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; namespace Thrift.Transport { // ReSharper disable once InconsistentNaming public class TTransportException : TException { public enum ExceptionType { Unknown, NotOpen, AlreadyOpen, TimedOut, EndOfFile, Interrupted } public ExceptionType ExType { get; private set; } public TTransportException() { } public TTransportException(ExceptionType exType, Exception inner = null) : base(string.Empty, inner) { ExType = exType; } public TTransportException(ExceptionType exType, string message, Exception inner = null) : base(message, inner) { ExType = exType; } public TTransportException(string message, Exception inner = null) : base(message, inner) { } public ExceptionType Type => ExType; } }thrift-0.16.0/lib/netstd/Thrift/Transport/TTransportFactory.cs000066400000000000000000000026211420101504100243650ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. namespace Thrift.Transport { /// /// From Mark Slee & Aditya Agarwal of Facebook: /// Factory class used to create wrapped instance of Transports. /// This is used primarily in servers, which get Transports from /// a ServerTransport and then may want to mutate them (i.e. create /// a BufferedTransport from the underlying base transport) /// // ReSharper disable once InconsistentNaming public class TTransportFactory { public virtual TTransport GetTransport(TTransport trans) { return trans; } } } thrift-0.16.0/lib/netstd/Thrift/thrift.snk000066400000000000000000000011241420101504100204040ustar00rootroot00000000000000$RSA2hAn,. R}ab |ce5+9\_zY5T$'f{GFiPf_ue0J,ԝWD.9WQ8\Wjeb"2ܢ8M`8eM [oJ8ƈQCGDK& kb|-)Gb>h0Pl>ɀDMqSYU8Fͭ#H@j(7ɨS`8X{Fk3lsJM p~p5KK',K+B%C6+_)>5>qfsG@Z_"k18#w Z#!N@;`W}yiCǓ;WD$;(8~cBӥ=@hRн*Qn73B=W%5_Ű P [X-Qk$o0΍w_Vl$2^mCqUx\˝L| /+T)ڃGI˲ߵÒ#"dthrift-0.16.0/lib/netstd/build.cmd000066400000000000000000000016631420101504100167230ustar00rootroot00000000000000@echo off rem /* rem * Licensed to the Apache Software Foundation (ASF) under one rem * or more contributor license agreements. See the NOTICE file rem * distributed with this work for additional information rem * regarding copyright ownership. The ASF licenses this file rem * to you under the Apache License, Version 2.0 (the rem * "License"); you may not use this file except in compliance rem * with the License. You may obtain a copy of the License at rem * rem * http://www.apache.org/licenses/LICENSE-2.0 rem * rem * Unless required by applicable law or agreed to in writing, rem * software distributed under the License is distributed on an rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY rem * KIND, either express or implied. See the License for the rem * specific language governing permissions and limitations rem * under the License. rem */ setlocal thrift -version dotnet --info dotnet build :eof thrift-0.16.0/lib/netstd/build.sh000066400000000000000000000020271420101504100165650ustar00rootroot00000000000000#!/usr/bin/env bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #exit if any command fails #set -e thrift --version dotnet --info dotnet build #revision=${TRAVIS_JOB_ID:=1} #revision=$(printf "%04d" $revision) #dotnet pack ./src/PROJECT_NAME -c Release -o ./artifacts --version-suffix=$revision thrift-0.16.0/lib/netstd/runtests.cmd000066400000000000000000000020411420101504100175020ustar00rootroot00000000000000@echo off rem /* rem * Licensed to the Apache Software Foundation (ASF) under one rem * or more contributor license agreements. See the NOTICE file rem * distributed with this work for additional information rem * regarding copyright ownership. The ASF licenses this file rem * to you under the Apache License, Version 2.0 (the rem * "License"); you may not use this file except in compliance rem * with the License. You may obtain a copy of the License at rem * rem * http://www.apache.org/licenses/LICENSE-2.0 rem * rem * Unless required by applicable law or agreed to in writing, rem * software distributed under the License is distributed on an rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY rem * KIND, either express or implied. See the License for the rem * specific language governing permissions and limitations rem * under the License. rem */ setlocal thrift -version dotnet --info dotnet test Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj dotnet test Tests\Thrift.Tests\Thrift.Tests.csproj :eof thrift-0.16.0/lib/netstd/runtests.sh000066400000000000000000000017011420101504100173530ustar00rootroot00000000000000#!/usr/bin/env bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # thrift -version dotnet --info dotnet test Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj dotnet test Tests\Thrift.Tests\Thrift.Tests.csprojthrift-0.16.0/lib/nodejs/000077500000000000000000000000001420101504100151125ustar00rootroot00000000000000thrift-0.16.0/lib/nodejs/CMakeLists.txt000066400000000000000000000031341420101504100176530ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # if(NOT NODEJS_INSTALL_DIR) if(IS_ABSOLUTE "${LIB_INSTALL_DIR}") set(NODEJS_INSTALL_DIR "${LIB_INSTALL_DIR}/nodejs") else() set(NODEJS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/nodejs") endif() endif() # Currently no doc #if(IS_ABSOLUTE "${DOC_INSTALL_DIR}") # set(NODEJS_DOC_INSTALL_DIR "${DOC_INSTALL_DIR}/nodejs") #else() # set(NODEJS_DOC_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${DOC_INSTALL_DIR}/nodejs") #endif() add_custom_target(ThriftNodeJS ALL COMMENT "Installing NodeJS dependencies with npm" COMMAND npm install WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../" ) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib/" DESTINATION "${NODEJS_INSTALL_DIR}") #install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/doc/" # DESTINATION "${NODEJS_DOC_INSTALL_DIR}") thrift-0.16.0/lib/nodejs/Makefile.am000077500000000000000000000027321420101504100171550ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # We call npm twice to work around npm issues stubs: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) --gen js:node -o test/ $(top_srcdir)/test/ThriftTest.thrift deps: $(top_srcdir)/package.json $(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/ all-local: deps precross: deps stubs # TODO: Lint nodejs lib and gen-code as part of build check: deps cd $(top_srcdir) && $(NPM) test && $(NPM) run lint-tests && cd lib/nodejs clean-local: $(RM) -r test/gen-* $(RM) -r $(top_srcdir)/node_modules $(RM) -r test/episodic-code-generation-test/gen* $(RM) -r test/episodic-code-generation-test/node_modules EXTRA_DIST = \ examples \ lib \ test \ coding_standards.md \ CMakeLists.txt \ README.md thrift-0.16.0/lib/nodejs/README.md000066400000000000000000000075661420101504100164070ustar00rootroot00000000000000Thrift Node.js Library ========================= License ------- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## Compatibility node version 6 or later is required ## Install npm install thrift ## Thrift Compiler You can compile IDL sources for Node.js with the following command: thrift --gen js:node thrift_file ## Cassandra Client Example: Here is a Cassandra example: ```js var thrift = require('thrift'), Cassandra = require('./gen-nodejs/Cassandra') ttypes = require('./gen-nodejs/cassandra_types'); var connection = thrift.createConnection("localhost", 9160), client = thrift.createClient(Cassandra, connection); connection.on('error', function(err) { console.error(err); }); client.get_slice("Keyspace", "key", new ttypes.ColumnParent({column_family: "ExampleCF"}), new ttypes.SlicePredicate({slice_range: new ttypes.SliceRange({start: '', finish: ''})}), ttypes.ConsistencyLevel.ONE, function(err, data) { if (err) { // handle err } else { // data == [ttypes.ColumnOrSuperColumn, ...] } connection.end(); }); ``` ## Int64 Since JavaScript represents all numbers as doubles, int64 values cannot be accurately represented naturally. To solve this, int64 values in responses will be wrapped with Thrift.Int64 objects. The Int64 implementation used is [broofa/node-int64](https://github.com/broofa/node-int64). ## Client and server examples Several example clients and servers are included in the thrift/lib/nodejs/examples folder and the cross language tutorial thrift/tutorial/nodejs folder. ## Use on browsers You can use code generated with js:node on browsers with Webpack. Here is an example. thrift --gen js:node,ts,es6,with_ns ```javascript import * as thrift from 'thrift'; import { MyServiceClient } from '../gen-nodejs/MyService'; let host = window.location.hostname; let port = 443; let opts = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, headers: { 'Content-Type': 'application/vnd.apache.thrift.json', }, https: true, path: '/url/path', useCORS: true, }; let connection = thrift.createXHRConnection(host, port, opts); let thriftClient = thrift.createXHRClient(MyServiceClient, connection); connection.on('error', (err) => { console.error(err); }); thriftClient.myService(param) .then((result) => { console.log(result); }) .catch((err) => { .... }); ``` Bundlers, like webpack, will use thrift/browser.js by default because of the `"browser": "./lib/nodejs/lib/thrift/browser.js"` field in package.json. ### Browser example with WebSocket, BufferedTransport and BinaryProtocol ```javascript import thrift from 'thrift'; import { MyServiceClient } from '../gen-nodejs/MyService'; const host = window.location.hostname; const port = 9090; const opts = { transport: thrift.TBufferedTransport, protocol: thrift.TBinaryProtocol } const connection = thrift.createWSConnection(host, port, opts); connection.open(); const thriftClient = thrift.createWSClient(MyServiceClient, connection); connection.on('error', (err) => { console.error(err); }); thriftClient.myService(param) .then((result) => { console.log(result); }) .catch((err) => { .... }); ``` thrift-0.16.0/lib/nodejs/coding_standards.md000066400000000000000000000001031420101504100207340ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/nodejs/examples/000077500000000000000000000000001420101504100167305ustar00rootroot00000000000000thrift-0.16.0/lib/nodejs/examples/Makefile000066400000000000000000000017371420101504100204000ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. all: ../../../compiler/cpp/thrift --gen js:node user.thrift server: all NODE_PATH=../lib:../lib/thrift:$(NODE_PATH) node server.js client: all NODE_PATH=../lib:../lib/thrift:$(NODE_PATH) node client.js thrift-0.16.0/lib/nodejs/examples/README.md000066400000000000000000000026201420101504100202070ustar00rootroot00000000000000# Thrift Node.js Examples ## License Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## Running the user example Generate the bindings: ../../../compiler/cpp/thrift --gen js:node user.thrift ../../../compiler/cpp/thrift --gen js:node --gen py hello.thrift To run the user example, first start up the server in one terminal: NODE_PATH=../lib:../lib/thrift node server.js Now run the client: NODE_PATH=../lib:../lib/thrift node client.js For an example using JavaScript in the browser to connect to a node.js server look at hello.html, hello.js and hello.thrift HTTP examples are provided also: httpClient.js and httpServer.js You can test HTTP cross platform with the httpServer.py Python server thrift-0.16.0/lib/nodejs/examples/client.js000066400000000000000000000032161420101504100205460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require('thrift'); var UserStorage = require('./gen-nodejs/UserStorage.js'), ttypes = require('./gen-nodejs/user_types'); var connection = thrift.createConnection('localhost', 9090), client = thrift.createClient(UserStorage, connection); var user = new ttypes.UserProfile({uid: 1, name: "Mark Slee", blurb: "I'll find something to put here."}); connection.on('error', function(err) { console.error(err); }); client.store(user, function(err, response) { if (err) { console.error(err); } else { console.log("client stored:", user.uid); client.retrieve(user.uid, function(err, responseUser) { if (err) { console.error(err); } else { console.log("client retrieved:", responseUser.uid); connection.end(); } }); } }); thrift-0.16.0/lib/nodejs/examples/client_multitransport.js000066400000000000000000000045521420101504100237410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require('thrift'), ttransport = require('thrift/transport'); var UserStorage = require('./gen-nodejs/UserStorage'), ttypes = require('./gen-nodejs/user_types'); var f_conn = thrift.createConnection('localhost', 9090), // default: framed f_client = thrift.createClient(UserStorage, f_conn); var b_conn = thrift.createConnection('localhost', 9091, {transport: ttransport.TBufferedTransport}), b_client = thrift.createClient(UserStorage, b_conn); var user1 = new ttypes.UserProfile({uid: 1, name: "Mark Slee", blurb: "I'll find something to put here."}); var user2 = new ttypes.UserProfile({uid: 2, name: "Satoshi Tagomori", blurb: "ok, let's test with buffered transport."}); f_conn.on('error', function(err) { console.error("framed:", err); }); f_client.store(user1, function(err, response) { if (err) { console.error(err); return; } console.log("stored:", user1.uid, " as ", user1.name); b_client.retrieve(user1.uid, function(err, responseUser) { if (err) { console.error(err); return; } console.log("retrieved:", responseUser.uid, " as ", responseUser.name); }); }); b_client.store(user2, function(err, response) { if (err) { console.error(err); return; } console.log("stored:", user2.uid, " as ", user2.name); f_client.retrieve(user2.uid, function(err, responseUser) { if (err) { console.error(err); return; } console.log("retrieved:", responseUser.uid, " as ", responseUser.name); }); }); thrift-0.16.0/lib/nodejs/examples/hello.html000066400000000000000000000076141420101504100207310ustar00rootroot00000000000000 Apache Thrift JavaScript Browser Client Demo

Apache Thrift JavaScript Browser Client Demo

This html file demonstrates Apache Thrift JavaScrpt RPC between a browser client to a node.js server. Clicking the buttons below will call the RPC functions hosted by the Apache Thrift server at localhost:8585. The file hello.js contains the JavaScript node.js server required. Here are the steps to get the example running:

  1. Install Node.js
    nodejs.org
  2. Install Apache Thrift for node (note that the node package manager will create the node_modules folder in the current directory so make sure to run npm from the same directory as hello.js so that the server can find the Thrift libraries. This example requires Apache Thrift 0.9.2+)
    $ npm install thrift
  3. Compile the hello.idl for JavaScript and Node.js (you'll need to have the Apache Thrift compiler installed for this step. This also needs to be executed in the same directory as hello.js because hello.js and hello.html look for the gen-nodejs and gen-js directories here.)
    $ thrift -gen js -gen js:node hello.thrift
  4. Run the node server in the directory with the hello.html file
    $ node hello.js
  5. Copy the Apache Thrift JavaScript library, thrift.js, into the directory with this html file.
    $ cp ...../thrift.js . (you should be able to use Bower to install the browser based Apache Thrift library in the near future.)
  6. Reload this page in a browser through the node server using using the URL:
    http://localhost:8585/hello.html
    then click a button below to make an RPC call

Server Response:

Server Dbl:

thrift-0.16.0/lib/nodejs/examples/hello.js000066400000000000000000000034631420101504100203770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require('thrift'); var HelloSvc = require('./gen-nodejs/HelloSvc.js'); var TimesTwoSvc = require('./gen-nodejs/TimesTwo.js'); var helloHandler = { hello_func: function(result) { this.call_counter = this.call_counter || 0; console.log("Client call: " + (++this.call_counter)); result(null, "Hello Apache Thrift for JavaScript " + this.call_counter); } } var timesTwoHandler = { dbl: function(val, result) { console.log("Client call: " + val); result(null, val * 2); } } var helloService = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: HelloSvc, handler: helloHandler }; var dblService = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: TimesTwoSvc, handler: timesTwoHandler }; var ServerOptions = { files: ".", services: { "/hello": helloService, "/dbl": dblService, } } var server = thrift.createWebServer(ServerOptions); var port = 8585; server.listen(port); console.log("Http/Thrift Server running on port: " + port); thrift-0.16.0/lib/nodejs/examples/hello.thrift000066400000000000000000000016031420101504100212550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ service HelloSvc { string hello_func(), } service TimesTwo { i64 dbl(1: i64 val), } thrift-0.16.0/lib/nodejs/examples/httpClient.js000066400000000000000000000010611420101504100214020ustar00rootroot00000000000000var thrift = require('thrift'); var helloSvc = require('./gen-nodejs/HelloSvc.js'); var options = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, path: "/hello", headers: {"Connection": "close"}, https: false }; var connection = thrift.createHttpConnection("localhost", 9090, options); var client = thrift.createHttpClient(helloSvc, connection); connection.on("error", function(err) { console.log("Error: " + err); }); client.hello_func(function(error, result) { console.log("Msg from server: " + result); }); thrift-0.16.0/lib/nodejs/examples/httpServer.js000066400000000000000000000020701420101504100214330ustar00rootroot00000000000000var thrift = require('thrift'); var helloSvc = require('./gen-nodejs/HelloSvc'); //ServiceHandler: Implement the hello service var helloHandler = { hello_func: function (result) { console.log("Received Hello call"); result(null, "Hello from Node.js"); } }; //ServiceOptions: The I/O stack for the service var helloSvcOpt = { handler: helloHandler, processor: helloSvc, protocol: thrift.TJSONProtocol, transport: thrift.TBufferedTransport }; //ServerOptions: Define server features var serverOpt = { services: { "/hello": helloSvcOpt } } //Create and start the web server var port = 9090; thrift.createWebServer(serverOpt).listen(port); console.log("Http/Thrift Server running on port: " + port); thrift-0.16.0/lib/nodejs/examples/httpServer.py000066400000000000000000000010121420101504100214420ustar00rootroot00000000000000import sys sys.path.append('gen-py') from hello import HelloSvc from thrift.protocol import TJSONProtocol from thrift.server import THttpServer class HelloSvcHandler: def hello_func(self): print("Hello Called") return "hello from Python" processor = HelloSvc.Processor(HelloSvcHandler()) protoFactory = TJSONProtocol.TJSONProtocolFactory() port = 9090 server = THttpServer.THttpServer(processor, ("localhost", port), protoFactory) print "Python server running on port " + str(port) server.serve() thrift-0.16.0/lib/nodejs/examples/parse.js000066400000000000000000000034321420101504100204020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** This is a standalone deserialize/parse example if you just want to deserialize thrift decoupled from cassandra server 1. acquire thrift template specification files from who ever built it (eg: EXAMPLE.thrift) 2. Install thrift on local machine 3. generate thrift clients for nodejs using template specification files (#1) thrift --gen js:node schema/EXAMPLE.thrift This creates creates gen-node.js directory containing a new file, GENERATED.js 4. Inside GENERATED.js is a class you will want to instanciate. Find this class name and plug it into the example code below (ie, "YOUR_CLASS_NAME") */ function parseThrift(thriftEncodedData, callback) { var thrift = require('thrift'); var transport = new thrift.TFramedTransport(thriftEncodedData); var protocol = new thrift.TBinaryProtocol(transport); var clientClass = require('../gen-nodejs/GENERATED').YOUR_CLASS_NAME; var client = new clientClass(); client.read(protocol); callback(null, client); } thrift-0.16.0/lib/nodejs/examples/server.js000066400000000000000000000024011420101504100205710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require('thrift'); var UserStorage = require('./gen-nodejs/UserStorage.js'), ttypes = require('./gen-nodejs/user_types'); var users = {}; var server = thrift.createServer(UserStorage, { store: function(user, result) { console.log("server stored:", user.uid); users[user.uid] = user; result(null); }, retrieve: function(uid, result) { console.log("server retrieved:", uid); result(null, users[uid]); }, }); server.listen(9090); thrift-0.16.0/lib/nodejs/examples/server_http.js000066400000000000000000000031651420101504100216400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var connect = require('connect'); var thrift = require('thrift'); var UserStorage = require('./gen-nodejs/UserStorage'), ttypes = require('./gen-nodejs/user_types'); var users = {}; var store = function(user, result) { console.log("stored:", user.uid); users[user.uid] = user; result(null); }; var retrieve = function(uid, result) { console.log("retrieved:", uid); result(null, users[uid]); }; var server_http = thrift.createHttpServer(UserStorage, { store: store, retrieve: retrieve }); server_http.listen(9090); var server_connect = connect(thrift.httpMiddleware(UserStorage, { store: store, retrieve: retrieve })); server_http.listen(9091); var server_connect_json = connect(thrift.httpMiddleware(UserStorage, { store: store, retrieve: retrieve }, {protocol: thrift.TJSONProtocol})); server_connect_json.listen(9092); thrift-0.16.0/lib/nodejs/examples/server_multitransport.js000066400000000000000000000027621420101504100237720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require('thrift'), ttransport = require('thrift/transport'); var UserStorage = require('./gen-nodejs/UserStorage'), ttypes = require('./gen-nodejs/user_types'); var users = {}; var store = function(user, result) { console.log("stored:", user.uid); users[user.uid] = user; result(null); }; var retrieve = function(uid, result) { console.log("retrieved:", uid); result(null, users[uid]); }; var server_framed = thrift.createServer(UserStorage, { store: store, retrieve: retrieve }); server_framed.listen(9090); var server_buffered = thrift.createServer(UserStorage, { store: store, retrieve: retrieve }, {transport: ttransport.TBufferedTransport}); server_buffered.listen(9091); thrift-0.16.0/lib/nodejs/examples/user.thrift000066400000000000000000000016661420101504100211410ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. struct UserProfile { 1: i32 uid, 2: string name, 3: string blurb } service UserStorage { void store(1: UserProfile user), UserProfile retrieve(1: i32 uid) } thrift-0.16.0/lib/nodejs/lib/000077500000000000000000000000001420101504100156605ustar00rootroot00000000000000thrift-0.16.0/lib/nodejs/lib/thrift/000077500000000000000000000000001420101504100171605ustar00rootroot00000000000000thrift-0.16.0/lib/nodejs/lib/thrift/binary.js000066400000000000000000000071151420101504100210060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var POW_8 = Math.pow(2, 8); var POW_16 = Math.pow(2, 16); var POW_24 = Math.pow(2, 24); var POW_32 = Math.pow(2, 32); var POW_40 = Math.pow(2, 40); var POW_48 = Math.pow(2, 48); var POW_52 = Math.pow(2, 52); var POW_1022 = Math.pow(2, 1022); exports.readByte = function(b){ return b > 127 ? b-256 : b; }; exports.readI16 = function(buff, off) { off = off || 0; var v = buff[off + 1]; v += buff[off] << 8; if (buff[off] & 128) { v -= POW_16; } return v; }; exports.readI32 = function(buff, off) { off = off || 0; var v = buff[off + 3]; v += buff[off + 2] << 8; v += buff[off + 1] << 16; v += buff[off] * POW_24; if (buff[off] & 0x80) { v -= POW_32; } return v; }; exports.writeI16 = function(buff, v) { buff[1] = v & 0xff; v >>= 8; buff[0] = v & 0xff; return buff; }; exports.writeI32 = function(buff, v) { buff[3] = v & 0xff; v >>= 8; buff[2] = v & 0xff; v >>= 8; buff[1] = v & 0xff; v >>= 8; buff[0] = v & 0xff; return buff; }; exports.readDouble = function(buff, off) { off = off || 0; var signed = buff[off] & 0x80; var e = (buff[off+1] & 0xF0) >> 4; e += (buff[off] & 0x7F) << 4; var m = buff[off+7]; m += buff[off+6] << 8; m += buff[off+5] << 16; m += buff[off+4] * POW_24; m += buff[off+3] * POW_32; m += buff[off+2] * POW_40; m += (buff[off+1] & 0x0F) * POW_48; switch (e) { case 0: e = -1022; break; case 2047: return m ? NaN : (signed ? -Infinity : Infinity); default: m += POW_52; e -= 1023; } if (signed) { m *= -1; } return m * Math.pow(2, e - 52); }; /* * Based on code from the jspack module: * http://code.google.com/p/jspack/ */ exports.writeDouble = function(buff, v) { var m, e, c; buff[0] = (v < 0 ? 0x80 : 0x00); v = Math.abs(v); if (v !== v) { // NaN, use QNaN IEEE format m = 2251799813685248; e = 2047; } else if (v === Infinity) { m = 0; e = 2047; } else { e = Math.floor(Math.log(v) / Math.LN2); c = Math.pow(2, -e); if (v * c < 1) { e--; c *= 2; } if (e + 1023 >= 2047) { // Overflow m = 0; e = 2047; } else if (e + 1023 >= 1) { // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow m = (v*c-1) * POW_52; e += 1023; } else { // Denormalized - also catches the '0' case, somewhat by chance m = (v * POW_1022) * POW_52; e = 0; } } buff[1] = (e << 4) & 0xf0; buff[0] |= (e >> 4) & 0x7f; buff[7] = m & 0xff; m = Math.floor(m / POW_8); buff[6] = m & 0xff; m = Math.floor(m / POW_8); buff[5] = m & 0xff; m = Math.floor(m / POW_8); buff[4] = m & 0xff; m >>= 8; buff[3] = m & 0xff; m >>= 8; buff[2] = m & 0xff; m >>= 8; buff[1] |= m & 0x0f; return buff; }; thrift-0.16.0/lib/nodejs/lib/thrift/binary_protocol.js000066400000000000000000000230331420101504100227240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var log = require('./log'); var binary = require('./binary'); var Int64 = require('node-int64'); var Thrift = require('./thrift'); var Type = Thrift.Type; module.exports = TBinaryProtocol; // JavaScript supports only numeric doubles, therefore even hex values are always signed. // The largest integer value which can be represented in JavaScript is +/-2^53. // Bitwise operations convert numbers to 32 bit integers but perform sign extension // upon assigning values back to variables. var VERSION_MASK = -65536, // 0xffff0000 VERSION_1 = -2147418112, // 0x80010000 TYPE_MASK = 0x000000ff; TBinaryProtocol.VERSION_MASK = VERSION_MASK; TBinaryProtocol.VERSION_1 = VERSION_1; TBinaryProtocol.TYPE_MASK = TYPE_MASK function TBinaryProtocol(trans, strictRead, strictWrite) { this.trans = trans; this.strictRead = (strictRead !== undefined ? strictRead : false); this.strictWrite = (strictWrite !== undefined ? strictWrite : true); this._seqid = null; }; TBinaryProtocol.prototype.flush = function() { return this.trans.flush(); }; TBinaryProtocol.prototype.writeMessageBegin = function(name, type, seqid) { if (this.strictWrite) { this.writeI32(VERSION_1 | type); this.writeString(name); this.writeI32(seqid); } else { this.writeString(name); this.writeByte(type); this.writeI32(seqid); } // Record client seqid to find callback again if (this._seqid !== null) { log.warning('SeqId already set', { 'name': name }); } else { this._seqid = seqid; this.trans.setCurrSeqId(seqid); } }; TBinaryProtocol.prototype.writeMessageEnd = function() { if (this._seqid !== null) { this._seqid = null; } else { log.warning('No seqid to unset'); } }; TBinaryProtocol.prototype.writeStructBegin = function(name) { }; TBinaryProtocol.prototype.writeStructEnd = function() { }; TBinaryProtocol.prototype.writeFieldBegin = function(name, type, id) { this.writeByte(type); this.writeI16(id); }; TBinaryProtocol.prototype.writeFieldEnd = function() { }; TBinaryProtocol.prototype.writeFieldStop = function() { this.writeByte(Type.STOP); }; TBinaryProtocol.prototype.writeMapBegin = function(ktype, vtype, size) { this.writeByte(ktype); this.writeByte(vtype); this.writeI32(size); }; TBinaryProtocol.prototype.writeMapEnd = function() { }; TBinaryProtocol.prototype.writeListBegin = function(etype, size) { this.writeByte(etype); this.writeI32(size); }; TBinaryProtocol.prototype.writeListEnd = function() { }; TBinaryProtocol.prototype.writeSetBegin = function(etype, size) { this.writeByte(etype); this.writeI32(size); }; TBinaryProtocol.prototype.writeSetEnd = function() { }; TBinaryProtocol.prototype.writeBool = function(bool) { if (bool) { this.writeByte(1); } else { this.writeByte(0); } }; TBinaryProtocol.prototype.writeByte = function(b) { this.trans.write(new Buffer([b])); }; TBinaryProtocol.prototype.writeI16 = function(i16) { this.trans.write(binary.writeI16(new Buffer(2), i16)); }; TBinaryProtocol.prototype.writeI32 = function(i32) { this.trans.write(binary.writeI32(new Buffer(4), i32)); }; TBinaryProtocol.prototype.writeI64 = function(i64) { if (i64.buffer) { this.trans.write(i64.buffer); } else { this.trans.write(new Int64(i64).buffer); } }; TBinaryProtocol.prototype.writeDouble = function(dub) { this.trans.write(binary.writeDouble(new Buffer(8), dub)); }; TBinaryProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) { if (typeof(arg) === 'string') { this.writeI32(Buffer.byteLength(arg, encoding)); this.trans.write(new Buffer(arg, encoding)); } else if ((arg instanceof Buffer) || (Object.prototype.toString.call(arg) == '[object Uint8Array]')) { // Buffers in Node.js under Browserify may extend UInt8Array instead of // defining a new object. We detect them here so we can write them // correctly this.writeI32(arg.length); this.trans.write(arg); } else { throw new Error(name + ' called without a string/Buffer argument: ' + arg); } }; TBinaryProtocol.prototype.writeString = function(arg) { this.writeStringOrBinary('writeString', 'utf8', arg); }; TBinaryProtocol.prototype.writeBinary = function(arg) { this.writeStringOrBinary('writeBinary', 'binary', arg); }; TBinaryProtocol.prototype.readMessageBegin = function() { var sz = this.readI32(); var type, name, seqid; if (sz < 0) { var version = sz & VERSION_MASK; if (version != VERSION_1) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad version in readMessageBegin: " + sz); } type = sz & TYPE_MASK; name = this.readString(); seqid = this.readI32(); } else { if (this.strictRead) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "No protocol version header"); } name = this.trans.read(sz); type = this.readByte(); seqid = this.readI32(); } return {fname: name, mtype: type, rseqid: seqid}; }; TBinaryProtocol.prototype.readMessageEnd = function() { }; TBinaryProtocol.prototype.readStructBegin = function() { return {fname: ''}; }; TBinaryProtocol.prototype.readStructEnd = function() { }; TBinaryProtocol.prototype.readFieldBegin = function() { var type = this.readByte(); if (type == Type.STOP) { return {fname: null, ftype: type, fid: 0}; } var id = this.readI16(); return {fname: null, ftype: type, fid: id}; }; TBinaryProtocol.prototype.readFieldEnd = function() { }; TBinaryProtocol.prototype.readMapBegin = function() { var ktype = this.readByte(); var vtype = this.readByte(); var size = this.readI32(); return {ktype: ktype, vtype: vtype, size: size}; }; TBinaryProtocol.prototype.readMapEnd = function() { }; TBinaryProtocol.prototype.readListBegin = function() { var etype = this.readByte(); var size = this.readI32(); return {etype: etype, size: size}; }; TBinaryProtocol.prototype.readListEnd = function() { }; TBinaryProtocol.prototype.readSetBegin = function() { var etype = this.readByte(); var size = this.readI32(); return {etype: etype, size: size}; }; TBinaryProtocol.prototype.readSetEnd = function() { }; TBinaryProtocol.prototype.readBool = function() { var b = this.readByte(); if (b === 0) { return false; } return true; }; TBinaryProtocol.prototype.readByte = function() { return this.trans.readByte(); }; TBinaryProtocol.prototype.readI16 = function() { return this.trans.readI16(); }; TBinaryProtocol.prototype.readI32 = function() { return this.trans.readI32(); }; TBinaryProtocol.prototype.readI64 = function() { var buff = this.trans.read(8); return new Int64(buff); }; TBinaryProtocol.prototype.readDouble = function() { return this.trans.readDouble(); }; TBinaryProtocol.prototype.readBinary = function() { var len = this.readI32(); if (len === 0) { return new Buffer(0); } if (len < 0) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative binary size"); } return this.trans.read(len); }; TBinaryProtocol.prototype.readString = function() { var len = this.readI32(); if (len === 0) { return ""; } if (len < 0) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative string size"); } return this.trans.readString(len); }; TBinaryProtocol.prototype.getTransport = function() { return this.trans; }; TBinaryProtocol.prototype.skip = function(type) { switch (type) { case Type.BOOL: this.readBool(); break; case Type.BYTE: this.readByte(); break; case Type.I16: this.readI16(); break; case Type.I32: this.readI32(); break; case Type.I64: this.readI64(); break; case Type.DOUBLE: this.readDouble(); break; case Type.STRING: this.readString(); break; case Type.STRUCT: this.readStructBegin(); while (true) { var r = this.readFieldBegin(); if (r.ftype === Type.STOP) { break; } this.skip(r.ftype); this.readFieldEnd(); } this.readStructEnd(); break; case Type.MAP: var mapBegin = this.readMapBegin(); for (var i = 0; i < mapBegin.size; ++i) { this.skip(mapBegin.ktype); this.skip(mapBegin.vtype); } this.readMapEnd(); break; case Type.SET: var setBegin = this.readSetBegin(); for (var i2 = 0; i2 < setBegin.size; ++i2) { this.skip(setBegin.etype); } this.readSetEnd(); break; case Type.LIST: var listBegin = this.readListBegin(); for (var i3 = 0; i3 < listBegin.size; ++i3) { this.skip(listBegin.etype); } this.readListEnd(); break; default: throw new Error("Invalid type: " + type); } }; thrift-0.16.0/lib/nodejs/lib/thrift/browser.js000066400000000000000000000036261420101504100212100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ exports.Thrift = require('./thrift'); var wsConnection = require('./ws_connection'); exports.WSConnection = wsConnection.WSConnection; exports.createWSConnection = wsConnection.createWSConnection; exports.createWSClient = wsConnection.createWSClient; var xhrConnection = require('./xhr_connection'); exports.XHRConnection = xhrConnection.XHRConnection; exports.createXHRConnection = xhrConnection.createXHRConnection; exports.createXHRClient = xhrConnection.createXHRClient; exports.Int64 = require('node-int64'); exports.Q = require('q'); var mpxProtocol = require('./multiplexed_protocol'); exports.Multiplexer = mpxProtocol.Multiplexer; /* * Export transport and protocol so they can be used outside of a * cassandra/server context */ exports.TBufferedTransport = require('./buffered_transport'); exports.TFramedTransport = require('./framed_transport'); exports.TWebSocketTransport = require('./ws_transport'); exports.Protocol = require('./json_protocol'); exports.TJSONProtocol = require('./json_protocol'); exports.TBinaryProtocol = require('./binary_protocol'); exports.TCompactProtocol = require('./compact_protocol'); thrift-0.16.0/lib/nodejs/lib/thrift/buffered_transport.js000066400000000000000000000122231420101504100234140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var binary = require('./binary'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); var THeaderTransport = require('./header_transport'); module.exports = TBufferedTransport; function TBufferedTransport(buffer, callback) { this.defaultReadBufferSize = 1024; this.writeBufferSize = 512; // Soft Limit this.inBuf = new Buffer(this.defaultReadBufferSize); this.readCursor = 0; this.writeCursor = 0; // for input buffer this.outBuffers = []; this.outCount = 0; this.onFlush = callback; }; TBufferedTransport.prototype = new THeaderTransport(); TBufferedTransport.prototype.reset = function() { this.inBuf = new Buffer(this.defaultReadBufferSize); this.readCursor = 0; this.writeCursor = 0; this.outBuffers = []; this.outCount = 0; } TBufferedTransport.receiver = function(callback, seqid) { var reader = new TBufferedTransport(); return function(data) { if (reader.writeCursor + data.length > reader.inBuf.length) { var buf = new Buffer(reader.writeCursor + data.length); reader.inBuf.copy(buf, 0, 0, reader.writeCursor); reader.inBuf = buf; } data.copy(reader.inBuf, reader.writeCursor, 0); reader.writeCursor += data.length; callback(reader, seqid); }; }; TBufferedTransport.prototype.commitPosition = function(){ var unreadSize = this.writeCursor - this.readCursor; var bufSize = (unreadSize * 2 > this.defaultReadBufferSize) ? unreadSize * 2 : this.defaultReadBufferSize; var buf = new Buffer(bufSize); if (unreadSize > 0) { this.inBuf.copy(buf, 0, this.readCursor, this.writeCursor); } this.readCursor = 0; this.writeCursor = unreadSize; this.inBuf = buf; }; TBufferedTransport.prototype.rollbackPosition = function(){ this.readCursor = 0; } // TODO: Implement open/close support TBufferedTransport.prototype.isOpen = function() { return true; }; TBufferedTransport.prototype.open = function() { }; TBufferedTransport.prototype.close = function() { }; // Set the seqid of the message in the client // So that callbacks can be found TBufferedTransport.prototype.setCurrSeqId = function(seqid) { this._seqid = seqid; }; TBufferedTransport.prototype.ensureAvailable = function(len) { if (this.readCursor + len > this.writeCursor) { throw new InputBufferUnderrunError(); } }; TBufferedTransport.prototype.read = function(len) { this.ensureAvailable(len); var buf = new Buffer(len); this.inBuf.copy(buf, 0, this.readCursor, this.readCursor + len); this.readCursor += len; return buf; }; TBufferedTransport.prototype.readByte = function() { this.ensureAvailable(1); return binary.readByte(this.inBuf[this.readCursor++]); }; TBufferedTransport.prototype.readI16 = function() { this.ensureAvailable(2); var i16 = binary.readI16(this.inBuf, this.readCursor); this.readCursor += 2; return i16; }; TBufferedTransport.prototype.readI32 = function() { this.ensureAvailable(4); var i32 = binary.readI32(this.inBuf, this.readCursor); this.readCursor += 4; return i32; }; TBufferedTransport.prototype.readDouble = function() { this.ensureAvailable(8); var d = binary.readDouble(this.inBuf, this.readCursor); this.readCursor += 8; return d; }; TBufferedTransport.prototype.readString = function(len) { this.ensureAvailable(len); var str = this.inBuf.toString('utf8', this.readCursor, this.readCursor + len); this.readCursor += len; return str; }; TBufferedTransport.prototype.borrow = function() { var obj = {buf: this.inBuf, readIndex: this.readCursor, writeIndex: this.writeCursor}; return obj; }; TBufferedTransport.prototype.consume = function(bytesConsumed) { this.readCursor += bytesConsumed; }; TBufferedTransport.prototype.write = function(buf) { if (typeof(buf) === "string") { buf = new Buffer(buf, 'utf8'); } this.outBuffers.push(buf); this.outCount += buf.length; }; TBufferedTransport.prototype.flush = function() { // If the seqid of the callback is available pass it to the onFlush // Then remove the current seqid var seqid = this._seqid; this._seqid = null; if (this.outCount < 1) { return; } var msg = new Buffer(this.outCount), pos = 0; this.outBuffers.forEach(function(buf) { buf.copy(msg, pos, 0); pos += buf.length; }); if (this.onFlush) { // Passing seqid through this call to get it to the connection this.onFlush(msg, seqid); } this.outBuffers = []; this.outCount = 0; } thrift-0.16.0/lib/nodejs/lib/thrift/compact_protocol.js000066400000000000000000000625671420101504100231050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var log = require('./log'); var Int64 = require('node-int64'); var Thrift = require('./thrift'); var Type = Thrift.Type; module.exports = TCompactProtocol; var POW_8 = Math.pow(2, 8); var POW_24 = Math.pow(2, 24); var POW_32 = Math.pow(2, 32); var POW_40 = Math.pow(2, 40); var POW_48 = Math.pow(2, 48); var POW_52 = Math.pow(2, 52); var POW_1022 = Math.pow(2, 1022); /** * Constructor Function for the Compact Protocol. * @constructor * @param {object} [trans] - The underlying transport to read/write. * @classdesc The Apache Thrift Protocol layer performs serialization * of base types, the compact protocol serializes data in binary * form with minimal space used for scalar values. */ function TCompactProtocol(trans) { this.trans = trans; this.lastField_ = []; this.lastFieldId_ = 0; this.string_limit_ = 0; this.string_buf_ = null; this.string_buf_size_ = 0; this.container_limit_ = 0; this.booleanField_ = { name: null, hasBoolValue: false }; this.boolValue_ = { hasBoolValue: false, boolValue: false }; }; // // Compact Protocol Constants // /** * Compact Protocol ID number. * @readonly * @const {number} PROTOCOL_ID */ TCompactProtocol.PROTOCOL_ID = -126; //1000 0010 /** * Compact Protocol version number. * @readonly * @const {number} VERSION_N */ TCompactProtocol.VERSION_N = 1; /** * Compact Protocol version mask for combining protocol version and message type in one byte. * @readonly * @const {number} VERSION_MASK */ TCompactProtocol.VERSION_MASK = 0x1f; //0001 1111 /** * Compact Protocol message type mask for combining protocol version and message type in one byte. * @readonly * @const {number} TYPE_MASK */ TCompactProtocol.TYPE_MASK = -32; //1110 0000 /** * Compact Protocol message type bits for ensuring message type bit size. * @readonly * @const {number} TYPE_BITS */ TCompactProtocol.TYPE_BITS = 7; //0000 0111 /** * Compact Protocol message type shift amount for combining protocol version and message type in one byte. * @readonly * @const {number} TYPE_SHIFT_AMOUNT */ TCompactProtocol.TYPE_SHIFT_AMOUNT = 5; /** * Compact Protocol type IDs used to keep type data within one nibble. * @readonly * @property {number} CT_STOP - End of a set of fields. * @property {number} CT_BOOLEAN_TRUE - Flag for Boolean field with true value (packed field and value). * @property {number} CT_BOOLEAN_FALSE - Flag for Boolean field with false value (packed field and value). * @property {number} CT_BYTE - Signed 8 bit integer. * @property {number} CT_I16 - Signed 16 bit integer. * @property {number} CT_I32 - Signed 32 bit integer. * @property {number} CT_I64 - Signed 64 bit integer (2^53 max in JavaScript). * @property {number} CT_DOUBLE - 64 bit IEEE 854 floating point. * @property {number} CT_BINARY - Array of bytes (used for strings also). * @property {number} CT_LIST - A collection type (unordered). * @property {number} CT_SET - A collection type (unordered and without repeated values). * @property {number} CT_MAP - A collection type (map/associative-array/dictionary). * @property {number} CT_STRUCT - A multifield type. */ TCompactProtocol.Types = { CT_STOP: 0x00, CT_BOOLEAN_TRUE: 0x01, CT_BOOLEAN_FALSE: 0x02, CT_BYTE: 0x03, CT_I16: 0x04, CT_I32: 0x05, CT_I64: 0x06, CT_DOUBLE: 0x07, CT_BINARY: 0x08, CT_LIST: 0x09, CT_SET: 0x0A, CT_MAP: 0x0B, CT_STRUCT: 0x0C }; /** * Array mapping Compact type IDs to standard Thrift type IDs. * @readonly */ TCompactProtocol.TTypeToCType = [ TCompactProtocol.Types.CT_STOP, // T_STOP 0, // unused TCompactProtocol.Types.CT_BOOLEAN_TRUE, // T_BOOL TCompactProtocol.Types.CT_BYTE, // T_BYTE TCompactProtocol.Types.CT_DOUBLE, // T_DOUBLE 0, // unused TCompactProtocol.Types.CT_I16, // T_I16 0, // unused TCompactProtocol.Types.CT_I32, // T_I32 0, // unused TCompactProtocol.Types.CT_I64, // T_I64 TCompactProtocol.Types.CT_BINARY, // T_STRING TCompactProtocol.Types.CT_STRUCT, // T_STRUCT TCompactProtocol.Types.CT_MAP, // T_MAP TCompactProtocol.Types.CT_SET, // T_SET TCompactProtocol.Types.CT_LIST, // T_LIST ]; // // Compact Protocol Utilities // /** * Returns the underlying transport layer. * @return {object} The underlying transport layer. */TCompactProtocol.prototype.getTransport = function() { return this.trans; }; /** * Lookup a Compact Protocol Type value for a given Thrift Type value. * N.B. Used only internally. * @param {number} ttype - Thrift type value * @returns {number} Compact protocol type value */ TCompactProtocol.prototype.getCompactType = function(ttype) { return TCompactProtocol.TTypeToCType[ttype]; }; /** * Lookup a Thrift Type value for a given Compact Protocol Type value. * N.B. Used only internally. * @param {number} type - Compact Protocol type value * @returns {number} Thrift Type value */ TCompactProtocol.prototype.getTType = function(type) { switch (type) { case Type.STOP: return Type.STOP; case TCompactProtocol.Types.CT_BOOLEAN_FALSE: case TCompactProtocol.Types.CT_BOOLEAN_TRUE: return Type.BOOL; case TCompactProtocol.Types.CT_BYTE: return Type.BYTE; case TCompactProtocol.Types.CT_I16: return Type.I16; case TCompactProtocol.Types.CT_I32: return Type.I32; case TCompactProtocol.Types.CT_I64: return Type.I64; case TCompactProtocol.Types.CT_DOUBLE: return Type.DOUBLE; case TCompactProtocol.Types.CT_BINARY: return Type.STRING; case TCompactProtocol.Types.CT_LIST: return Type.LIST; case TCompactProtocol.Types.CT_SET: return Type.SET; case TCompactProtocol.Types.CT_MAP: return Type.MAP; case TCompactProtocol.Types.CT_STRUCT: return Type.STRUCT; default: throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Unknown type: " + type); } return Type.STOP; }; // // Compact Protocol write operations // /** * Send any buffered bytes to the end point. */ TCompactProtocol.prototype.flush = function() { return this.trans.flush(); }; /** * Writes an RPC message header * @param {string} name - The method name for the message. * @param {number} type - The type of message (CALL, REPLY, EXCEPTION, ONEWAY). * @param {number} seqid - The call sequence number (if any). */ TCompactProtocol.prototype.writeMessageBegin = function(name, type, seqid) { this.writeByte(TCompactProtocol.PROTOCOL_ID); this.writeByte((TCompactProtocol.VERSION_N & TCompactProtocol.VERSION_MASK) | ((type << TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_MASK)); this.writeVarint32(seqid); this.writeString(name); // Record client seqid to find callback again if (this._seqid) { log.warning('SeqId already set', { 'name': name }); } else { this._seqid = seqid; this.trans.setCurrSeqId(seqid); } }; TCompactProtocol.prototype.writeMessageEnd = function() { }; TCompactProtocol.prototype.writeStructBegin = function(name) { this.lastField_.push(this.lastFieldId_); this.lastFieldId_ = 0; }; TCompactProtocol.prototype.writeStructEnd = function() { this.lastFieldId_ = this.lastField_.pop(); }; /** * Writes a struct field header * @param {string} name - The field name (not written with the compact protocol). * @param {number} type - The field data type (a normal Thrift field Type). * @param {number} id - The IDL field Id. */ TCompactProtocol.prototype.writeFieldBegin = function(name, type, id) { if (type != Type.BOOL) { return this.writeFieldBeginInternal(name, type, id, -1); } this.booleanField_.name = name; this.booleanField_.fieldType = type; this.booleanField_.fieldId = id; }; TCompactProtocol.prototype.writeFieldEnd = function() { }; TCompactProtocol.prototype.writeFieldStop = function() { this.writeByte(TCompactProtocol.Types.CT_STOP); }; /** * Writes a map collection header * @param {number} keyType - The Thrift type of the map keys. * @param {number} valType - The Thrift type of the map values. * @param {number} size - The number of k/v pairs in the map. */ TCompactProtocol.prototype.writeMapBegin = function(keyType, valType, size) { if (size === 0) { this.writeByte(0); } else { this.writeVarint32(size); this.writeByte(this.getCompactType(keyType) << 4 | this.getCompactType(valType)); } }; TCompactProtocol.prototype.writeMapEnd = function() { }; /** * Writes a list collection header * @param {number} elemType - The Thrift type of the list elements. * @param {number} size - The number of elements in the list. */ TCompactProtocol.prototype.writeListBegin = function(elemType, size) { this.writeCollectionBegin(elemType, size); }; TCompactProtocol.prototype.writeListEnd = function() { }; /** * Writes a set collection header * @param {number} elemType - The Thrift type of the set elements. * @param {number} size - The number of elements in the set. */ TCompactProtocol.prototype.writeSetBegin = function(elemType, size) { this.writeCollectionBegin(elemType, size); }; TCompactProtocol.prototype.writeSetEnd = function() { }; TCompactProtocol.prototype.writeBool = function(value) { if (this.booleanField_.name !== null) { // we haven't written the field header yet this.writeFieldBeginInternal(this.booleanField_.name, this.booleanField_.fieldType, this.booleanField_.fieldId, (value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE : TCompactProtocol.Types.CT_BOOLEAN_FALSE)); this.booleanField_.name = null; } else { // we're not part of a field, so just write the value this.writeByte((value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE : TCompactProtocol.Types.CT_BOOLEAN_FALSE)); } }; TCompactProtocol.prototype.writeByte = function(b) { this.trans.write(new Buffer([b])); }; TCompactProtocol.prototype.writeI16 = function(i16) { this.writeVarint32(this.i32ToZigzag(i16)); }; TCompactProtocol.prototype.writeI32 = function(i32) { this.writeVarint32(this.i32ToZigzag(i32)); }; TCompactProtocol.prototype.writeI64 = function(i64) { this.writeVarint64(this.i64ToZigzag(i64)); }; // Little-endian, unlike TBinaryProtocol TCompactProtocol.prototype.writeDouble = function(v) { var buff = new Buffer(8); var m, e, c; buff[7] = (v < 0 ? 0x80 : 0x00); v = Math.abs(v); if (v !== v) { // NaN, use QNaN IEEE format m = 2251799813685248; e = 2047; } else if (v === Infinity) { m = 0; e = 2047; } else { e = Math.floor(Math.log(v) / Math.LN2); c = Math.pow(2, -e); if (v * c < 1) { e--; c *= 2; } if (e + 1023 >= 2047) { // Overflow m = 0; e = 2047; } else if (e + 1023 >= 1) { // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow m = (v*c-1) * POW_52; e += 1023; } else { // Denormalized - also catches the '0' case, somewhat by chance m = (v * POW_1022) * POW_52; e = 0; } } buff[6] = (e << 4) & 0xf0; buff[7] |= (e >> 4) & 0x7f; buff[0] = m & 0xff; m = Math.floor(m / POW_8); buff[1] = m & 0xff; m = Math.floor(m / POW_8); buff[2] = m & 0xff; m = Math.floor(m / POW_8); buff[3] = m & 0xff; m >>= 8; buff[4] = m & 0xff; m >>= 8; buff[5] = m & 0xff; m >>= 8; buff[6] |= m & 0x0f; this.trans.write(buff); }; TCompactProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) { if (typeof arg === 'string') { this.writeVarint32(Buffer.byteLength(arg, encoding)) ; this.trans.write(new Buffer(arg, encoding)); } else if (arg instanceof Buffer || Object.prototype.toString.call(arg) == '[object Uint8Array]') { // Buffers in Node.js under Browserify may extend UInt8Array instead of // defining a new object. We detect them here so we can write them // correctly this.writeVarint32(arg.length); this.trans.write(arg); } else { throw new Error(name + ' called without a string/Buffer argument: ' + arg); } }; TCompactProtocol.prototype.writeString = function(arg) { this.writeStringOrBinary('writeString', 'utf8', arg); }; TCompactProtocol.prototype.writeBinary = function(arg) { this.writeStringOrBinary('writeBinary', 'binary', arg); }; // // Compact Protocol internal write methods // TCompactProtocol.prototype.writeFieldBeginInternal = function(name, fieldType, fieldId, typeOverride) { //If there's a type override, use that. var typeToWrite = (typeOverride == -1 ? this.getCompactType(fieldType) : typeOverride); //Check if we can delta encode the field id if (fieldId > this.lastFieldId_ && fieldId - this.lastFieldId_ <= 15) { //Include the type delta with the field ID this.writeByte((fieldId - this.lastFieldId_) << 4 | typeToWrite); } else { //Write separate type and ID values this.writeByte(typeToWrite); this.writeI16(fieldId); } this.lastFieldId_ = fieldId; }; TCompactProtocol.prototype.writeCollectionBegin = function(elemType, size) { if (size <= 14) { //Combine size and type in one byte if possible this.writeByte(size << 4 | this.getCompactType(elemType)); } else { this.writeByte(0xf0 | this.getCompactType(elemType)); this.writeVarint32(size); } }; /** * Write an i32 as a varint. Results in 1-5 bytes on the wire. */ TCompactProtocol.prototype.writeVarint32 = function(n) { var buf = new Buffer(5); var wsize = 0; while (true) { if ((n & ~0x7F) === 0) { buf[wsize++] = n; break; } else { buf[wsize++] = ((n & 0x7F) | 0x80); n = n >>> 7; } } var wbuf = new Buffer(wsize); buf.copy(wbuf,0,0,wsize); this.trans.write(wbuf); }; /** * Write an i64 as a varint. Results in 1-10 bytes on the wire. * N.B. node-int64 is always big endian */ TCompactProtocol.prototype.writeVarint64 = function(n) { if (typeof n === "number"){ n = new Int64(n); } if (! (n instanceof Int64)) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + n); } var buf = new Buffer(10); var wsize = 0; var hi = n.buffer.readUInt32BE(0, true); var lo = n.buffer.readUInt32BE(4, true); var mask = 0; while (true) { if (((lo & ~0x7F) === 0) && (hi === 0)) { buf[wsize++] = lo; break; } else { buf[wsize++] = ((lo & 0x7F) | 0x80); mask = hi << 25; lo = lo >>> 7; hi = hi >>> 7; lo = lo | mask; } } var wbuf = new Buffer(wsize); buf.copy(wbuf,0,0,wsize); this.trans.write(wbuf); }; /** * Convert l into a zigzag long. This allows negative numbers to be * represented compactly as a varint. */ TCompactProtocol.prototype.i64ToZigzag = function(l) { if (typeof l === 'string') { l = new Int64(parseInt(l, 10)); } else if (typeof l === 'number') { l = new Int64(l); } if (! (l instanceof Int64)) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + l); } var hi = l.buffer.readUInt32BE(0, true); var lo = l.buffer.readUInt32BE(4, true); var sign = hi >>> 31; hi = ((hi << 1) | (lo >>> 31)) ^ ((!!sign) ? 0xFFFFFFFF : 0); lo = (lo << 1) ^ ((!!sign) ? 0xFFFFFFFF : 0); return new Int64(hi, lo); }; /** * Convert n into a zigzag int. This allows negative numbers to be * represented compactly as a varint. */ TCompactProtocol.prototype.i32ToZigzag = function(n) { return (n << 1) ^ ((n & 0x80000000) ? 0xFFFFFFFF : 0); }; // // Compact Protocol read operations // TCompactProtocol.prototype.readMessageBegin = function() { //Read protocol ID var protocolId = this.trans.readByte(); if (protocolId != TCompactProtocol.PROTOCOL_ID) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol identifier " + protocolId); } //Read Version and Type var versionAndType = this.trans.readByte(); var version = (versionAndType & TCompactProtocol.VERSION_MASK); if (version != TCompactProtocol.VERSION_N) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol version " + version); } var type = ((versionAndType >> TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_BITS); //Read SeqId var seqid = this.readVarint32(); //Read name var name = this.readString(); return {fname: name, mtype: type, rseqid: seqid}; }; TCompactProtocol.prototype.readMessageEnd = function() { }; TCompactProtocol.prototype.readStructBegin = function() { this.lastField_.push(this.lastFieldId_); this.lastFieldId_ = 0; return {fname: ''}; }; TCompactProtocol.prototype.readStructEnd = function() { this.lastFieldId_ = this.lastField_.pop(); }; TCompactProtocol.prototype.readFieldBegin = function() { var fieldId = 0; var b = this.trans.readByte(b); var type = (b & 0x0f); if (type == TCompactProtocol.Types.CT_STOP) { return {fname: null, ftype: Thrift.Type.STOP, fid: 0}; } //Mask off the 4 MSB of the type header to check for field id delta. var modifier = ((b & 0x000000f0) >>> 4); if (modifier === 0) { //If not a delta read the field id. fieldId = this.readI16(); } else { //Recover the field id from the delta fieldId = (this.lastFieldId_ + modifier); } var fieldType = this.getTType(type); //Boolean are encoded with the type if (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE || type == TCompactProtocol.Types.CT_BOOLEAN_FALSE) { this.boolValue_.hasBoolValue = true; this.boolValue_.boolValue = (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE ? true : false); } //Save the new field for the next delta computation. this.lastFieldId_ = fieldId; return {fname: null, ftype: fieldType, fid: fieldId}; }; TCompactProtocol.prototype.readFieldEnd = function() { }; TCompactProtocol.prototype.readMapBegin = function() { var msize = this.readVarint32(); if (msize < 0) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative map size"); } var kvType = 0; if (msize !== 0) { kvType = this.trans.readByte(); } var keyType = this.getTType((kvType & 0xf0) >>> 4); var valType = this.getTType(kvType & 0xf); return {ktype: keyType, vtype: valType, size: msize}; }; TCompactProtocol.prototype.readMapEnd = function() { }; TCompactProtocol.prototype.readListBegin = function() { var size_and_type = this.trans.readByte(); var lsize = (size_and_type >>> 4) & 0x0000000f; if (lsize == 15) { lsize = this.readVarint32(); } if (lsize < 0) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative list size"); } var elemType = this.getTType(size_and_type & 0x0000000f); return {etype: elemType, size: lsize}; }; TCompactProtocol.prototype.readListEnd = function() { }; TCompactProtocol.prototype.readSetBegin = function() { return this.readListBegin(); }; TCompactProtocol.prototype.readSetEnd = function() { }; TCompactProtocol.prototype.readBool = function() { var value = false; var rsize = 0; if (this.boolValue_.hasBoolValue === true) { value = this.boolValue_.boolValue; this.boolValue_.hasBoolValue = false; } else { var res = this.trans.readByte(); rsize = res.rsize; value = (res.value == TCompactProtocol.Types.CT_BOOLEAN_TRUE); } return value; }; TCompactProtocol.prototype.readByte = function() { return this.trans.readByte(); }; TCompactProtocol.prototype.readI16 = function() { return this.readI32(); }; TCompactProtocol.prototype.readI32 = function() { return this.zigzagToI32(this.readVarint32()); }; TCompactProtocol.prototype.readI64 = function() { return this.zigzagToI64(this.readVarint64()); }; // Little-endian, unlike TBinaryProtocol TCompactProtocol.prototype.readDouble = function() { var buff = this.trans.read(8); var off = 0; var signed = buff[off + 7] & 0x80; var e = (buff[off+6] & 0xF0) >> 4; e += (buff[off+7] & 0x7F) << 4; var m = buff[off]; m += buff[off+1] << 8; m += buff[off+2] << 16; m += buff[off+3] * POW_24; m += buff[off+4] * POW_32; m += buff[off+5] * POW_40; m += (buff[off+6] & 0x0F) * POW_48; switch (e) { case 0: e = -1022; break; case 2047: return m ? NaN : (signed ? -Infinity : Infinity); default: m += POW_52; e -= 1023; } if (signed) { m *= -1; } return m * Math.pow(2, e - 52); }; TCompactProtocol.prototype.readBinary = function() { var size = this.readVarint32(); if (size === 0) { return new Buffer(0); } if (size < 0) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative binary size"); } return this.trans.read(size); }; TCompactProtocol.prototype.readString = function() { var size = this.readVarint32(); // Catch empty string case if (size === 0) { return ""; } // Catch error cases if (size < 0) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative string size"); } return this.trans.readString(size); }; // // Compact Protocol internal read operations // /** * Read an i32 from the wire as a varint. The MSB of each byte is set * if there is another byte to follow. This can read up to 5 bytes. */ TCompactProtocol.prototype.readVarint32 = function() { return this.readVarint64().toNumber(); }; /** * Read an i64 from the wire as a proper varint. The MSB of each byte is set * if there is another byte to follow. This can read up to 10 bytes. */ TCompactProtocol.prototype.readVarint64 = function() { var rsize = 0; var lo = 0; var hi = 0; var shift = 0; while (true) { var b = this.trans.readByte(); rsize ++; if (shift <= 25) { lo = lo | ((b & 0x7f) << shift); } else if (25 < shift && shift < 32) { lo = lo | ((b & 0x7f) << shift); hi = hi | ((b & 0x7f) >>> (32-shift)); } else { hi = hi | ((b & 0x7f) << (shift-32)); } shift += 7; if (!(b & 0x80)) { break; } if (rsize >= 10) { throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Variable-length int over 10 bytes."); } } return new Int64(hi, lo); }; /** * Convert from zigzag int to int. */ TCompactProtocol.prototype.zigzagToI32 = function(n) { return (n >>> 1) ^ (-1 * (n & 1)); }; /** * Convert from zigzag long to long. */ TCompactProtocol.prototype.zigzagToI64 = function(n) { var hi = n.buffer.readUInt32BE(0, true); var lo = n.buffer.readUInt32BE(4, true); var neg = new Int64(hi & 0, lo & 1); neg._2scomp(); var hi_neg = neg.buffer.readUInt32BE(0, true); var lo_neg = neg.buffer.readUInt32BE(4, true); var hi_lo = (hi << 31); hi = (hi >>> 1) ^ (hi_neg); lo = ((lo >>> 1) | hi_lo) ^ (lo_neg); return new Int64(hi, lo); }; TCompactProtocol.prototype.skip = function(type) { switch (type) { case Type.BOOL: this.readBool(); break; case Type.BYTE: this.readByte(); break; case Type.I16: this.readI16(); break; case Type.I32: this.readI32(); break; case Type.I64: this.readI64(); break; case Type.DOUBLE: this.readDouble(); break; case Type.STRING: this.readString(); break; case Type.STRUCT: this.readStructBegin(); while (true) { var r = this.readFieldBegin(); if (r.ftype === Type.STOP) { break; } this.skip(r.ftype); this.readFieldEnd(); } this.readStructEnd(); break; case Type.MAP: var mapBegin = this.readMapBegin(); for (var i = 0; i < mapBegin.size; ++i) { this.skip(mapBegin.ktype); this.skip(mapBegin.vtype); } this.readMapEnd(); break; case Type.SET: var setBegin = this.readSetBegin(); for (var i2 = 0; i2 < setBegin.size; ++i2) { this.skip(setBegin.etype); } this.readSetEnd(); break; case Type.LIST: var listBegin = this.readListBegin(); for (var i3 = 0; i3 < listBegin.size; ++i3) { this.skip(listBegin.etype); } this.readListEnd(); break; default: throw new Error("Invalid type: " + type); } }; thrift-0.16.0/lib/nodejs/lib/thrift/connection.js000066400000000000000000000271201420101504100216570ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var EventEmitter = require('events').EventEmitter; var constants = require('constants'); var net = require('net'); var tls = require('tls'); var thrift = require('./thrift'); var log = require('./log'); var TBufferedTransport = require('./buffered_transport'); var TBinaryProtocol = require('./binary_protocol'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); var createClient = require('./create_client'); var binary = require('./binary'); var Connection = exports.Connection = function(stream, options) { var self = this; EventEmitter.call(this); this.seqId2Service = {}; this.connection = stream; this.ssl = (stream.encrypted); this.options = options || {}; this.transport = this.options.transport || TBufferedTransport; this.protocol = this.options.protocol || TBinaryProtocol; this.offline_queue = []; this.connected = false; this.initialize_retry_vars(); this._debug = this.options.debug || false; if (this.options.max_attempts && !isNaN(this.options.max_attempts) && this.options.max_attempts > 0) { this.max_attempts = +this.options.max_attempts; } this.retry_max_delay = null; if (this.options.retry_max_delay !== undefined && !isNaN(this.options.retry_max_delay) && this.options.retry_max_delay > 0) { this.retry_max_delay = this.options.retry_max_delay; } this.connect_timeout = false; if (this.options.connect_timeout && !isNaN(this.options.connect_timeout) && this.options.connect_timeout > 0) { this.connect_timeout = +this.options.connect_timeout; } this.connection.addListener(this.ssl ? "secureConnect" : "connect", function() { self.connected = true; this.setTimeout(self.options.timeout || 0); this.setNoDelay(); this.frameLeft = 0; this.framePos = 0; this.frame = null; self.initialize_retry_vars(); self.flush_offline_queue(); self.emit("connect"); }); this.connection.addListener("error", function(err) { // Only emit the error if no-one else is listening on the connection // or if someone is listening on us, because Node turns unhandled // 'error' events into exceptions. if (self.connection.listeners('error').length === 1 || self.listeners('error').length > 0) { self.emit("error", err); } }); // Add a close listener this.connection.addListener("close", function() { self.connection_gone(); // handle close event. try to reconnect }); this.connection.addListener("timeout", function() { self.emit("timeout"); }); this.connection.addListener("data", self.transport.receiver(function(transport_with_data) { var message = new self.protocol(transport_with_data); try { while (true) { var header = message.readMessageBegin(); var dummy_seqid = header.rseqid * -1; var client = self.client; //The Multiplexed Protocol stores a hash of seqid to service names // in seqId2Service. If the SeqId is found in the hash we need to // lookup the appropriate client for this call. // The connection.client object is a single client object when not // multiplexing, when using multiplexing it is a service name keyed // hash of client objects. //NOTE: The 2 way interdependencies between protocols, transports, // connections and clients in the Node.js implementation are irregular // and make the implementation difficult to extend and maintain. We // should bring this stuff inline with typical thrift I/O stack // operation soon. // --ra var service_name = self.seqId2Service[header.rseqid]; if (service_name) { client = self.client[service_name]; } /*jshint -W083 */ client._reqs[dummy_seqid] = function(err, success){ transport_with_data.commitPosition(); var callback = client._reqs[header.rseqid]; delete client._reqs[header.rseqid]; if (service_name) { delete self.seqId2Service[header.rseqid]; } if (callback) { callback(err, success); } }; /*jshint +W083 */ if(client['recv_' + header.fname]) { client['recv_' + header.fname](message, header.mtype, dummy_seqid); } else { delete client._reqs[dummy_seqid]; self.emit("error", new thrift.TApplicationException(thrift.TApplicationExceptionType.WRONG_METHOD_NAME, "Received a response to an unknown RPC function")); } } } catch (e) { if (e instanceof InputBufferUnderrunError) { transport_with_data.rollbackPosition(); } else { self.emit('error', e); } } })); }; util.inherits(Connection, EventEmitter); Connection.prototype.end = function() { this.connection.end(); }; Connection.prototype.destroy = function() { this.connection.destroy(); }; Connection.prototype.initialize_retry_vars = function () { this.retry_timer = null; this.retry_totaltime = 0; this.retry_delay = 150; this.retry_backoff = 1.7; this.attempts = 0; }; Connection.prototype.flush_offline_queue = function () { var self = this; var offline_queue = this.offline_queue; // Reset offline queue this.offline_queue = []; // Attempt to write queued items offline_queue.forEach(function(data) { self.write(data); }); }; Connection.prototype.write = function(data) { if (!this.connected) { this.offline_queue.push(data); return; } this.connection.write(data); }; Connection.prototype.connection_gone = function () { var self = this; this.connected = false; // If a retry is already in progress, just let that happen if (this.retry_timer) { return; } // We cannot reconnect a secure socket. if (!this.max_attempts || this.ssl) { self.emit("close"); return; } if (this.retry_max_delay !== null && this.retry_delay >= this.retry_max_delay) { this.retry_delay = this.retry_max_delay; } else { this.retry_delay = Math.floor(this.retry_delay * this.retry_backoff); } log.debug("Retry connection in " + this.retry_delay + " ms"); if (this.max_attempts && this.attempts >= this.max_attempts) { this.retry_timer = null; console.error("thrift: Couldn't get thrift connection after " + this.max_attempts + " attempts."); self.emit("close"); return; } this.attempts += 1; this.emit("reconnecting", { delay: self.retry_delay, attempt: self.attempts }); this.retry_timer = setTimeout(function () { if (self.connection.destroyed) { self.retry_timer = null; return; } log.debug("Retrying connection..."); self.retry_totaltime += self.retry_delay; if (self.connect_timeout && self.retry_totaltime >= self.connect_timeout) { self.retry_timer = null; console.error("thrift: Couldn't get thrift connection after " + self.retry_totaltime + "ms."); self.emit("close"); return; } if (self.path !== undefined) { self.connection.connect(self.path); } else { self.connection.connect(self.port, self.host); } self.retry_timer = null; }, this.retry_delay); }; exports.createConnection = function(host, port, options) { var stream = net.createConnection( { port: port, host: host, timeout: options.connect_timeout || options.timeout || 0 }); var connection = new Connection(stream, options); connection.host = host; connection.port = port; return connection; }; exports.createUDSConnection = function(path, options) { var stream = net.createConnection(path); var connection = new Connection(stream, options); connection.path = path; return connection; }; exports.createSSLConnection = function(host, port, options) { if (!('secureProtocol' in options) && !('secureOptions' in options)) { options.secureProtocol = "SSLv23_method"; options.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3; } var stream = tls.connect(port, host, options); var connection = new Connection(stream, options); connection.host = host; connection.port = port; return connection; }; exports.createClient = createClient; var child_process = require('child_process'); var StdIOConnection = exports.StdIOConnection = function(command, options) { var command_parts = command.split(' '); command = command_parts[0]; var args = command_parts.splice(1,command_parts.length -1); var child = this.child = child_process.spawn(command,args); var self = this; EventEmitter.call(this); this.connection = child.stdin; this.options = options || {}; this.transport = this.options.transport || TBufferedTransport; this.protocol = this.options.protocol || TBinaryProtocol; this.offline_queue = []; if (log.getLogLevel() === 'debug') { this.child.stderr.on('data', function (err) { log.debug(err.toString(), 'CHILD ERROR'); }); this.child.on('exit', function (code,signal) { log.debug(code + ':' + signal, 'CHILD EXITED'); }); } this.frameLeft = 0; this.framePos = 0; this.frame = null; this.connected = true; self.flush_offline_queue(); this.connection.addListener("error", function(err) { self.emit("error", err); }); // Add a close listener this.connection.addListener("close", function() { self.emit("close"); }); child.stdout.addListener("data", self.transport.receiver(function(transport_with_data) { var message = new self.protocol(transport_with_data); try { var header = message.readMessageBegin(); var dummy_seqid = header.rseqid * -1; var client = self.client; client._reqs[dummy_seqid] = function(err, success){ transport_with_data.commitPosition(); var callback = client._reqs[header.rseqid]; delete client._reqs[header.rseqid]; if (callback) { callback(err, success); } }; client['recv_' + header.fname](message, header.mtype, dummy_seqid); } catch (e) { if (e instanceof InputBufferUnderrunError) { transport_with_data.rollbackPosition(); } else { throw e; } } })); }; util.inherits(StdIOConnection, EventEmitter); StdIOConnection.prototype.end = function() { this.connection.end(); }; StdIOConnection.prototype.flush_offline_queue = function () { var self = this; var offline_queue = this.offline_queue; // Reset offline queue this.offline_queue = []; // Attempt to write queued items offline_queue.forEach(function(data) { self.write(data); }); }; StdIOConnection.prototype.write = function(data) { if (!this.connected) { this.offline_queue.push(data); return; } this.connection.write(data); }; exports.createStdIOConnection = function(command,options){ return new StdIOConnection(command,options); }; exports.createStdIOClient = createClient; thrift-0.16.0/lib/nodejs/lib/thrift/create_client.js000066400000000000000000000036131420101504100223220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ module.exports = createClient; /** * Creates a new client object for the specified Thrift service. * @param {object} ServiceClient - The module containing the generated service client * @param {Connection} Connection - The connection to use. * @returns {object} The client object. */ function createClient(ServiceClient, connection) { // TODO validate required options and throw otherwise if (ServiceClient.Client) { ServiceClient = ServiceClient.Client; } // TODO detangle these initialization calls // creating "client" requires // - new service client instance // // New service client instance requires // - new transport instance // - protocol class reference // // New transport instance requires // - Buffer to use (or none) // - Callback to call on flush // Wrap the write method var writeCb = function(buf, seqid) { connection.write(buf, seqid); }; var transport = new connection.transport(undefined, writeCb); var client = new ServiceClient(transport, connection.protocol); transport.client = client; connection.client = client; return client; }; thrift-0.16.0/lib/nodejs/lib/thrift/framed_transport.js000066400000000000000000000121031420101504100230650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var binary = require('./binary'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); var THeaderTransport = require('./header_transport'); module.exports = TFramedTransport; function TFramedTransport(buffer, callback) { this.inBuf = buffer || new Buffer(0); this.outBuffers = []; this.outCount = 0; this.readPos = 0; this.onFlush = callback; }; TFramedTransport.prototype = new THeaderTransport(); TFramedTransport.receiver = function(callback, seqid) { var residual = null; return function(data) { // Prepend any residual data from our previous read if (residual) { data = Buffer.concat([residual, data]); residual = null; } // framed transport while (data.length) { if (data.length < 4) { // Not enough bytes to continue, save and resume on next packet residual = data; return; } var frameSize = binary.readI32(data, 0); if (data.length < 4 + frameSize) { // Not enough bytes to continue, save and resume on next packet residual = data; return; } var frame = data.slice(4, 4 + frameSize); residual = data.slice(4 + frameSize); callback(new TFramedTransport(frame), seqid); data = residual; residual = null; } }; }; TFramedTransport.prototype.commitPosition = function(){}, TFramedTransport.prototype.rollbackPosition = function(){}, // TODO: Implement open/close support TFramedTransport.prototype.isOpen = function() { return true; }; TFramedTransport.prototype.open = function() {}; TFramedTransport.prototype.close = function() {}; // Set the seqid of the message in the client // So that callbacks can be found TFramedTransport.prototype.setCurrSeqId = function(seqid) { this._seqid = seqid; }; TFramedTransport.prototype.ensureAvailable = function(len) { if (this.readPos + len > this.inBuf.length) { throw new InputBufferUnderrunError(); } }; TFramedTransport.prototype.read = function(len) { // this function will be used for each frames. this.ensureAvailable(len); var end = this.readPos + len; if (this.inBuf.length < end) { throw new Error('read(' + len + ') failed - not enough data'); } var buf = this.inBuf.slice(this.readPos, end); this.readPos = end; return buf; }; TFramedTransport.prototype.readByte = function() { this.ensureAvailable(1); return binary.readByte(this.inBuf[this.readPos++]); }; TFramedTransport.prototype.readI16 = function() { this.ensureAvailable(2); var i16 = binary.readI16(this.inBuf, this.readPos); this.readPos += 2; return i16; }; TFramedTransport.prototype.readI32 = function() { this.ensureAvailable(4); var i32 = binary.readI32(this.inBuf, this.readPos); this.readPos += 4; return i32; }; TFramedTransport.prototype.readDouble = function() { this.ensureAvailable(8); var d = binary.readDouble(this.inBuf, this.readPos); this.readPos += 8; return d; }; TFramedTransport.prototype.readString = function(len) { this.ensureAvailable(len); var str = this.inBuf.toString('utf8', this.readPos, this.readPos + len); this.readPos += len; return str; }; TFramedTransport.prototype.borrow = function() { return { buf: this.inBuf, readIndex: this.readPos, writeIndex: this.inBuf.length }; }; TFramedTransport.prototype.consume = function(bytesConsumed) { this.readPos += bytesConsumed; }; TFramedTransport.prototype.write = function(buf, encoding) { if (typeof(buf) === "string") { buf = new Buffer(buf, encoding || 'utf8'); } this.outBuffers.push(buf); this.outCount += buf.length; }; TFramedTransport.prototype.flush = function() { // If the seqid of the callback is available pass it to the onFlush // Then remove the current seqid var seqid = this._seqid; this._seqid = null; var out = new Buffer(this.outCount), pos = 0; this.outBuffers.forEach(function(buf) { buf.copy(out, pos, 0); pos += buf.length; }); if (this.onFlush) { // TODO: optimize this better, allocate one buffer instead of both: var msg = new Buffer(out.length + 4); binary.writeI32(msg, out.length); out.copy(msg, 4, 0, out.length); if (this.onFlush) { // Passing seqid through this call to get it to the connection this.onFlush(msg, seqid); } } this.outBuffers = []; this.outCount = 0; }; thrift-0.16.0/lib/nodejs/lib/thrift/header_protocol.js000066400000000000000000000162101420101504100226670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var TBinaryProtocol = require('./binary_protocol'); var TCompactProtocol = require('./compact_protocol'); var THeaderTransport = require('./header_transport'); var ProtocolMap = {}; ProtocolMap[THeaderTransport.SubprotocolId.BINARY] = TBinaryProtocol; ProtocolMap[THeaderTransport.SubprotocolId.COMPACT] = TCompactProtocol; module.exports = THeaderProtocol; function THeaderProtocolError(message) { Error.call(this); if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, this.constructor); } this.name = this.constructor.name; this.message = message; } util.inherits(THeaderProtocolError, Error); /** * A framed protocol with headers. * * THeaderProtocol frames other Thrift protocols and adds support for * optional out-of-band headers. The currently supported subprotocols are * TBinaryProtocol and TCompactProtocol. It can currently only be used with * transports that inherit THeaderTransport. * * THeaderProtocol does not currently support THTTPServer, TNonblockingServer, * or TProcessPoolServer. * * See doc/specs/HeaderFormat.md for details of the wire format. */ function THeaderProtocol(trans) { if (!(trans instanceof THeaderTransport)) { throw new THeaderProtocolError( 'Only transports that inherit THeaderTransport can be' + ' used with THeaderProtocol' ); } this.trans = trans; this.setProtocol(); }; THeaderProtocol.prototype.flush = function() { // Headers must be written prior to flushing because because // you need to calculate the length of the payload for the length // field of the header this.trans.writeHeaders(); return this.trans.flush(); }; THeaderProtocol.prototype.writeMessageBegin = function(name, type, seqid) { return this.protocol.writeMessageBegin(name, type, seqid); }; THeaderProtocol.prototype.writeMessageEnd = function() { return this.protocol.writeMessageEnd(); }; THeaderProtocol.prototype.writeStructBegin = function(name) { return this.protocol.writeStructBegin(name); }; THeaderProtocol.prototype.writeStructEnd = function() { return this.protocol.writeStructEnd(); }; THeaderProtocol.prototype.writeFieldBegin = function(name, type, id) { return this.protocol.writeFieldBegin(name, type, id); } THeaderProtocol.prototype.writeFieldEnd = function() { return this.protocol.writeFieldEnd(); }; THeaderProtocol.prototype.writeFieldStop = function() { return this.protocol.writeFieldStop(); }; THeaderProtocol.prototype.writeMapBegin = function(ktype, vtype, size) { return this.protocol.writeMapBegin(ktype, vtype, size); }; THeaderProtocol.prototype.writeMapEnd = function() { return this.protocol.writeMapEnd(); }; THeaderProtocol.prototype.writeListBegin = function(etype, size) { return this.protocol.writeListBegin(etype, size); }; THeaderProtocol.prototype.writeListEnd = function() { return this.protocol.writeListEnd(); }; THeaderProtocol.prototype.writeSetBegin = function(etype, size) { return this.protocol.writeSetBegin(etype, size); }; THeaderProtocol.prototype.writeSetEnd = function() { return this.protocol.writeSetEnd(); }; THeaderProtocol.prototype.writeBool = function(b) { return this.protocol.writeBool(b); }; THeaderProtocol.prototype.writeByte = function(b) { return this.protocol.writeByte(b); }; THeaderProtocol.prototype.writeI16 = function(i16) { return this.protocol.writeI16(i16); }; THeaderProtocol.prototype.writeI32 = function(i32) { return this.protocol.writeI32(i32); }; THeaderProtocol.prototype.writeI64 = function(i64) { return this.protocol.writeI64(i64); }; THeaderProtocol.prototype.writeDouble = function(dub) { return this.protocol.writeDouble(dub); }; THeaderProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) { return this.protocol.writeStringOrBinary(name, encoding, arg); }; THeaderProtocol.prototype.writeString = function(arg) { return this.protocol.writeString(arg); }; THeaderProtocol.prototype.writeBinary = function(arg) { return this.protocol.writeBinary(arg); }; THeaderProtocol.prototype.readMessageBegin = function() { this.trans.readHeaders(); this.setProtocol(); return this.protocol.readMessageBegin(); }; THeaderProtocol.prototype.readMessageEnd = function() { return this.protocol.readMessageEnd(); }; THeaderProtocol.prototype.readStructBegin = function() { return this.protocol.readStructBegin(); }; THeaderProtocol.prototype.readStructEnd = function() { return this.protocol.readStructEnd(); }; THeaderProtocol.prototype.readFieldBegin = function() { return this.protocol.readFieldBegin(); }; THeaderProtocol.prototype.readFieldEnd = function() { return this.protocol.readFieldEnd(); }; THeaderProtocol.prototype.readMapBegin = function() { return this.protocol.readMapBegin(); }; THeaderProtocol.prototype.readMapEnd = function() { return this.protocol.readMapEnd(); }; THeaderProtocol.prototype.readListBegin = function() { return this.protocol.readListBegin(); }; THeaderProtocol.prototype.readListEnd = function() { return this.protocol.readListEnd(); }; THeaderProtocol.prototype.readSetBegin = function() { return this.protocol.readSetBegin(); }; THeaderProtocol.prototype.readSetEnd = function() { return this.protocol.readSetEnd(); }; THeaderProtocol.prototype.readBool = function() { return this.protocol.readBool(); }; THeaderProtocol.prototype.readByte = function() { return this.protocol.readByte(); }; THeaderProtocol.prototype.readI16 = function() { return this.protocol.readI16(); }; THeaderProtocol.prototype.readI32 = function() { return this.protocol.readI32(); }; THeaderProtocol.prototype.readI64 = function() { return this.protocol.readI64(); }; THeaderProtocol.prototype.readDouble = function() { return this.protocol.readDouble(); }; THeaderProtocol.prototype.readBinary = function() { return this.protocol.readBinary(); }; THeaderProtocol.prototype.readString = function() { return this.protocol.readString(); }; THeaderProtocol.prototype.getTransport = function() { return this.trans; }; THeaderProtocol.prototype.skip = function(type) { return this.protocol.skip(type); }; THeaderProtocol.prototype.setProtocol = function(subProtocolId) { var subProtocolId = this.trans.getProtocolId(); if (!ProtocolMap[subProtocolId]) { throw new THeaderProtocolError('Headers not supported for protocol ' + subProtocolId); } this.protocol = new ProtocolMap[subProtocolId](this.trans); }; thrift-0.16.0/lib/nodejs/lib/thrift/header_transport.js000066400000000000000000000240651420101504100230710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var TCompactProtocol = require('./compact_protocol'); var TBinaryProtocol = require('./binary_protocol'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); function THeaderTransportError(message) { Error.call(this); if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, this.constructor); } this.name = this.constructor.name; this.message = message; } util.inherits(THeaderTransportError, Error); module.exports = THeaderTransport; // from HeaderFormat.md var COMPACT_PROTOCOL_OFFSET = 0; var COMPACT_PROTOCOL_VERSION_OFFSET = 1; var FRAME_SIZE_OFFSET = 0; var HEADER_MAGIC_OFFSET = 32 / 8; var FLAGS_OFFSET = 48 / 8; var SEQID_OFFSET = 64 / 8; var HEADER_SIZE_OFFSET = 96 / 8; var HEADER_START_OFFSET = 112 / 8; var HEADER_MAGIC = 0x0FFF; var TINFO_HEADER_KEY_VALUE_TYPE = 0x01; var MAX_FRAME_SIZE = 0x3FFFFFFF; // A helper class for reading/writing varints. Uses // TCompactProtocol under the hood function VarintHelper(readBuffer) { var TBufferedTransport = require('./buffered_transport'); this.outputBuffer = null; var _this = this; this.transport = new TBufferedTransport(null, function(output) { _this.outputBuffer = output; }); this.transport.inBuf = readBuffer || Buffer.alloc(0); this.transport.writeCursor = this.transport.inBuf.length; this.protocol = new TCompactProtocol(this.transport); }; VarintHelper.prototype.readVarint32 = function() { return this.protocol.readVarint32(); }; VarintHelper.prototype.writeVarint32 = function(i) { this.protocol.writeVarint32(i); }; VarintHelper.prototype.readString = function() { return this.protocol.readString(); }; VarintHelper.prototype.writeString = function(str) { this.protocol.writeString(str); } VarintHelper.prototype.getOutCount = function() { return this.transport.outCount; }; VarintHelper.prototype.write = function(str) { this.transport.write(str); }; VarintHelper.prototype.toBuffer = function() { this.transport.flush(); return this.outputBuffer; }; // from lib/cpp/src/thrift/protocol/TProtocolTypes.h THeaderTransport.SubprotocolId = { BINARY: 0, JSON: 1, COMPACT: 2, }; /** An abstract transport used as a prototype for other transports to enable reading/writing theaders. This should NOT be used as a standalone transport The methods in this transport are called by THeaderProtocol, which will call readHeaders/writeHeaders in the read/writeMessageBegin methods and parse/write headers to/from a request prior to reading/writing. The reason this is not a standalone transport type is because different transport types have their own individual static receiver methods that are called prior to instantiation. There doesn't seem to be a way for THeaderTransport to know which receiver method to use without reworking the server API. For reading headers from a request, the parsed headers can be retrieved via getReadHeader. Similarly, you can set headers to be written on the client via setWriteHeader. */ function THeaderTransport() { this.maxFrameSize = MAX_FRAME_SIZE; this.protocolId = THeaderTransport.SubprotocolId.BINARY; this.rheaders = {}; this.wheaders = {}; this.inBuf = Buffer.alloc(0); this.outCount = 0; this.flags = null; this.seqid = 0; this.shouldWriteHeaders = true; }; var validateHeaders = function(key, value) { if (typeof key !== 'string' || typeof value !== 'string') { throw new THeaderTransportError('Header key and values must be strings'); } }; var validateProtocolId = function(protocolId) { var protocols = Object.keys(THeaderTransport.SubprotocolId); for (var i = 0; i < protocols.length; i++) { if (protocolId === THeaderTransport.SubprotocolId[protocols[i]]) return true; } throw new Error(protocolId + ' is not a valid protocol id'); }; THeaderTransport.prototype.setSeqId = function(seqid) { this.seqid = seqid; }; THeaderTransport.prototype.getSeqId = function(seqid) { return this.seqid; }; THeaderTransport.prototype.setFlags = function(flags) { this.flags = flags; }; THeaderTransport.prototype.getReadHeaders = function() { return this.rheaders; }; THeaderTransport.prototype.setReadHeader = function(key, value) { validateHeaders(key, value); this.rheaders[key] = value; }; THeaderTransport.prototype.clearReadHeaders = function() { this.rheaders = {}; }; THeaderTransport.prototype.getWriteHeaders = function() { return this.wheaders; }; THeaderTransport.prototype.setWriteHeader = function(key, value) { validateHeaders(key, value); this.wheaders[key] = value; }; THeaderTransport.prototype.clearWriteHeaders = function() { this.wheaders = {}; }; THeaderTransport.prototype.setMaxFrameSize = function(frameSize) { this.maxFrameSize = frameSize; }; THeaderTransport.prototype.setProtocolId = function(protocolId) { validateProtocolId(protocolId); this.protocolId = protocolId; }; THeaderTransport.prototype.getProtocolId = function() { return this.protocolId; }; var isUnframedBinary = function(readBuffer) { var version = readBuffer.readInt32BE(); return (version & TBinaryProtocol.VERSION_MASK) === TBinaryProtocol.VERSION_1; } var isUnframedCompact = function(readBuffer) { var protocolId = readBuffer.readInt8(COMPACT_PROTOCOL_OFFSET); var version = readBuffer.readInt8(COMPACT_PROTOCOL_VERSION_OFFSET); return protocolId === TCompactProtocol.PROTOCOL_ID && (version & TCompactProtocol.VERSION_MASK) === TCompactProtocol.VERSION_N; } THeaderTransport.prototype.readHeaders = function() { var readBuffer = this.inBuf; var isUnframed = false; if (isUnframedBinary(readBuffer)) { this.setProtocolId(THeaderTransport.SubprotocolId.BINARY); isUnframed = true; } if (isUnframedCompact(readBuffer)) { this.setProtocolId(THeaderTransport.SubprotocolId.COMPACT); isUnframed = true; } if (isUnframed) { this.shouldWriteHeaders = false; return; } var frameSize = readBuffer.readInt32BE(FRAME_SIZE_OFFSET); if (frameSize > this.maxFrameSize) { throw new THeaderTransportError('Frame exceeds maximum frame size'); } var headerMagic = readBuffer.readInt16BE(HEADER_MAGIC_OFFSET); this.shouldWriteHeaders = headerMagic === HEADER_MAGIC; if (!this.shouldWriteHeaders) { return; } this.setFlags(readBuffer.readInt16BE(FLAGS_OFFSET)); this.setSeqId(readBuffer.readInt32BE(SEQID_OFFSET)); var headerSize = readBuffer.readInt16BE(HEADER_SIZE_OFFSET) * 4; var endOfHeaders = HEADER_START_OFFSET + headerSize; if (endOfHeaders > readBuffer.length) { throw new THeaderTransportError('Header size is greater than frame size'); } var headerBuffer = Buffer.alloc(headerSize); readBuffer.copy(headerBuffer, 0, HEADER_START_OFFSET, endOfHeaders); var varintHelper = new VarintHelper(headerBuffer); this.setProtocolId(varintHelper.readVarint32()); var transformCount = varintHelper.readVarint32(); if (transformCount > 0) { throw new THeaderTransportError('Transforms are not yet supported'); } while (true) { try { var headerType = varintHelper.readVarint32(); if (headerType !== TINFO_HEADER_KEY_VALUE_TYPE) { break; } var numberOfHeaders = varintHelper.readVarint32(); for (var i = 0; i < numberOfHeaders; i++) { var key = varintHelper.readString(); var value = varintHelper.readString(); this.setReadHeader(key, value); } } catch (e) { if (e instanceof InputBufferUnderrunError) { break; } throw e; } } // moves the read cursor past the headers this.read(endOfHeaders); return this.getReadHeaders(); }; THeaderTransport.prototype.writeHeaders = function() { // only write headers on the server if the client contained headers if (!this.shouldWriteHeaders) { return; } var headers = this.getWriteHeaders(); var varintWriter = new VarintHelper(); varintWriter.writeVarint32(this.protocolId); varintWriter.writeVarint32(0); // transforms not supported // writing info header key values var headerKeys = Object.keys(headers); if (headerKeys.length > 0) { varintWriter.writeVarint32(TINFO_HEADER_KEY_VALUE_TYPE); varintWriter.writeVarint32(headerKeys.length); for (var i = 0; i < headerKeys.length; i++) { var key = headerKeys[i]; var value = headers[key]; varintWriter.writeString(key); varintWriter.writeString(value); } } var headerSizeWithoutPadding = varintWriter.getOutCount(); var paddingNeeded = (4 - (headerSizeWithoutPadding % 4)) % 4; var headerSize = Buffer.alloc(2); headerSize.writeInt16BE(Math.floor((headerSizeWithoutPadding + paddingNeeded) / 4)); var paddingBuffer = Buffer.alloc(paddingNeeded); paddingBuffer.fill(0x00); varintWriter.write(paddingBuffer); var headerContentBuffer = varintWriter.toBuffer(); var frameSize = Buffer.alloc(4); frameSize.writeInt32BE(10 + this.outCount + headerContentBuffer.length); var headerMagic = Buffer.alloc(2); headerMagic.writeInt16BE(HEADER_MAGIC); // flags are not yet supported, so write a zero var flags = Buffer.alloc(2); flags.writeInt16BE(0); var seqid = Buffer.alloc(4); seqid.writeInt32BE(this.getSeqId()); var headerBuffer = Buffer.concat([ frameSize, headerMagic, flags, seqid, headerSize, headerContentBuffer, ]); this.outBuffers.unshift(headerBuffer); this.outCount += headerBuffer.length; }; thrift-0.16.0/lib/nodejs/lib/thrift/http_connection.js000066400000000000000000000235561420101504100227270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var http = require('http'); var https = require('https'); var EventEmitter = require('events').EventEmitter; var thrift = require('./thrift'); var TBufferedTransport = require('./buffered_transport'); var TBinaryProtocol = require('./binary_protocol'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); var createClient = require('./create_client'); /** * @class * @name ConnectOptions * @property {string} transport - The Thrift layered transport to use (TBufferedTransport, etc). * @property {string} protocol - The Thrift serialization protocol to use (TBinaryProtocol, etc.). * @property {string} path - The URL path to POST to (e.g. "/", "/mySvc", "/thrift/quoteSvc", etc.). * @property {object} headers - A standard Node.js header hash, an object hash containing key/value * pairs where the key is the header name string and the value is the header value string. * @property {boolean} https - True causes the connection to use https, otherwise http is used. * @property {object} nodeOptions - Options passed on to node. * @example * //Use a connection that requires ssl/tls, closes the connection after each request, * // uses the buffered transport layer, uses the JSON protocol and directs RPC traffic * // to https://thrift.example.com:9090/hello * var thrift = require('thrift'); * var options = { * transport: thrift.TBufferedTransport, * protocol: thrift.TJSONProtocol, * path: "/hello", * headers: {"Connection": "close"}, * https: true * }; * var con = thrift.createHttpConnection("thrift.example.com", 9090, options); * var client = thrift.createHttpClient(myService, connection); * client.myServiceFunction(); */ /** * Initializes a Thrift HttpConnection instance (use createHttpConnection() rather than * instantiating directly). * @constructor * @param {ConnectOptions} options - The configuration options to use. * @throws {error} Exceptions other than InputBufferUnderrunError are rethrown * @event {error} The "error" event is fired when a Node.js error event occurs during * request or response processing, in which case the node error is passed on. An "error" * event may also be fired when the connection can not map a response back to the * appropriate client (an internal error), generating a TApplicationException. * @classdesc HttpConnection objects provide Thrift end point transport * semantics implemented over the Node.js http.request() method. * @see {@link createHttpConnection} */ var HttpConnection = exports.HttpConnection = function(options) { //Initialize the emitter base object EventEmitter.call(this); //Set configuration var self = this; this.options = options || {}; this.host = this.options.host; this.port = this.options.port; this.socketPath = this.options.socketPath; this.https = this.options.https || false; this.transport = this.options.transport || TBufferedTransport; this.protocol = this.options.protocol || TBinaryProtocol; //Prepare Node.js options this.nodeOptions = { host: this.host, port: this.port, socketPath: this.socketPath, path: this.options.path || '/', method: 'POST', headers: this.options.headers || {}, responseType: this.options.responseType || null }; for (var attrname in this.options.nodeOptions) { this.nodeOptions[attrname] = this.options.nodeOptions[attrname]; } /*jshint -W069 */ if (! this.nodeOptions.headers['Connection']) { this.nodeOptions.headers['Connection'] = 'keep-alive'; } /*jshint +W069 */ //The sequence map is used to map seqIDs back to the // calling client in multiplexed scenarios this.seqId2Service = {}; function decodeCallback(transport_with_data) { var proto = new self.protocol(transport_with_data); try { while (true) { var header = proto.readMessageBegin(); var dummy_seqid = header.rseqid * -1; var client = self.client; //The Multiplexed Protocol stores a hash of seqid to service names // in seqId2Service. If the SeqId is found in the hash we need to // lookup the appropriate client for this call. // The client var is a single client object when not multiplexing, // when using multiplexing it is a service name keyed hash of client // objects. //NOTE: The 2 way interdependencies between protocols, transports, // connections and clients in the Node.js implementation are irregular // and make the implementation difficult to extend and maintain. We // should bring this stuff inline with typical thrift I/O stack // operation soon. // --ra var service_name = self.seqId2Service[header.rseqid]; if (service_name) { client = self.client[service_name]; delete self.seqId2Service[header.rseqid]; } /*jshint -W083 */ client._reqs[dummy_seqid] = function(err, success){ transport_with_data.commitPosition(); var clientCallback = client._reqs[header.rseqid]; delete client._reqs[header.rseqid]; if (clientCallback) { process.nextTick(function() { clientCallback(err, success); }); } }; /*jshint +W083 */ if(client['recv_' + header.fname]) { client['recv_' + header.fname](proto, header.mtype, dummy_seqid); } else { delete client._reqs[dummy_seqid]; self.emit("error", new thrift.TApplicationException( thrift.TApplicationExceptionType.WRONG_METHOD_NAME, "Received a response to an unknown RPC function")); } } } catch (e) { if (e instanceof InputBufferUnderrunError) { transport_with_data.rollbackPosition(); } else { self.emit('error', e); } } } //Response handler ////////////////////////////////////////////////// this.responseCallback = function(response) { var data = []; var dataLen = 0; if (response.statusCode !== 200) { this.emit("error", new THTTPException(response)); } response.on('error', function (e) { self.emit("error", e); }); // When running directly under node, chunk will be a buffer, // however, when running in a Browser (e.g. Browserify), chunk // will be a string or an ArrayBuffer. response.on('data', function (chunk) { if ((typeof chunk == 'string') || (Object.prototype.toString.call(chunk) == '[object Uint8Array]')) { // Wrap ArrayBuffer/string in a Buffer so data[i].copy will work data.push(new Buffer(chunk)); } else { data.push(chunk); } dataLen += chunk.length; }); response.on('end', function(){ var buf = new Buffer(dataLen); for (var i=0, len=data.length, pos=0; i= 0; --i) { buffer[i] = (~b[o + i] + (incremented ? 0 : 1)) & 0xff; incremented |= b[o + i]; } b = buffer; } var high2 = b[o + 1] + (b[o] << 8); // Lesser 11 digits with exceeding values but is under 53 bits capacity. var low = b[o + 7] + (b[o + 6] << 8) + (b[o + 5] << 16) + b[o + 4] * POW2_24 // Bit shift renders 32th bit as sign, so use multiplication + (b[o + 3] + (b[o + 2] << 8)) * POW2_32 + high2 * 74976710656; // The literal is 2^48 % 10^11 // 12th digit and greater. var high = Math.floor(low / POW10_11) + high2 * 2814; // The literal is 2^48 / 10^11 // Make it exactly 11 with leading zeros. low = ('00000000000' + String(low % POW10_11)).slice(-11); return (negative ? '-' : '') + String(high) + low; } }; Int64Util.fromDecimalString = function(text) { var negative = text.charAt(0) === '-'; if (text.length < (negative ? 17 : 16)) { // The magnitude is smaller than 2^53. return new Int64(+text); } else if (text.length > (negative ? 20 : 19)) { throw new RangeError('Too many digits for Int64: ' + text); } else { // Most significant (up to 5) digits var high5 = +text.slice(negative ? 1 : 0, -15); var low = +text.slice(-15) + high5 * 2764472320; // The literal is 10^15 % 2^32 var high = Math.floor(low / POW2_32) + high5 * 232830; // The literal is 10^15 / 2^&32 low = low % POW2_32; if (high >= POW2_31 && !(negative && high == POW2_31 && low == 0) // Allow minimum Int64 ) { throw new RangeError('The magnitude is too large for Int64.'); } if (negative) { // 2's complement high = ~high; if (low === 0) { high = (high + 1) & 0xffffffff; } else { low = ~low + 1; } high = 0x80000000 | high; } return new Int64(high, low); } }; thrift-0.16.0/lib/nodejs/lib/thrift/json_parse.js000066400000000000000000000171261420101504100216700ustar00rootroot00000000000000/* * Imported from Douglas Crockford's reference implementation with minimum modification * to handle Int64. * * https://github.com/douglascrockford/JSON-js/blob/c98948ae1944a28e2e8ebc3717894e580aeaaa05/json_parse.js * * Original license header: * * json_parse.js * 2015-05-02 * Public Domain. * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. */ /*jslint for */ /*property at, b, call, charAt, f, fromCharCode, hasOwnProperty, message, n, name, prototype, push, r, t, text */ var Int64 = require('node-int64'); var Int64Util = require('./int64_util'); var json_parse = module.exports = (function () { "use strict"; // This is a function that can parse a JSON text, producing a JavaScript // data structure. It is a simple, recursive descent parser. It does not use // eval or regular expressions, so it can be used as a model for implementing // a JSON parser in other languages. // We are defining the function inside of another function to avoid creating // global variables. var at, // The index of the current character ch, // The current character escapee = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' }, text, error = function (m) { // Call error when something is wrong. throw new SyntaxError(m); }, next = function (c) { // If a c parameter is provided, verify that it matches the current character. if (c && c !== ch) { error("Expected '" + c + "' instead of '" + ch + "'"); } // Get the next character. When there are no more characters, // return the empty string. ch = text.charAt(at); at += 1; return ch; }, number = function () { // Parse a number value. var number, string = ''; if (ch === '-') { string = '-'; next('-'); } while (ch >= '0' && ch <= '9') { string += ch; next(); } if (ch === '.') { string += '.'; while (next() && ch >= '0' && ch <= '9') { string += ch; } } if (ch === 'e' || ch === 'E') { string += ch; next(); if (ch === '-' || ch === '+') { string += ch; next(); } while (ch >= '0' && ch <= '9') { string += ch; next(); } } number = +string; if (!isFinite(number)) { error("Bad number"); } else if (number >= Int64.MAX_INT || number <= Int64.MIN_INT) { // Return raw string for further process in TJSONProtocol return string; } else { return number; } }, string = function () { // Parse a string value. var hex, i, string = '', uffff; // When parsing for string values, we must look for " and \ characters. if (ch === '"') { while (next()) { if (ch === '"') { next(); return string; } if (ch === '\\') { next(); if (ch === 'u') { uffff = 0; for (i = 0; i < 4; i += 1) { hex = parseInt(next(), 16); if (!isFinite(hex)) { break; } uffff = uffff * 16 + hex; } string += String.fromCharCode(uffff); } else if (typeof escapee[ch] === 'string') { string += escapee[ch]; } else { break; } } else { string += ch; } } } error("Bad string"); }, white = function () { // Skip whitespace. while (ch && ch <= ' ') { next(); } }, word = function () { // true, false, or null. switch (ch) { case 't': next('t'); next('r'); next('u'); next('e'); return true; case 'f': next('f'); next('a'); next('l'); next('s'); next('e'); return false; case 'n': next('n'); next('u'); next('l'); next('l'); return null; } error("Unexpected '" + ch + "'"); }, value, // Place holder for the value function. array = function () { // Parse an array value. var array = []; if (ch === '[') { next('['); white(); if (ch === ']') { next(']'); return array; // empty array } while (ch) { array.push(value()); white(); if (ch === ']') { next(']'); return array; } next(','); white(); } } error("Bad array"); }, object = function () { // Parse an object value. var key, object = {}; if (ch === '{') { next('{'); white(); if (ch === '}') { next('}'); return object; // empty object } while (ch) { key = string(); white(); next(':'); if (Object.hasOwnProperty.call(object, key)) { error('Duplicate key "' + key + '"'); } object[key] = value(); white(); if (ch === '}') { next('}'); return object; } next(','); white(); } } error("Bad object"); }; value = function () { // Parse a JSON value. It could be an object, an array, a string, a number, // or a word. white(); switch (ch) { case '{': return object(); case '[': return array(); case '"': return string(); case '-': return number(); default: return ch >= '0' && ch <= '9' ? number() : word(); } }; // Return the json_parse function. It will have access to all of the above // functions and variables. return function (source) { var result; text = source; at = 0; ch = ' '; result = value(); white(); if (ch) { error("Syntax error"); } return result; }; }()); thrift-0.16.0/lib/nodejs/lib/thrift/json_protocol.js000066400000000000000000000520311420101504100224110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var Int64 = require('node-int64'); var Thrift = require('./thrift'); var Type = Thrift.Type; var util = require("util"); var Int64Util = require('./int64_util'); var json_parse = require('./json_parse'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); module.exports = TJSONProtocol; /** * Initializes a Thrift JSON protocol instance. * @constructor * @param {Thrift.Transport} trans - The transport to serialize to/from. * @classdesc Apache Thrift Protocols perform serialization which enables cross * language RPC. The Protocol type is the JavaScript browser implementation * of the Apache Thrift TJSONProtocol. * @example * var protocol = new Thrift.Protocol(transport); */ function TJSONProtocol(trans) { this.tstack = []; this.tpos = []; this.trans = trans; }; /** * Thrift IDL type Id to string mapping. * @readonly * @see {@link Thrift.Type} */ TJSONProtocol.Type = {}; TJSONProtocol.Type[Type.BOOL] = '"tf"'; TJSONProtocol.Type[Type.BYTE] = '"i8"'; TJSONProtocol.Type[Type.I16] = '"i16"'; TJSONProtocol.Type[Type.I32] = '"i32"'; TJSONProtocol.Type[Type.I64] = '"i64"'; TJSONProtocol.Type[Type.DOUBLE] = '"dbl"'; TJSONProtocol.Type[Type.STRUCT] = '"rec"'; TJSONProtocol.Type[Type.STRING] = '"str"'; TJSONProtocol.Type[Type.MAP] = '"map"'; TJSONProtocol.Type[Type.LIST] = '"lst"'; TJSONProtocol.Type[Type.SET] = '"set"'; /** * Thrift IDL type string to Id mapping. * @readonly * @see {@link Thrift.Type} */ TJSONProtocol.RType = {}; TJSONProtocol.RType.tf = Type.BOOL; TJSONProtocol.RType.i8 = Type.BYTE; TJSONProtocol.RType.i16 = Type.I16; TJSONProtocol.RType.i32 = Type.I32; TJSONProtocol.RType.i64 = Type.I64; TJSONProtocol.RType.dbl = Type.DOUBLE; TJSONProtocol.RType.rec = Type.STRUCT; TJSONProtocol.RType.str = Type.STRING; TJSONProtocol.RType.map = Type.MAP; TJSONProtocol.RType.lst = Type.LIST; TJSONProtocol.RType.set = Type.SET; /** * The TJSONProtocol version number. * @readonly * @const {number} Version * @memberof Thrift.Protocol */ TJSONProtocol.Version = 1; TJSONProtocol.prototype.flush = function() { this.writeToTransportIfStackIsFlushable(); return this.trans.flush(); }; TJSONProtocol.prototype.writeToTransportIfStackIsFlushable = function() { if (this.tstack.length === 1) { this.trans.write(this.tstack.pop()); } }; /** * Serializes the beginning of a Thrift RPC message. * @param {string} name - The service method to call. * @param {Thrift.MessageType} messageType - The type of method call. * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). */ TJSONProtocol.prototype.writeMessageBegin = function(name, messageType, seqid) { this.tstack.push([TJSONProtocol.Version, '"' + name + '"', messageType, seqid]); }; /** * Serializes the end of a Thrift RPC message. */ TJSONProtocol.prototype.writeMessageEnd = function() { var obj = this.tstack.pop(); this.wobj = this.tstack.pop(); this.wobj.push(obj); this.wbuf = '[' + this.wobj.join(',') + ']'; // we assume there is nothing more to come so we write this.trans.write(this.wbuf); }; /** * Serializes the beginning of a struct. * @param {string} name - The name of the struct. */ TJSONProtocol.prototype.writeStructBegin = function(name) { this.tpos.push(this.tstack.length); this.tstack.push({}); }; /** * Serializes the end of a struct. */ TJSONProtocol.prototype.writeStructEnd = function() { var p = this.tpos.pop(); var struct = this.tstack[p]; var str = '{'; var first = true; for (var key in struct) { if (first) { first = false; } else { str += ','; } str += key + ':' + struct[key]; } str += '}'; this.tstack[p] = str; this.writeToTransportIfStackIsFlushable(); }; /** * Serializes the beginning of a struct field. * @param {string} name - The name of the field. * @param {Thrift.Protocol.Type} fieldType - The data type of the field. * @param {number} fieldId - The field's unique identifier. */ TJSONProtocol.prototype.writeFieldBegin = function(name, fieldType, fieldId) { this.tpos.push(this.tstack.length); this.tstack.push({ 'fieldId': '"' + fieldId + '"', 'fieldType': TJSONProtocol.Type[fieldType] }); }; /** * Serializes the end of a field. */ TJSONProtocol.prototype.writeFieldEnd = function() { var value = this.tstack.pop(); var fieldInfo = this.tstack.pop(); if (':' + value === ":[object Object]") { this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + fieldInfo.fieldType + ':' + JSON.stringify(value) + '}'; } else { this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + fieldInfo.fieldType + ':' + value + '}'; } this.tpos.pop(); this.writeToTransportIfStackIsFlushable(); }; /** * Serializes the end of the set of fields for a struct. */ TJSONProtocol.prototype.writeFieldStop = function() { }; /** * Serializes the beginning of a map collection. * @param {Thrift.Type} keyType - The data type of the key. * @param {Thrift.Type} valType - The data type of the value. * @param {number} [size] - The number of elements in the map (ignored). */ TJSONProtocol.prototype.writeMapBegin = function(keyType, valType, size) { //size is invalid, we'll set it on end. this.tpos.push(this.tstack.length); this.tstack.push([TJSONProtocol.Type[keyType], TJSONProtocol.Type[valType], 0]); }; /** * Serializes the end of a map. */ TJSONProtocol.prototype.writeMapEnd = function() { var p = this.tpos.pop(); if (p == this.tstack.length) { return; } if ((this.tstack.length - p - 1) % 2 !== 0) { this.tstack.push(''); } var size = (this.tstack.length - p - 1) / 2; this.tstack[p][this.tstack[p].length - 1] = size; var map = '}'; var first = true; while (this.tstack.length > p + 1) { var v = this.tstack.pop(); var k = this.tstack.pop(); if (first) { first = false; } else { map = ',' + map; } if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings map = k + ':' + v + map; } map = '{' + map; this.tstack[p].push(map); this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; this.writeToTransportIfStackIsFlushable(); }; /** * Serializes the beginning of a list collection. * @param {Thrift.Type} elemType - The data type of the elements. * @param {number} size - The number of elements in the list. */ TJSONProtocol.prototype.writeListBegin = function(elemType, size) { this.tpos.push(this.tstack.length); this.tstack.push([TJSONProtocol.Type[elemType], size]); }; /** * Serializes the end of a list. */ TJSONProtocol.prototype.writeListEnd = function() { var p = this.tpos.pop(); while (this.tstack.length > p + 1) { var tmpVal = this.tstack[p + 1]; this.tstack.splice(p + 1, 1); this.tstack[p].push(tmpVal); } this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; this.writeToTransportIfStackIsFlushable(); }; /** * Serializes the beginning of a set collection. * @param {Thrift.Type} elemType - The data type of the elements. * @param {number} size - The number of elements in the list. */ TJSONProtocol.prototype.writeSetBegin = function(elemType, size) { this.tpos.push(this.tstack.length); this.tstack.push([TJSONProtocol.Type[elemType], size]); }; /** * Serializes the end of a set. */ TJSONProtocol.prototype.writeSetEnd = function() { var p = this.tpos.pop(); while (this.tstack.length > p + 1) { var tmpVal = this.tstack[p + 1]; this.tstack.splice(p + 1, 1); this.tstack[p].push(tmpVal); } this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; this.writeToTransportIfStackIsFlushable(); }; /** Serializes a boolean */ TJSONProtocol.prototype.writeBool = function(bool) { this.tstack.push(bool ? 1 : 0); }; /** Serializes a number */ TJSONProtocol.prototype.writeByte = function(byte) { this.tstack.push(byte); }; /** Serializes a number */ TJSONProtocol.prototype.writeI16 = function(i16) { this.tstack.push(i16); }; /** Serializes a number */ TJSONProtocol.prototype.writeI32 = function(i32) { this.tstack.push(i32); }; /** Serializes a number */ TJSONProtocol.prototype.writeI64 = function(i64) { if (i64 instanceof Int64) { this.tstack.push(Int64Util.toDecimalString(i64)); } else { this.tstack.push(i64); } }; /** Serializes a number */ TJSONProtocol.prototype.writeDouble = function(dub) { this.tstack.push(dub); }; /** Serializes a string */ TJSONProtocol.prototype.writeString = function(arg) { // We do not encode uri components for wire transfer: if (arg === null) { this.tstack.push(null); } else { if (typeof arg === 'string') { var str = arg; } else if (arg instanceof Buffer) { var str = arg.toString('utf8'); } else { throw new Error('writeString called without a string/Buffer argument: ' + arg); } // concat may be slower than building a byte buffer var escapedString = ''; for (var i = 0; i < str.length; i++) { var ch = str.charAt(i); // a single double quote: " if (ch === '\"') { escapedString += '\\\"'; // write out as: \" } else if (ch === '\\') { // a single backslash: \ escapedString += '\\\\'; // write out as: \\ /* Currently escaped forward slashes break TJSONProtocol. * As it stands, we can simply pass forward slashes into * our strings across the wire without being escaped. * I think this is the protocol's bug, not thrift.js * } else if(ch === '/') { // a single forward slash: / * escapedString += '\\/'; // write out as \/ * } */ } else if (ch === '\b') { // a single backspace: invisible escapedString += '\\b'; // write out as: \b" } else if (ch === '\f') { // a single formfeed: invisible escapedString += '\\f'; // write out as: \f" } else if (ch === '\n') { // a single newline: invisible escapedString += '\\n'; // write out as: \n" } else if (ch === '\r') { // a single return: invisible escapedString += '\\r'; // write out as: \r" } else if (ch === '\t') { // a single tab: invisible escapedString += '\\t'; // write out as: \t" } else { escapedString += ch; // Else it need not be escaped } } this.tstack.push('"' + escapedString + '"'); } }; /** Serializes a string */ TJSONProtocol.prototype.writeBinary = function(arg) { if (typeof arg === 'string') { var buf = new Buffer(arg, 'binary'); } else if (arg instanceof Buffer || Object.prototype.toString.call(arg) == '[object Uint8Array]') { var buf = arg; } else { throw new Error('writeBinary called without a string/Buffer argument: ' + arg); } this.tstack.push('"' + buf.toString('base64') + '"'); }; /** * @class * @name AnonReadMessageBeginReturn * @property {string} fname - The name of the service method. * @property {Thrift.MessageType} mtype - The type of message call. * @property {number} rseqid - The sequence number of the message (0 in Thrift RPC). */ /** * Deserializes the beginning of a message. * @returns {AnonReadMessageBeginReturn} */ TJSONProtocol.prototype.readMessageBegin = function() { this.rstack = []; this.rpos = []; //Borrow the inbound transport buffer and ensure data is present/consistent var transBuf = this.trans.borrow(); if (transBuf.readIndex >= transBuf.writeIndex) { throw new InputBufferUnderrunError(); } var cursor = transBuf.readIndex; if (transBuf.buf[cursor] !== 0x5B) { //[ throw new Error("Malformed JSON input, no opening bracket"); } //Parse a single message (there may be several in the buffer) // TODO: Handle characters using multiple code units cursor++; var openBracketCount = 1; var inString = false; for (; cursor < transBuf.writeIndex; cursor++) { var chr = transBuf.buf[cursor]; //we use hexa charcode here because data[i] returns an int and not a char if (inString) { if (chr === 0x22) { //" inString = false; } else if (chr === 0x5C) { //\ //escaped character, skip cursor += 1; } } else { if (chr === 0x5B) { //[ openBracketCount += 1; } else if (chr === 0x5D) { //] openBracketCount -= 1; if (openBracketCount === 0) { //end of json message detected break; } } else if (chr === 0x22) { //" inString = true; } } } if (openBracketCount !== 0) { // Missing closing bracket. Can be buffer underrun. throw new InputBufferUnderrunError(); } //Reconstitute the JSON object and conume the necessary bytes this.robj = json_parse(transBuf.buf.slice(transBuf.readIndex, cursor+1).toString()); this.trans.consume(cursor + 1 - transBuf.readIndex); //Verify the protocol version var version = this.robj.shift(); if (version != TJSONProtocol.Version) { throw new Error('Wrong thrift protocol version: ' + version); } //Objectify the thrift message {name/type/sequence-number} for return // and then save the JSON object in rstack var r = {}; r.fname = this.robj.shift(); r.mtype = this.robj.shift(); r.rseqid = this.robj.shift(); this.rstack.push(this.robj.shift()); return r; }; /** Deserializes the end of a message. */ TJSONProtocol.prototype.readMessageEnd = function() { }; /** * Deserializes the beginning of a struct. * @param {string} [name] - The name of the struct (ignored) * @returns {object} - An object with an empty string fname property */ TJSONProtocol.prototype.readStructBegin = function() { var r = {}; r.fname = ''; //incase this is an array of structs if (this.rstack[this.rstack.length - 1] instanceof Array) { this.rstack.push(this.rstack[this.rstack.length - 1].shift()); } return r; }; /** Deserializes the end of a struct. */ TJSONProtocol.prototype.readStructEnd = function() { this.rstack.pop(); }; /** * @class * @name AnonReadFieldBeginReturn * @property {string} fname - The name of the field (always ''). * @property {Thrift.Type} ftype - The data type of the field. * @property {number} fid - The unique identifier of the field. */ /** * Deserializes the beginning of a field. * @returns {AnonReadFieldBeginReturn} */ TJSONProtocol.prototype.readFieldBegin = function() { var r = {}; var fid = -1; var ftype = Type.STOP; //get a fieldId for (var f in (this.rstack[this.rstack.length - 1])) { if (f === null) { continue; } fid = parseInt(f, 10); this.rpos.push(this.rstack.length); var field = this.rstack[this.rstack.length - 1][fid]; //remove so we don't see it again delete this.rstack[this.rstack.length - 1][fid]; this.rstack.push(field); break; } if (fid != -1) { //should only be 1 of these but this is the only //way to match a key for (var i in (this.rstack[this.rstack.length - 1])) { if (TJSONProtocol.RType[i] === null) { continue; } ftype = TJSONProtocol.RType[i]; this.rstack[this.rstack.length - 1] = this.rstack[this.rstack.length - 1][i]; } } r.fname = ''; r.ftype = ftype; r.fid = fid; return r; }; /** Deserializes the end of a field. */ TJSONProtocol.prototype.readFieldEnd = function() { var pos = this.rpos.pop(); //get back to the right place in the stack while (this.rstack.length > pos) { this.rstack.pop(); } }; /** * @class * @name AnonReadMapBeginReturn * @property {Thrift.Type} ktype - The data type of the key. * @property {Thrift.Type} vtype - The data type of the value. * @property {number} size - The number of elements in the map. */ /** * Deserializes the beginning of a map. * @returns {AnonReadMapBeginReturn} */ TJSONProtocol.prototype.readMapBegin = function() { var map = this.rstack.pop(); var first = map.shift(); if (first instanceof Array) { this.rstack.push(map); map = first; first = map.shift(); } var r = {}; r.ktype = TJSONProtocol.RType[first]; r.vtype = TJSONProtocol.RType[map.shift()]; r.size = map.shift(); this.rpos.push(this.rstack.length); this.rstack.push(map.shift()); return r; }; /** Deserializes the end of a map. */ TJSONProtocol.prototype.readMapEnd = function() { this.readFieldEnd(); }; /** * @class * @name AnonReadColBeginReturn * @property {Thrift.Type} etype - The data type of the element. * @property {number} size - The number of elements in the collection. */ /** * Deserializes the beginning of a list. * @returns {AnonReadColBeginReturn} */ TJSONProtocol.prototype.readListBegin = function() { var list = this.rstack[this.rstack.length - 1]; var r = {}; r.etype = TJSONProtocol.RType[list.shift()]; r.size = list.shift(); this.rpos.push(this.rstack.length); this.rstack.push(list.shift()); return r; }; /** Deserializes the end of a list. */ TJSONProtocol.prototype.readListEnd = function() { var pos = this.rpos.pop() - 2; var st = this.rstack; st.pop(); if (st instanceof Array && st.length > pos && st[pos].length > 0) { st.push(st[pos].shift()); } }; /** * Deserializes the beginning of a set. * @returns {AnonReadColBeginReturn} */ TJSONProtocol.prototype.readSetBegin = function() { return this.readListBegin(); }; /** Deserializes the end of a set. */ TJSONProtocol.prototype.readSetEnd = function() { return this.readListEnd(); }; TJSONProtocol.prototype.readBool = function() { return this.readValue() == '1'; }; TJSONProtocol.prototype.readByte = function() { return this.readI32(); }; TJSONProtocol.prototype.readI16 = function() { return this.readI32(); }; TJSONProtocol.prototype.readI32 = function(f) { return +this.readValue(); } /** Returns the next value found in the protocol buffer */ TJSONProtocol.prototype.readValue = function(f) { if (f === undefined) { f = this.rstack[this.rstack.length - 1]; } var r = {}; if (f instanceof Array) { if (f.length === 0) { r.value = undefined; } else { r.value = f.shift(); } } else if (!(f instanceof Int64) && f instanceof Object) { for (var i in f) { if (i === null) { continue; } this.rstack.push(f[i]); delete f[i]; r.value = i; break; } } else { r.value = f; this.rstack.pop(); } return r.value; }; TJSONProtocol.prototype.readI64 = function() { var n = this.readValue() if (typeof n === 'string') { // Assuming no one is sending in 1.11111e+33 format return Int64Util.fromDecimalString(n); } else { return new Int64(n); } }; TJSONProtocol.prototype.readDouble = function() { return this.readI32(); }; TJSONProtocol.prototype.readBinary = function() { return new Buffer(this.readValue(), 'base64'); }; TJSONProtocol.prototype.readString = function() { return this.readValue(); }; /** * Returns the underlying transport. * @readonly * @returns {Thrift.Transport} The underlying transport. */ TJSONProtocol.prototype.getTransport = function() { return this.trans; }; /** * Method to arbitrarily skip over data */ TJSONProtocol.prototype.skip = function(type) { switch (type) { case Type.BOOL: this.readBool(); break; case Type.BYTE: this.readByte(); break; case Type.I16: this.readI16(); break; case Type.I32: this.readI32(); break; case Type.I64: this.readI64(); break; case Type.DOUBLE: this.readDouble(); break; case Type.STRING: this.readString(); break; case Type.STRUCT: this.readStructBegin(); while (true) { var r = this.readFieldBegin(); if (r.ftype === Type.STOP) { break; } this.skip(r.ftype); this.readFieldEnd(); } this.readStructEnd(); break; case Type.MAP: var mapBegin = this.readMapBegin(); for (var i = 0; i < mapBegin.size; ++i) { this.skip(mapBegin.ktype); this.skip(mapBegin.vtype); } this.readMapEnd(); break; case Type.SET: var setBegin = this.readSetBegin(); for (var i2 = 0; i2 < setBegin.size; ++i2) { this.skip(setBegin.etype); } this.readSetEnd(); break; case Type.LIST: var listBegin = this.readListBegin(); for (var i3 = 0; i3 < listBegin.size; ++i3) { this.skip(listBegin.etype); } this.readListEnd(); break; default: throw new Error("Invalid type: " + type); } }; thrift-0.16.0/lib/nodejs/lib/thrift/log.js000066400000000000000000000042741420101504100203060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var disabled = function () {}; var logFunc = console.log; var logLevel = 'error'; // default level function factory(level) { return function () { // better use spread syntax, but due to compatibility, // use legacy method here. var args = ['thrift: [' + level + '] '].concat(Array.from(arguments)); return logFunc(util.format.apply(null, args)); }; } var trace = disabled; var debug = disabled; var error = disabled; var warning = disabled; var info = disabled; exports.setLogFunc = function (func) { logFunc = func; }; var setLogLevel = exports.setLogLevel = function (level) { trace = debug = error = warning = info = disabled; logLevel = level; switch (logLevel) { case 'trace': trace = factory('TRACE'); case 'debug': debug = factory('DEBUG'); case 'error': error = factory('ERROR'); case 'warning': warning = factory('WARN'); case 'info': info = factory('INFO'); } }; // set default setLogLevel(logLevel); exports.getLogLevel = function () { return logLevel; }; exports.trace = function () { return trace.apply(null, arguments); }; exports.debug = function () { return debug.apply(null, arguments); }; exports.error = function () { return error.apply(null, arguments); }; exports.warning = function () { return warning.apply(null, arguments); }; exports.info = function () { return info.apply(null, arguments); }; thrift-0.16.0/lib/nodejs/lib/thrift/multiplexed_processor.js000066400000000000000000000036031420101504100241530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var Thrift = require('./thrift'); exports.MultiplexedProcessor = MultiplexedProcessor; function MultiplexedProcessor(stream, options) { this.services = {}; }; MultiplexedProcessor.prototype.registerProcessor = function(name, handler) { this.services[name] = handler; }; MultiplexedProcessor.prototype.process = function(inp, out) { var begin = inp.readMessageBegin(); if (begin.mtype != Thrift.MessageType.CALL && begin.mtype != Thrift.MessageType.ONEWAY) { throw new Thrift.TException('TMultiplexedProcessor: Unexpected message type'); } var p = begin.fname.split(':'); var sname = p[0]; var fname = p[1]; if (! (sname in this.services)) { throw new Thrift.TException('TMultiplexedProcessor: Unknown service: ' + sname); } //construct a proxy object which stubs the readMessageBegin //for the service var inpProxy = {}; for (var attr in inp) { inpProxy[attr] = inp[attr]; } inpProxy.readMessageBegin = function() { return { fname: fname, mtype: begin.mtype, rseqid: begin.rseqid }; }; this.services[sname].process(inpProxy, out); }; thrift-0.16.0/lib/nodejs/lib/thrift/multiplexed_protocol.js000066400000000000000000000047501420101504100240010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var Thrift = require('./thrift'); exports.Multiplexer = Multiplexer; function Wrapper(serviceName, protocol, connection) { function MultiplexProtocol(trans, strictRead, strictWrite) { protocol.call(this, trans, strictRead, strictWrite); }; util.inherits(MultiplexProtocol, protocol); MultiplexProtocol.prototype.writeMessageBegin = function(name, type, seqid) { if (type == Thrift.MessageType.CALL || type == Thrift.MessageType.ONEWAY) { connection.seqId2Service[seqid] = serviceName; MultiplexProtocol.super_.prototype.writeMessageBegin.call(this, serviceName + ":" + name, type, seqid); } else { MultiplexProtocol.super_.prototype.writeMessageBegin.call(this, name, type, seqid); } }; return MultiplexProtocol; }; function Multiplexer() { this.seqid = 0; }; Multiplexer.prototype.createClient = function(serviceName, ServiceClient, connection) { if (ServiceClient.Client) { ServiceClient = ServiceClient.Client; } var writeCb = function(buf, seqid) { connection.write(buf,seqid); }; var transport = new connection.transport(undefined, writeCb); var protocolWrapper = new Wrapper(serviceName, connection.protocol, connection); var client = new ServiceClient(transport, protocolWrapper); var self = this; client.new_seqid = function() { self.seqid += 1; return self.seqid; }; if (typeof connection.client !== 'object') { connection.client = {}; } connection.client[serviceName] = client; return client; }; thrift-0.16.0/lib/nodejs/lib/thrift/protocol.js000066400000000000000000000017401420101504100213610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ module.exports.TBinaryProtocol = require('./binary_protocol'); module.exports.TCompactProtocol = require('./compact_protocol'); module.exports.TJSONProtocol = require('./json_protocol'); thrift-0.16.0/lib/nodejs/lib/thrift/server.js000066400000000000000000000111511420101504100210230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var constants = require('constants'); var net = require('net'); var tls = require('tls'); var TBufferedTransport = require('./buffered_transport'); var TBinaryProtocol = require('./binary_protocol'); var THeaderProtocol = require('./header_protocol'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); /** * Create a Thrift server which can serve one or multiple services. * @param {object} processor - A normal or multiplexedProcessor (must * be preconstructed with the desired handler). * @param {ServerOptions} options - Optional additional server configuration. * @returns {object} - The Apache Thrift Multiplex Server. */ exports.createMultiplexServer = function(processor, options) { var transport = (options && options.transport) ? options.transport : TBufferedTransport; var protocol = (options && options.protocol) ? options.protocol : TBinaryProtocol; function serverImpl(stream) { var self = this; stream.on('error', function(err) { self.emit('error', err); }); stream.on('data', transport.receiver(function(transportWithData) { var input = new protocol(transportWithData); var outputCb = function(buf) { try { stream.write(buf); } catch (err) { self.emit('error', err); stream.end(); } }; var output = new protocol(new transport(undefined, outputCb)); // Read and write need to be performed on the same transport // for THeaderProtocol because we should only respond with // headers if the request contains headers if (protocol === THeaderProtocol) { output = input; output.trans.onFlush = outputCb; } try { do { processor.process(input, output); transportWithData.commitPosition(); } while (true); } catch (err) { if (err instanceof InputBufferUnderrunError) { //The last data in the buffer was not a complete message, wait for the rest transportWithData.rollbackPosition(); } else if (err.message === "Invalid type: undefined") { //No more data in the buffer //This trap is a bit hackish //The next step to improve the node behavior here is to have // the compiler generated process method throw a more explicit // error when the network buffer is empty (regardles of the // protocol/transport stack in use) and replace this heuristic. // Also transports should probably not force upper layers to // manage their buffer positions (i.e. rollbackPosition() and // commitPosition() should be eliminated in lieu of a transport // encapsulated buffer management strategy.) transportWithData.rollbackPosition(); } else { //Unexpected error self.emit('error', err); stream.end(); } } })); stream.on('end', function() { stream.end(); }); } if (options && options.tls) { if (!('secureProtocol' in options.tls) && !('secureOptions' in options.tls)) { options.tls.secureProtocol = "SSLv23_method"; options.tls.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3; } return tls.createServer(options.tls, serverImpl); } else { return net.createServer(serverImpl); } }; /** * Create a single service Apache Thrift server. * @param {object} processor - A service class or processor function. * @param {ServerOptions} options - Optional additional server configuration. * @returns {object} - The Apache Thrift Multiplex Server. */ exports.createServer = function(processor, handler, options) { if (processor.Processor) { processor = processor.Processor; } return exports.createMultiplexServer(new processor(handler), options); }; thrift-0.16.0/lib/nodejs/lib/thrift/thrift.js000066400000000000000000000124701420101504100210220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var Type = exports.Type = { STOP: 0, VOID: 1, BOOL: 2, BYTE: 3, I08: 3, DOUBLE: 4, I16: 6, I32: 8, I64: 10, STRING: 11, UTF7: 11, STRUCT: 12, MAP: 13, SET: 14, LIST: 15, UTF8: 16, UTF16: 17 }; exports.MessageType = { CALL: 1, REPLY: 2, EXCEPTION: 3, ONEWAY: 4 }; exports.TException = TException; function TException(message) { Error.call(this); if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, this.constructor); } this.name = this.constructor.name; this.message = message; }; util.inherits(TException, Error); var TApplicationExceptionType = exports.TApplicationExceptionType = { UNKNOWN: 0, UNKNOWN_METHOD: 1, INVALID_MESSAGE_TYPE: 2, WRONG_METHOD_NAME: 3, BAD_SEQUENCE_ID: 4, MISSING_RESULT: 5, INTERNAL_ERROR: 6, PROTOCOL_ERROR: 7, INVALID_TRANSFORM: 8, INVALID_PROTOCOL: 9, UNSUPPORTED_CLIENT_TYPE: 10 }; exports.TApplicationException = TApplicationException; function TApplicationException(type, message) { TException.call(this); if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, this.constructor); } this.type = type || TApplicationExceptionType.UNKNOWN; this.name = this.constructor.name; this.message = message; }; util.inherits(TApplicationException, TException); TApplicationException.prototype.read = function(input) { var ftype; var ret = input.readStructBegin('TApplicationException'); while(1){ ret = input.readFieldBegin(); if(ret.ftype == Type.STOP) break; switch(ret.fid){ case 1: if( ret.ftype == Type.STRING ){ ret = input.readString(); this.message = ret; } else { ret = input.skip(ret.ftype); } break; case 2: if( ret.ftype == Type.I32 ){ ret = input.readI32(); this.type = ret; } else { ret = input.skip(ret.ftype); } break; default: ret = input.skip(ret.ftype); break; } input.readFieldEnd(); } input.readStructEnd(); }; TApplicationException.prototype.write = function(output){ output.writeStructBegin('TApplicationException'); if (this.message) { output.writeFieldBegin('message', Type.STRING, 1); output.writeString(this.message); output.writeFieldEnd(); } if (this.code) { output.writeFieldBegin('type', Type.I32, 2); output.writeI32(this.code); output.writeFieldEnd(); } output.writeFieldStop(); output.writeStructEnd(); }; var TProtocolExceptionType = exports.TProtocolExceptionType = { UNKNOWN: 0, INVALID_DATA: 1, NEGATIVE_SIZE: 2, SIZE_LIMIT: 3, BAD_VERSION: 4, NOT_IMPLEMENTED: 5, DEPTH_LIMIT: 6 }; exports.TProtocolException = TProtocolException; function TProtocolException(type, message) { Error.call(this); if (Error.captureStackTrace !== undefined) { Error.captureStackTrace(this, this.constructor); } this.name = this.constructor.name; this.type = type; this.message = message; }; util.inherits(TProtocolException, Error); exports.objectLength = function(obj) { return Object.keys(obj).length; }; exports.inherits = function(constructor, superConstructor) { util.inherits(constructor, superConstructor); }; var copyList, copyMap; copyList = function(lst, types) { if (!lst) {return lst; } var type; if (types.shift === undefined) { type = types; } else { type = types[0]; } var Type = type; var len = lst.length, result = [], i, val; for (i = 0; i < len; i++) { val = lst[i]; if (type === null) { result.push(val); } else if (type === copyMap || type === copyList) { result.push(type(val, types.slice(1))); } else { result.push(new Type(val)); } } return result; }; copyMap = function(obj, types){ if (!obj) {return obj; } var type; if (types.shift === undefined) { type = types; } else { type = types[0]; } var Type = type; var result = {}, val; for(var prop in obj) { if(obj.hasOwnProperty(prop)) { val = obj[prop]; if (type === null) { result[prop] = val; } else if (type === copyMap || type === copyList) { result[prop] = type(val, types.slice(1)); } else { result[prop] = new Type(val); } } } return result; }; module.exports.copyMap = copyMap; module.exports.copyList = copyList; thrift-0.16.0/lib/nodejs/lib/thrift/transport.js000066400000000000000000000017771420101504100215660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ module.exports.TBufferedTransport = require('./buffered_transport'); module.exports.TFramedTransport = require('./framed_transport'); module.exports.InputBufferUnderrunError = require('./input_buffer_underrun_error'); thrift-0.16.0/lib/nodejs/lib/thrift/web_server.js000066400000000000000000000471211420101504100216660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var http = require('http'); var https = require('https'); var url = require("url"); var path = require("path"); var fs = require("fs"); var crypto = require("crypto"); var log = require('./log'); var MultiplexedProcessor = require('./multiplexed_processor').MultiplexedProcessor; var TBufferedTransport = require('./buffered_transport'); var TBinaryProtocol = require('./binary_protocol'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); // WSFrame constructor and prototype ///////////////////////////////////////////////////////////////////// /** Apache Thrift RPC Web Socket Transport * Frame layout conforming to RFC 6455 circa 12/2011 * * Theoretical frame size limit is 4GB*4GB, however the Node Buffer * limit is 1GB as of v0.10. The frame length encoding is also * configured for a max of 4GB presently and needs to be adjusted * if Node/Browsers become capabile of > 4GB frames. * * - FIN is 1 if the message is complete * - RSV1/2/3 are always 0 * - Opcode is 1(TEXT) for TJSONProtocol and 2(BIN) for TBinaryProtocol * - Mask Present bit is 1 sending to-server and 0 sending to-client * - Payload Len: * + If < 126: then represented directly * + If >=126: but within range of an unsigned 16 bit integer * then Payload Len is 126 and the two following bytes store * the length * + Else: Payload Len is 127 and the following 8 bytes store the * length as an unsigned 64 bit integer * - Masking key is a 32 bit key only present when sending to the server * - Payload follows the masking key or length * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-------+-+-------------+-------------------------------+ * |F|R|R|R| opcode|M| Payload len | Extended payload length | * |I|S|S|S| (4) |A| (7) | (16/64) | * |N|V|V|V| |S| | (if payload len==126/127) | * | |1|2|3| |K| | | * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + * | Extended payload length continued, if payload len == 127 | * + - - - - - - - - - - - - - - - +-------------------------------+ * | |Masking-key, if MASK set to 1 | * +-------------------------------+-------------------------------+ * | Masking-key (continued) | Payload Data | * +-------------------------------- - - - - - - - - - - - - - - - + * : Payload Data continued ... : * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * | Payload Data continued ... | * +---------------------------------------------------------------+ */ var wsFrame = { /** Encodes a WebSocket frame * * @param {Buffer} data - The raw data to encode * @param {Buffer} mask - The mask to apply when sending to server, null for no mask * @param {Boolean} binEncoding - True for binary encoding, false for text encoding * @returns {Buffer} - The WebSocket frame, ready to send */ encode: function(data, mask, binEncoding) { var frame = new Buffer(wsFrame.frameSizeFromData(data, mask)); //Byte 0 - FIN & OPCODE frame[0] = wsFrame.fin.FIN + (binEncoding ? wsFrame.frameOpCodes.BIN : wsFrame.frameOpCodes.TEXT); //Byte 1 or 1-3 or 1-9 - MASK FLAG & SIZE var payloadOffset = 2; if (data.length < 0x7E) { frame[1] = data.length + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT); } else if (data.length < 0xFFFF) { frame[1] = 0x7E + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT); frame.writeUInt16BE(data.length, 2, true); payloadOffset = 4; } else { frame[1] = 0x7F + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT); frame.writeUInt32BE(0, 2, true); frame.writeUInt32BE(data.length, 6, true); payloadOffset = 10; } //MASK if (mask) { mask.copy(frame, payloadOffset, 0, 4); payloadOffset += 4; } //Payload data.copy(frame, payloadOffset); if (mask) { wsFrame.applyMask(frame.slice(payloadOffset), frame.slice(payloadOffset-4,payloadOffset)); } return frame; }, /** * @class * @name WSDecodeResult * @property {Buffer} data - The decoded data for the first ATRPC message * @property {Buffer} mask - The frame mask * @property {Boolean} binEncoding - True if binary (TBinaryProtocol), * False if text (TJSONProtocol) * @property {Buffer} nextFrame - Multiple ATRPC messages may be sent in a * single WebSocket frame, this Buffer contains * any bytes remaining to be decoded * @property {Boolean} FIN - True is the message is complete */ /** Decodes a WebSocket frame * * @param {Buffer} frame - The raw inbound frame, if this is a continuation * frame it must have a mask property with the mask. * @returns {WSDecodeResult} - The decoded payload * * @see {@link WSDecodeResult} */ decode: function(frame) { var result = { data: null, mask: null, binEncoding: false, nextFrame: null, FIN: true }; //Byte 0 - FIN & OPCODE if (wsFrame.fin.FIN != (frame[0] & wsFrame.fin.FIN)) { result.FIN = false; } result.binEncoding = (wsFrame.frameOpCodes.BIN == (frame[0] & wsFrame.frameOpCodes.BIN)); //Byte 1 or 1-3 or 1-9 - SIZE var lenByte = (frame[1] & 0x0000007F); var len = lenByte; var dataOffset = 2; if (lenByte == 0x7E) { len = frame.readUInt16BE(2); dataOffset = 4; } else if (lenByte == 0x7F) { len = frame.readUInt32BE(6); dataOffset = 10; } //MASK if (wsFrame.mask.TO_SERVER == (frame[1] & wsFrame.mask.TO_SERVER)) { result.mask = new Buffer(4); frame.copy(result.mask, 0, dataOffset, dataOffset + 4); dataOffset += 4; } //Payload result.data = new Buffer(len); frame.copy(result.data, 0, dataOffset, dataOffset+len); if (result.mask) { wsFrame.applyMask(result.data, result.mask); } //Next Frame if (frame.length > dataOffset+len) { result.nextFrame = new Buffer(frame.length - (dataOffset+len)); frame.copy(result.nextFrame, 0, dataOffset+len, frame.length); } //Don't forward control frames if (frame[0] & wsFrame.frameOpCodes.FINCTRL) { result.data = null; } return result; }, /** Masks/Unmasks data * * @param {Buffer} data - data to mask/unmask in place * @param {Buffer} mask - the mask */ applyMask: function(data, mask){ //TODO: look into xoring words at a time var dataLen = data.length; var maskLen = mask.length; for (var i = 0; i < dataLen; i++) { data[i] = data[i] ^ mask[i%maskLen]; } }, /** Computes frame size on the wire from data to be sent * * @param {Buffer} data - data.length is the assumed payload size * @param {Boolean} mask - true if a mask will be sent (TO_SERVER) */ frameSizeFromData: function(data, mask) { var headerSize = 10; if (data.length < 0x7E) { headerSize = 2; } else if (data.length < 0xFFFF) { headerSize = 4; } return headerSize + data.length + (mask ? 4 : 0); }, frameOpCodes: { CONT: 0x00, TEXT: 0x01, BIN: 0x02, CTRL: 0x80 }, mask: { TO_SERVER: 0x80, TO_CLIENT: 0x00 }, fin: { CONT: 0x00, FIN: 0x80 } }; // createWebServer constructor and options ///////////////////////////////////////////////////////////////////// /** * @class * @name ServerOptions * @property {array} cors - Array of CORS origin strings to permit requests from. * @property {string} files - Path to serve static files from, if absent or "" * static file service is disabled. * @property {object} headers - An object hash mapping header strings to header value * strings, these headers are transmitted in response to * static file GET operations. * @property {object} services - An object hash mapping service URI strings * to ServiceOptions objects * @property {object} tls - Node.js TLS options (see: nodejs.org/api/tls.html), * if not present or null regular http is used, * at least a key and a cert must be defined to use SSL/TLS * @see {@link ServiceOptions} */ /** * @class * @name ServiceOptions * @property {object} transport - The layered transport to use (defaults * to TBufferedTransport). * @property {object} protocol - The serialization Protocol to use (defaults to * TBinaryProtocol). * @property {object} processor - The Thrift Service class/processor generated * by the IDL Compiler for the service (the "cls" * key can also be used for this attribute). * @property {object} handler - The handler methods for the Thrift Service. */ /** * Create a Thrift server which can serve static files and/or one or * more Thrift Services. * @param {ServerOptions} options - The server configuration. * @returns {object} - The Apache Thrift Web Server. */ exports.createWebServer = function(options) { var baseDir = options.files; var contentTypesByExtension = { '.txt': 'text/plain', '.html': 'text/html', '.css': 'text/css', '.xml': 'application/xml', '.json': 'application/json', '.js': 'application/javascript', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.png': 'image/png', '.svg': 'image/svg+xml' }; //Setup all of the services var services = options.services; for (var uri in services) { var svcObj = services[uri]; //Setup the processor if (svcObj.processor instanceof MultiplexedProcessor) { //Multiplex processors have pre embedded processor/handler pairs, save as is svcObj.processor = svcObj.processor; } else { //For historical reasons Node.js supports processors passed in directly or via the // IDL Compiler generated class housing the processor. Also, the options property // for a Processor has been called both cls and processor at different times. We // support any of the four possibilities here. var processor = (svcObj.processor) ? (svcObj.processor.Processor || svcObj.processor) : (svcObj.cls.Processor || svcObj.cls); //Processors can be supplied as constructed objects with handlers already embedded, // if a handler is provided we construct a new processor, if not we use the processor // object directly if (svcObj.handler) { svcObj.processor = new processor(svcObj.handler); } else { svcObj.processor = processor; } } svcObj.transport = svcObj.transport ? svcObj.transport : TBufferedTransport; svcObj.protocol = svcObj.protocol ? svcObj.protocol : TBinaryProtocol; } //Verify CORS requirements function VerifyCORSAndSetHeaders(request, response) { if (request.headers.origin && options.cors) { if (options.cors["*"] || options.cors[request.headers.origin]) { //Allow, origin allowed response.setHeader("access-control-allow-origin", request.headers.origin); response.setHeader("access-control-allow-methods", "GET, POST, OPTIONS"); response.setHeader("access-control-allow-headers", "content-type, accept"); response.setHeader("access-control-max-age", "60"); return true; } else { //Disallow, origin denied return false; } } //Allow, CORS is not in use return true; } //Handle OPTIONS method (CORS) /////////////////////////////////////////////////// function processOptions(request, response) { if (VerifyCORSAndSetHeaders(request, response)) { response.writeHead("204", "No Content", {"content-length": 0}); } else { response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {}); } response.end(); } //Handle POST methods (TXHRTransport) /////////////////////////////////////////////////// function processPost(request, response) { //Lookup service var uri = url.parse(request.url).pathname; var svc = services[uri]; if (!svc) { response.writeHead("403", "No Apache Thrift Service at " + uri, {}); response.end(); return; } //Verify CORS requirements if (!VerifyCORSAndSetHeaders(request, response)) { response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {}); response.end(); return; } //Process XHR payload request.on('data', svc.transport.receiver(function(transportWithData) { var input = new svc.protocol(transportWithData); var output = new svc.protocol(new svc.transport(undefined, function(buf) { try { response.writeHead(200); response.end(buf); } catch (err) { response.writeHead(500); response.end(); } })); try { svc.processor.process(input, output); transportWithData.commitPosition(); } catch (err) { if (err instanceof InputBufferUnderrunError) { transportWithData.rollbackPosition(); } else { response.writeHead(500); response.end(); } } })); } //Handle GET methods (Static Page Server) /////////////////////////////////////////////////// function processGet(request, response) { //Undefined or empty base directory means do not serve static files if (!baseDir || "" === baseDir) { response.writeHead(404); response.end(); return; } //Verify CORS requirements if (!VerifyCORSAndSetHeaders(request, response)) { response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {}); response.end(); return; } //Locate the file requested and send it var uri = url.parse(request.url).pathname; var filename = path.resolve(path.join(baseDir, uri)); //Ensure the basedir path is not able to be escaped if (filename.indexOf(baseDir) != 0) { response.writeHead(400, "Invalid request path", {}); response.end(); return; } fs.exists(filename, function(exists) { if(!exists) { response.writeHead(404); response.end(); return; } if (fs.statSync(filename).isDirectory()) { filename += '/index.html'; } fs.readFile(filename, "binary", function(err, file) { if (err) { response.writeHead(500); response.end(err + "\n"); return; } var headers = {}; var contentType = contentTypesByExtension[path.extname(filename)]; if (contentType) { headers["Content-Type"] = contentType; } for (var k in options.headers) { headers[k] = options.headers[k]; } response.writeHead(200, headers); response.write(file, "binary"); response.end(); }); }); } //Handle WebSocket calls (TWebSocketTransport) /////////////////////////////////////////////////// function processWS(data, socket, svc, binEncoding) { svc.transport.receiver(function(transportWithData) { var input = new svc.protocol(transportWithData); var output = new svc.protocol(new svc.transport(undefined, function(buf) { try { var frame = wsFrame.encode(buf, null, binEncoding); socket.write(frame); } catch (err) { //TODO: Add better error processing } })); try { svc.processor.process(input, output); transportWithData.commitPosition(); } catch (err) { if (err instanceof InputBufferUnderrunError) { transportWithData.rollbackPosition(); } else { //TODO: Add better error processing } } })(data); } //Create the server (HTTP or HTTPS) var server = null; if (options.tls) { server = https.createServer(options.tls); } else { server = http.createServer(); } //Wire up listeners for upgrade(to WebSocket) & request methods for: // - GET static files, // - POST XHR Thrift services // - OPTIONS CORS requests server.on('request', function(request, response) { if (request.method === 'POST') { processPost(request, response); } else if (request.method === 'GET') { processGet(request, response); } else if (request.method === 'OPTIONS') { processOptions(request, response); } else { response.writeHead(500); response.end(); } }).on('upgrade', function(request, socket, head) { //Lookup service var svc; try { svc = services[Object.keys(services)[0]]; } catch(e) { socket.write("HTTP/1.1 403 No Apache Thrift Service available\r\n\r\n"); return; } //Perform upgrade var hash = crypto.createHash("sha1"); hash.update(request.headers['sec-websocket-key'] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); socket.write("HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: " + hash.digest("base64") + "\r\n" + "Sec-WebSocket-Origin: " + request.headers.origin + "\r\n" + "Sec-WebSocket-Location: ws://" + request.headers.host + request.url + "\r\n" + "\r\n"); //Handle WebSocket traffic var data = null; socket.on('data', function(frame) { try { while (frame) { var result = wsFrame.decode(frame); //Prepend any existing decoded data if (data) { if (result.data) { var newData = new Buffer(data.length + result.data.length); data.copy(newData); result.data.copy(newData, data.length); result.data = newData; } else { result.data = data; } data = null; } //If this completes a message process it if (result.FIN) { processWS(result.data, socket, svc, result.binEncoding); } else { data = result.data; } //Prepare next frame for decoding (if any) frame = result.nextFrame; } } catch(e) { log.error('TWebSocketTransport Exception: ' + e); socket.destroy(); } }); }); //Return the server return server; }; thrift-0.16.0/lib/nodejs/lib/thrift/ws_connection.js000066400000000000000000000234701420101504100223740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var WebSocket = require('isomorphic-ws'); var EventEmitter = require("events").EventEmitter; var thrift = require('./thrift'); var TBufferedTransport = require('./buffered_transport'); var TJSONProtocol = require('./json_protocol'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); var createClient = require('./create_client'); var jsEnv = require('browser-or-node'); exports.WSConnection = WSConnection; /** * @class * @name WSConnectOptions * @property {string} transport - The Thrift layered transport to use (TBufferedTransport, etc). * @property {string} protocol - The Thrift serialization protocol to use (TJSONProtocol, etc.). * @property {string} path - The URL path to connect to (e.g. "/", "/mySvc", "/thrift/quoteSvc", etc.). * @property {object} headers - A standard Node.js header hash, an object hash containing key/value * pairs where the key is the header name string and the value is the header value string. * @property {boolean} secure - True causes the connection to use wss, otherwise ws is used. * @property {object} wsOptions - Options passed on to WebSocket. * @example * //Use a secured websocket connection * // uses the buffered transport layer, uses the JSON protocol and directs RPC traffic * // to wss://thrift.example.com:9090/hello * var thrift = require('thrift'); * var options = { * transport: thrift.TBufferedTransport, * protocol: thrift.TJSONProtocol, * path: "/hello", * secure: true * }; * var con = thrift.createWSConnection("thrift.example.com", 9090, options); * con.open() * var client = thrift.createWSClient(myService, connection); * client.myServiceFunction(); * con.close() */ /** * Initializes a Thrift WSConnection instance (use createWSConnection() rather than * instantiating directly). * @constructor * @param {string} host - The host name or IP to connect to. * @param {number} port - The TCP port to connect to. * @param {WSConnectOptions} options - The configuration options to use. * @throws {error} Exceptions other than ttransport.InputBufferUnderrunError are rethrown * @event {error} The "error" event is fired when a Node.js error event occurs during * request or response processing, in which case the node error is passed on. An "error" * event may also be fired when the connection can not map a response back to the * appropriate client (an internal error), generating a TApplicationException. * @classdesc WSConnection objects provide Thrift end point transport * semantics implemented using Websockets. * @see {@link createWSConnection} */ function WSConnection(host, port, options) { //Initialize the emitter base object EventEmitter.call(this); //Set configuration this.options = options || {}; this.host = host; this.port = port; this.secure = this.options.secure || false; this.transport = this.options.transport || TBufferedTransport; this.protocol = this.options.protocol || TJSONProtocol; this.path = this.options.path; this.send_pending = []; //The sequence map is used to map seqIDs back to the // calling client in multiplexed scenarios this.seqId2Service = {}; //Prepare WebSocket options this.wsOptions = { host: this.host, port: this.port || 80, path: this.options.path || '/', headers: this.options.headers || {} }; for (var attrname in this.options.wsOptions) { this.wsOptions[attrname] = this.options.wsOptions[attrname]; } }; util.inherits(WSConnection, EventEmitter); WSConnection.prototype.__reset = function() { this.socket = null; //The web socket this.send_pending = []; //Buffers/Callback pairs waiting to be sent }; WSConnection.prototype.__onOpen = function() { this.emit("open"); if (this.send_pending.length > 0) { //If the user made calls before the connection was fully //open, send them now this.send_pending.forEach(function(data) { this.socket.send(data); }, this); this.send_pending = []; } }; WSConnection.prototype.__onClose = function(evt) { this.emit("close"); this.__reset(); }; WSConnection.prototype.__decodeCallback = function(transport_with_data) { var proto = new this.protocol(transport_with_data); try { while (true) { var header = proto.readMessageBegin(); var dummy_seqid = header.rseqid * -1; var client = this.client; //The Multiplexed Protocol stores a hash of seqid to service names // in seqId2Service. If the SeqId is found in the hash we need to // lookup the appropriate client for this call. // The client var is a single client object when not multiplexing, // when using multiplexing it is a service name keyed hash of client // objects. //NOTE: The 2 way interdependencies between protocols, transports, // connections and clients in the Node.js implementation are irregular // and make the implementation difficult to extend and maintain. We // should bring this stuff inline with typical thrift I/O stack // operation soon. // --ra var service_name = this.seqId2Service[header.rseqid]; if (service_name) { client = this.client[service_name]; delete this.seqId2Service[header.rseqid]; } /*jshint -W083 */ client._reqs[dummy_seqid] = function(err, success) { transport_with_data.commitPosition(); var clientCallback = client._reqs[header.rseqid]; delete client._reqs[header.rseqid]; if (clientCallback) { clientCallback(err, success); } }; /*jshint +W083 */ if (client['recv_' + header.fname]) { client['recv_' + header.fname](proto, header.mtype, dummy_seqid); } else { delete client._reqs[dummy_seqid]; this.emit("error", new thrift.TApplicationException( thrift.TApplicationExceptionType.WRONG_METHOD_NAME, "Received a response to an unknown RPC function")); } } } catch (e) { if (e instanceof InputBufferUnderrunError) { transport_with_data.rollbackPosition(); } else { throw e; } } }; WSConnection.prototype.__onData = function(data) { if (Object.prototype.toString.call(data) === "[object ArrayBuffer]") { data = new Uint8Array(data); } var buf = new Buffer(data); this.transport.receiver(this.__decodeCallback.bind(this))(buf); }; WSConnection.prototype.__onMessage = function(evt) { this.__onData(evt.data); }; WSConnection.prototype.__onError = function(evt) { this.emit("error", evt); this.socket.close(); }; /** * Returns true if the transport is open * @readonly * @returns {boolean} */ WSConnection.prototype.isOpen = function() { return this.socket && this.socket.readyState === this.socket.OPEN; }; /** * Opens the transport connection */ WSConnection.prototype.open = function() { //If OPEN/CONNECTING/CLOSING ignore additional opens if (this.socket && this.socket.readyState !== this.socket.CLOSED) { return; } //If there is no socket or the socket is closed: if (jsEnv.isBrowser) { this.socket = new WebSocket(this.uri()); } else { this.socket = new WebSocket(this.uri(), "", this.wsOptions); } this.socket.binaryType = 'arraybuffer'; this.socket.onopen = this.__onOpen.bind(this); this.socket.onmessage = this.__onMessage.bind(this); this.socket.onerror = this.__onError.bind(this); this.socket.onclose = this.__onClose.bind(this); }; /** * Closes the transport connection */ WSConnection.prototype.close = function() { this.socket.close(); }; /** * Return URI for the connection * @returns {string} URI */ WSConnection.prototype.uri = function() { var schema = this.secure ? 'wss' : 'ws'; var port = ''; var path = this.path || '/'; var host = this.host; // avoid port if default for schema if (this.port && (('wss' === schema && this.port !== 443) || ('ws' === schema && this.port !== 80))) { port = ':' + this.port; } return schema + '://' + host + port + path; }; /** * Writes Thrift message data to the connection * @param {Buffer} data - A Node.js Buffer containing the data to write * @returns {void} No return value. * @event {error} the "error" event is raised upon request failure passing the * Node.js error object to the listener. */ WSConnection.prototype.write = function(data) { if (this.isOpen()) { //Send data and register a callback to invoke the client callback this.socket.send(data); } else { //Queue the send to go out __onOpen this.send_pending.push(data); } }; /** * Creates a new WSConnection object, used by Thrift clients to connect * to Thrift HTTP based servers. * @param {string} host - The host name or IP to connect to. * @param {number} port - The TCP port to connect to. * @param {WSConnectOptions} options - The configuration options to use. * @returns {WSConnection} The connection object. * @see {@link WSConnectOptions} */ exports.createWSConnection = function(host, port, options) { return new WSConnection(host, port, options); }; exports.createWSClient = createClient; thrift-0.16.0/lib/nodejs/lib/thrift/ws_transport.js000066400000000000000000000134711420101504100222710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var log = require('./log'); module.exports = TWebSocketTransport; /** * Constructor Function for the WebSocket transport. * @constructor * @param {string} [url] - The URL to connect to. * @classdesc The Apache Thrift Transport layer performs byte level I/O * between RPC clients and servers. The JavaScript TWebSocketTransport object * uses the WebSocket protocol. Target servers must implement WebSocket. * (see: node.js example server_http.js). * @example * var transport = new Thrift.TWebSocketTransport("http://localhost:8585"); */ function TWebSocketTransport(url) { this.__reset(url); }; TWebSocketTransport.prototype.__reset = function(url) { this.url = url; //Where to connect this.socket = null; //The web socket this.callbacks = []; //Pending callbacks this.send_pending = []; //Buffers/Callback pairs waiting to be sent this.send_buf = ''; //Outbound data, immutable until sent this.recv_buf = ''; //Inbound data this.rb_wpos = 0; //Network write position in receive buffer this.rb_rpos = 0; //Client read position in receive buffer }; /** * Sends the current WS request and registers callback. The async * parameter is ignored (WS flush is always async) and the callback * function parameter is required. * @param {object} async - Ignored. * @param {object} callback - The client completion callback. * @returns {undefined|string} Nothing (undefined) */ TWebSocketTransport.prototype.flush = function(async, callback) { var self = this; if (this.isOpen()) { //Send data and register a callback to invoke the client callback this.socket.send(this.send_buf); this.callbacks.push((function() { var clientCallback = callback; return function(msg) { self.setRecvBuffer(msg); clientCallback(); }; }())); } else { //Queue the send to go out __onOpen this.send_pending.push({ buf: this.send_buf, cb: callback }); } }; TWebSocketTransport.prototype.__onOpen = function() { var self = this; if (this.send_pending.length > 0) { //If the user made calls before the connection was fully //open, send them now this.send_pending.forEach(function(elem) { self.socket.send(elem.buf); self.callbacks.push((function() { var clientCallback = elem.cb; return function(msg) { self.setRecvBuffer(msg); clientCallback(); }; }())); }); this.send_pending = []; } }; TWebSocketTransport.prototype.__onClose = function(evt) { this.__reset(this.url); }; TWebSocketTransport.prototype.__onMessage = function(evt) { if (this.callbacks.length) { this.callbacks.shift()(evt.data); } }; TWebSocketTransport.prototype.__onError = function(evt) { log.error('websocket: ' + evt.toString()); this.socket.close(); }; /** * Sets the buffer to use when receiving server responses. * @param {string} buf - The buffer to receive server responses. */ TWebSocketTransport.prototype.setRecvBuffer = function(buf) { this.recv_buf = buf; this.recv_buf_sz = this.recv_buf.length; this.wpos = this.recv_buf.length; this.rpos = 0; }; /** * Returns true if the transport is open * @readonly * @returns {boolean} */ TWebSocketTransport.prototype.isOpen = function() { return this.socket && this.socket.readyState == this.socket.OPEN; }; /** * Opens the transport connection */ TWebSocketTransport.prototype.open = function() { //If OPEN/CONNECTING/CLOSING ignore additional opens if (this.socket && this.socket.readyState != this.socket.CLOSED) { return; } //If there is no socket or the socket is closed: this.socket = new WebSocket(this.url); this.socket.onopen = this.__onOpen.bind(this); this.socket.onmessage = this.__onMessage.bind(this); this.socket.onerror = this.__onError.bind(this); this.socket.onclose = this.__onClose.bind(this); }; /** * Closes the transport connection */ TWebSocketTransport.prototype.close = function() { this.socket.close(); }; /** * Returns the specified number of characters from the response * buffer. * @param {number} len - The number of characters to return. * @returns {string} Characters sent by the server. */ TWebSocketTransport.prototype.read = function(len) { var avail = this.wpos - this.rpos; if (avail === 0) { return ''; } var give = len; if (avail < len) { give = avail; } var ret = this.read_buf.substr(this.rpos, give); this.rpos += give; //clear buf when complete? return ret; }; /** * Returns the entire response buffer. * @returns {string} Characters sent by the server. */ TWebSocketTransport.prototype.readAll = function() { return this.recv_buf; }; /** * Sets the send buffer to buf. * @param {string} buf - The buffer to send. */ TWebSocketTransport.prototype.write = function(buf) { this.send_buf = buf; }; /** * Returns the send buffer. * @readonly * @returns {string} The send buffer. */ TWebSocketTransport.prototype.getSendBuffer = function() { return this.send_buf; }; thrift-0.16.0/lib/nodejs/lib/thrift/xhr_connection.js000066400000000000000000000210031420101504100225320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var util = require('util'); var EventEmitter = require("events").EventEmitter; var thrift = require('./thrift'); var TBufferedTransport = require('./buffered_transport'); var TJSONProtocol = require('./json_protocol'); var InputBufferUnderrunError = require('./input_buffer_underrun_error'); var createClient = require('./create_client'); exports.XHRConnection = XHRConnection; /** * Constructor Function for the XHR Connection. * If you do not specify a host and port then XHRConnection will default to the * host and port of the page from which this javascript is served. * @constructor * @param {string} [url] - The URL to connect to. * @classdesc TXHRConnection objects provide Thrift end point transport * semantics implemented using XHR. * @example * var transport = new Thrift.TXHRConnection('localhost', 9099, {}); */ function XHRConnection(host, port, options) { this.options = options || {}; this.wpos = 0; this.rpos = 0; this.useCORS = (options && options.useCORS); this.send_buf = ''; this.recv_buf = ''; this.transport = options.transport || TBufferedTransport; this.protocol = options.protocol || TJSONProtocol; this.headers = options.headers || {}; host = host || window.location.host; port = port || window.location.port; var prefix = options.https ? 'https://' : 'http://'; var path = options.path || '/'; if (port === '') { port = undefined; } if (!port || port === 80 || port === '80') { this.url = prefix + host + path; } else { this.url = prefix + host + ':' + port + path; } //The sequence map is used to map seqIDs back to the // calling client in multiplexed scenarios this.seqId2Service = {}; }; util.inherits(XHRConnection, EventEmitter); /** * Gets the browser specific XmlHttpRequest Object. * @returns {object} the browser XHR interface object */ XHRConnection.prototype.getXmlHttpRequestObject = function() { try { return new XMLHttpRequest(); } catch (e1) { } try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { } try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { } throw "Your browser doesn't support XHR."; }; /** * Sends the current XRH request if the transport was created with a URL * and the async parameter is false. If the transport was not created with * a URL, or the async parameter is True and no callback is provided, or * the URL is an empty string, the current send buffer is returned. * @param {object} async - If true the current send buffer is returned. * @param {object} callback - Optional async completion callback * @returns {undefined|string} Nothing or the current send buffer. * @throws {string} If XHR fails. */ XHRConnection.prototype.flush = function() { var self = this; if (this.url === undefined || this.url === '') { return this.send_buf; } var xreq = this.getXmlHttpRequestObject(); if (xreq.overrideMimeType) { xreq.overrideMimeType('application/json'); } xreq.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { self.setRecvBuffer(this.responseText); } }; xreq.open('POST', this.url, true); Object.keys(this.headers).forEach(function(headerKey) { xreq.setRequestHeader(headerKey, self.headers[headerKey]); }); xreq.send(this.send_buf); }; /** * Sets the buffer to provide the protocol when deserializing. * @param {string} buf - The buffer to supply the protocol. */ XHRConnection.prototype.setRecvBuffer = function(buf) { this.recv_buf = buf; this.recv_buf_sz = this.recv_buf.length; this.wpos = this.recv_buf.length; this.rpos = 0; if (Object.prototype.toString.call(buf) == "[object ArrayBuffer]") { var data = new Uint8Array(buf); } var thing = new Buffer(data || buf); this.transport.receiver(this.__decodeCallback.bind(this))(thing); }; XHRConnection.prototype.__decodeCallback = function(transport_with_data) { var proto = new this.protocol(transport_with_data); try { while (true) { var header = proto.readMessageBegin(); var dummy_seqid = header.rseqid * -1; var client = this.client; //The Multiplexed Protocol stores a hash of seqid to service names // in seqId2Service. If the SeqId is found in the hash we need to // lookup the appropriate client for this call. // The client var is a single client object when not multiplexing, // when using multiplexing it is a service name keyed hash of client // objects. //NOTE: The 2 way interdependencies between protocols, transports, // connections and clients in the Node.js implementation are irregular // and make the implementation difficult to extend and maintain. We // should bring this stuff inline with typical thrift I/O stack // operation soon. // --ra var service_name = this.seqId2Service[header.rseqid]; if (service_name) { client = this.client[service_name]; delete this.seqId2Service[header.rseqid]; } /*jshint -W083 */ client._reqs[dummy_seqid] = function(err, success) { transport_with_data.commitPosition(); var clientCallback = client._reqs[header.rseqid]; delete client._reqs[header.rseqid]; if (clientCallback) { clientCallback(err, success); } }; /*jshint +W083 */ if (client['recv_' + header.fname]) { client['recv_' + header.fname](proto, header.mtype, dummy_seqid); } else { delete client._reqs[dummy_seqid]; this.emit("error", new thrift.TApplicationException( thrift.TApplicationExceptionType.WRONG_METHOD_NAME, "Received a response to an unknown RPC function")); } } } catch (e) { if (e instanceof InputBufferUnderrunError) { transport_with_data.rollbackPosition(); } else { throw e; } } }; /** * Returns true if the transport is open, XHR always returns true. * @readonly * @returns {boolean} Always True. */ XHRConnection.prototype.isOpen = function() { return true; }; /** * Opens the transport connection, with XHR this is a nop. */ XHRConnection.prototype.open = function() {}; /** * Closes the transport connection, with XHR this is a nop. */ XHRConnection.prototype.close = function() {}; /** * Returns the specified number of characters from the response * buffer. * @param {number} len - The number of characters to return. * @returns {string} Characters sent by the server. */ XHRConnection.prototype.read = function(len) { var avail = this.wpos - this.rpos; if (avail === 0) { return ''; } var give = len; if (avail < len) { give = avail; } var ret = this.read_buf.substr(this.rpos, give); this.rpos += give; //clear buf when complete? return ret; }; /** * Returns the entire response buffer. * @returns {string} Characters sent by the server. */ XHRConnection.prototype.readAll = function() { return this.recv_buf; }; /** * Sets the send buffer to buf. * @param {string} buf - The buffer to send. */ XHRConnection.prototype.write = function(buf) { this.send_buf = buf; this.flush(); }; /** * Returns the send buffer. * @readonly * @returns {string} The send buffer. */ XHRConnection.prototype.getSendBuffer = function() { return this.send_buf; }; /** * Creates a new TXHRTransport object, used by Thrift clients to connect * to Thrift HTTP based servers. * @param {string} host - The host name or IP to connect to. * @param {number} port - The TCP port to connect to. * @param {XHRConnectOptions} options - The configuration options to use. * @returns {XHRConnection} The connection object. * @see {@link XHRConnectOptions} */ exports.createXHRConnection = function(host, port, options) { return new XHRConnection(host, port, options); }; exports.createXHRClient = createClient; thrift-0.16.0/lib/nodejs/test/000077500000000000000000000000001420101504100160715ustar00rootroot00000000000000thrift-0.16.0/lib/nodejs/test/binary.test.js000066400000000000000000000144071420101504100206770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const test = require("tape"); const binary = require("thrift/binary"); const cases = { "Should read signed byte": function(assert) { assert.equal(1, binary.readByte(0x01)); assert.equal(-1, binary.readByte(0xff)); assert.equal(127, binary.readByte(0x7f)); assert.equal(-128, binary.readByte(0x80)); assert.end(); }, "Should write byte": function(assert) { //Protocol simply writes to the buffer. Nothing to test.. yet. assert.ok(true); assert.end(); }, "Should read I16": function(assert) { assert.equal(0, binary.readI16([0x00, 0x00])); assert.equal(1, binary.readI16([0x00, 0x01])); assert.equal(-1, binary.readI16([0xff, 0xff])); // Min I16 assert.equal(-32768, binary.readI16([0x80, 0x00])); // Max I16 assert.equal(32767, binary.readI16([0x7f, 0xff])); assert.end(); }, "Should write I16": function(assert) { assert.deepEqual([0x00, 0x00], binary.writeI16([], 0)); assert.deepEqual([0x00, 0x01], binary.writeI16([], 1)); assert.deepEqual([0xff, 0xff], binary.writeI16([], -1)); // Min I16 assert.deepEqual([0x80, 0x00], binary.writeI16([], -32768)); // Max I16 assert.deepEqual([0x7f, 0xff], binary.writeI16([], 32767)); assert.end(); }, "Should read I32": function(assert) { assert.equal(0, binary.readI32([0x00, 0x00, 0x00, 0x00])); assert.equal(1, binary.readI32([0x00, 0x00, 0x00, 0x01])); assert.equal(-1, binary.readI32([0xff, 0xff, 0xff, 0xff])); // Min I32 assert.equal(-2147483648, binary.readI32([0x80, 0x00, 0x00, 0x00])); // Max I32 assert.equal(2147483647, binary.readI32([0x7f, 0xff, 0xff, 0xff])); assert.end(); }, "Should write I32": function(assert) { assert.deepEqual([0x00, 0x00, 0x00, 0x00], binary.writeI32([], 0)); assert.deepEqual([0x00, 0x00, 0x00, 0x01], binary.writeI32([], 1)); assert.deepEqual([0xff, 0xff, 0xff, 0xff], binary.writeI32([], -1)); // Min I32 assert.deepEqual( [0x80, 0x00, 0x00, 0x00], binary.writeI32([], -2147483648) ); // Max I32 assert.deepEqual([0x7f, 0xff, 0xff, 0xff], binary.writeI32([], 2147483647)); assert.end(); }, "Should read doubles": function(assert) { assert.equal( 0, binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); assert.equal( 0, binary.readDouble([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); assert.equal( 1, binary.readDouble([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); assert.equal( 2, binary.readDouble([0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); assert.equal( -2, binary.readDouble([0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); assert.equal( Math.PI, binary.readDouble([0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18]) ); assert.equal( Infinity, binary.readDouble([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); assert.equal( -Infinity, binary.readDouble([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); assert.ok( isNaN(binary.readDouble([0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) ); assert.equal( 1 / 3, binary.readDouble([0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55]) ); // Min subnormal positive double assert.equal( 4.9406564584124654e-324, binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]) ); // Min normal positive double assert.equal( 2.2250738585072014e-308, binary.readDouble([0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ); // Max positive double assert.equal( 1.7976931348623157e308, binary.readDouble([0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]) ); assert.end(); }, "Should write doubles": function(assert) { assert.deepEqual( [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 0) ); assert.deepEqual( [0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 1) ); assert.deepEqual( [0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 2) ); assert.deepEqual( [0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], -2) ); assert.deepEqual( [0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18], binary.writeDouble([], Math.PI) ); assert.deepEqual( [0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], Infinity) ); assert.deepEqual( [0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], -Infinity) ); assert.deepEqual( [0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], NaN) ); assert.deepEqual( [0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55], binary.writeDouble([], 1 / 3) ); // Min subnormal positive double assert.deepEqual( [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], binary.writeDouble([], 4.9406564584124654e-324) ); // Min normal positive double assert.deepEqual( [0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 2.2250738585072014e-308) ); // Max positive double assert.deepEqual( [0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], binary.writeDouble([], 1.7976931348623157e308) ); assert.end(); } }; Object.keys(cases).forEach(function(caseName) { test(caseName, cases[caseName]); }); thrift-0.16.0/lib/nodejs/test/certificates.README000066400000000000000000000003511420101504100214140ustar00rootroot00000000000000server.crt AND server.key ARE PROVIDED FOR TEST PURPOSE AND SHOULD *NEVER* BE USED IN PRODUCTION Origin of the test key and cert is the folder test/keys of Apache Thrift source code distribution We need copies for npm deployment thrift-0.16.0/lib/nodejs/test/client.js000066400000000000000000000116351420101504100177130ustar00rootroot00000000000000#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const assert = require("assert"); const thrift = require("thrift"); const helpers = require("./helpers"); const ThriftTest = require(`./${helpers.genPath}/ThriftTest`); const ThriftTestDriver = require("./test_driver").ThriftTestDriver; const ThriftTestDriverPromise = require("./test_driver") .ThriftTestDriverPromise; const SecondService = require(`./${helpers.genPath}/SecondService`); const program = require("commander"); program .option( "-p, --protocol ", "Set thrift protocol (binary|compact|json) [protocol]" ) .option( "-t, --transport ", "Set thrift transport (buffered|framed|http) [transport]" ) .option("--port ", "Set thrift server port number to connect", 9090) .option("--host ", "Set thrift server host to connect", "localhost") .option( "--domain-socket ", "Set thrift server unix domain socket to connect" ) .option("--ssl", "use SSL transport") .option("--callback", "test with callback style functions") .option( "-t, --type ", "Select server type (http|multiplex|tcp|websocket)", "tcp" ) .option("--es6", "Use es6 code") .option("--es5", "Use es5 code") .parse(process.argv); const host = program.host; const port = program.port; const domainSocket = program.domainSocket; const ssl = program.ssl; let type = program.type; /* for compatibility with cross test invocation for http transport testing */ if (program.transport === "http") { program.transport = "buffered"; type = "http"; } if (program.transport === "websocket") { program.transport = "buffered"; type = "websocket"; } const options = { transport: helpers.transports[program.transport], protocol: helpers.protocols[program.protocol] }; if (type === "http" || type === "websocket") { options.path = "/test"; } if (type === "http") { options.headers = { Connection: "close" }; } if (ssl) { if (type === "tcp" || type === "multiplex") { options.rejectUnauthorized = false; } else if (type === "http") { options.nodeOptions = { rejectUnauthorized: false }; options.https = true; } else if (type === "websocket") { options.wsOptions = { rejectUnauthorized: false }; options.secure = true; } } let connection; let client; const testDriver = program.callback ? ThriftTestDriver : ThriftTestDriverPromise; if (helpers.ecmaMode === "es6" && program.callback) { console.log("ES6 does not support callback style"); process.exit(0); } if (type === "tcp" || type === "multiplex") { if (domainSocket) { connection = thrift.createUDSConnection(domainSocket, options); } else { connection = ssl ? thrift.createSSLConnection(host, port, options) : thrift.createConnection(host, port, options); } } else if (type === "http") { if (domainSocket) { connection = thrift.createHttpUDSConnection(domainSocket, options); } else { connection = thrift.createHttpConnection(host, port, options); } } else if (type === "websocket") { connection = thrift.createWSConnection(host, port, options); connection.open(); } connection.on("error", function(err) { assert(false, err); }); if (type === "tcp") { client = thrift.createClient(ThriftTest, connection); runTests(); } else if (type === "multiplex") { const mp = new thrift.Multiplexer(); client = mp.createClient("ThriftTest", ThriftTest, connection); const secondclient = mp.createClient( "SecondService", SecondService, connection ); connection.on("connect", function() { secondclient.secondtestString("Test", function(err, response) { assert(!err); assert.equal('testString("Test")', response); }); runTests(); }); } else if (type === "http") { client = thrift.createHttpClient(ThriftTest, connection); runTests(); } else if (type === "websocket") { client = thrift.createWSClient(ThriftTest, connection); runTests(); } function runTests() { testDriver(client, function(status) { console.log(status); if (type !== "http" && type !== "websocket") { connection.end(); } if (type !== "multiplex") { process.exit(0); } }); } exports.expressoTest = function() {}; thrift-0.16.0/lib/nodejs/test/deep-constructor.test.js000066400000000000000000000246531420101504100227170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const ttypes = require("./gen-nodejs/JsDeepConstructorTest_types"); const thrift = require("thrift"); const test = require("tape"); const bufferEquals = require("buffer-equals"); function serializeBinary(data) { let buff; const transport = new thrift.TBufferedTransport(null, function(msg) { buff = msg; }); const prot = new thrift.TBinaryProtocol(transport); data.write(prot); prot.flush(); return buff; } function deserializeBinary(serialized, type) { const t = new thrift.TFramedTransport(serialized); const p = new thrift.TBinaryProtocol(t); const data = new type(); data.read(p); return data; } function serializeJSON(data) { let buff; const transport = new thrift.TBufferedTransport(null, function(msg) { buff = msg; }); const protocol = new thrift.TJSONProtocol(transport); protocol.writeMessageBegin("", 0, 0); data.write(protocol); protocol.writeMessageEnd(); protocol.flush(); return buff; } function deserializeJSON(serialized, type) { const transport = new thrift.TFramedTransport(serialized); const protocol = new thrift.TJSONProtocol(transport); protocol.readMessageBegin(); const data = new type(); data.read(protocol); protocol.readMessageEnd(); return data; } function createThriftObj() { return new ttypes.Complex({ struct_field: new ttypes.Simple({ value: "a" }), struct_list_field: [ new ttypes.Simple({ value: "b" }), new ttypes.Simple({ value: "c" }) ], struct_set_field: [ new ttypes.Simple({ value: "d" }), new ttypes.Simple({ value: "e" }) ], struct_map_field: { A: new ttypes.Simple({ value: "f" }), B: new ttypes.Simple({ value: "g" }) }, struct_nested_containers_field: [ [ { C: [ new ttypes.Simple({ value: "h" }), new ttypes.Simple({ value: "i" }) ] } ] ], struct_nested_containers_field2: { D: [ { DA: new ttypes.Simple({ value: "j" }) }, { DB: new ttypes.Simple({ value: "k" }) } ] }, list_of_list_field: [ ["l00", "l01", "l02"], ["l10", "l11", "l12"], ["l20", "l21", "l22"] ], list_of_list_of_list_field: [ [ ["m000", "m001", "m002"], ["m010", "m011", "m012"], ["m020", "m021", "m022"] ], [ ["m100", "m101", "m102"], ["m110", "m111", "m112"], ["m120", "m121", "m122"] ], [ ["m200", "m201", "m202"], ["m210", "m211", "m212"], ["m220", "m221", "m222"] ] ] }); } function createJsObj() { return { struct_field: { value: "a" }, struct_list_field: [{ value: "b" }, { value: "c" }], struct_set_field: [{ value: "d" }, { value: "e" }], struct_map_field: { A: { value: "f" }, B: { value: "g" } }, struct_nested_containers_field: [ [ { C: [{ value: "h" }, { value: "i" }] } ] ], struct_nested_containers_field2: { D: [ { DA: { value: "j" } }, { DB: { value: "k" } } ] }, list_of_list_field: [ ["l00", "l01", "l02"], ["l10", "l11", "l12"], ["l20", "l21", "l22"] ], list_of_list_of_list_field: [ [ ["m000", "m001", "m002"], ["m010", "m011", "m012"], ["m020", "m021", "m022"] ], [ ["m100", "m101", "m102"], ["m110", "m111", "m112"], ["m120", "m121", "m122"] ], [ ["m200", "m201", "m202"], ["m210", "m211", "m212"], ["m220", "m221", "m222"] ] ] }; } function assertValues(obj, assert) { assert.equals(obj.struct_field.value, "a"); assert.equals(obj.struct_list_field[0].value, "b"); assert.equals(obj.struct_list_field[1].value, "c"); assert.equals(obj.struct_set_field[0].value, "d"); assert.equals(obj.struct_set_field[1].value, "e"); assert.equals(obj.struct_map_field.A.value, "f"); assert.equals(obj.struct_map_field.B.value, "g"); assert.equals(obj.struct_nested_containers_field[0][0].C[0].value, "h"); assert.equals(obj.struct_nested_containers_field[0][0].C[1].value, "i"); assert.equals(obj.struct_nested_containers_field2.D[0].DA.value, "j"); assert.equals(obj.struct_nested_containers_field2.D[1].DB.value, "k"); assert.equals(obj.list_of_list_field[0][0], "l00"); assert.equals(obj.list_of_list_field[0][1], "l01"); assert.equals(obj.list_of_list_field[0][2], "l02"); assert.equals(obj.list_of_list_field[1][0], "l10"); assert.equals(obj.list_of_list_field[1][1], "l11"); assert.equals(obj.list_of_list_field[1][2], "l12"); assert.equals(obj.list_of_list_field[2][0], "l20"); assert.equals(obj.list_of_list_field[2][1], "l21"); assert.equals(obj.list_of_list_field[2][2], "l22"); assert.equals(obj.list_of_list_of_list_field[0][0][0], "m000"); assert.equals(obj.list_of_list_of_list_field[0][0][1], "m001"); assert.equals(obj.list_of_list_of_list_field[0][0][2], "m002"); assert.equals(obj.list_of_list_of_list_field[0][1][0], "m010"); assert.equals(obj.list_of_list_of_list_field[0][1][1], "m011"); assert.equals(obj.list_of_list_of_list_field[0][1][2], "m012"); assert.equals(obj.list_of_list_of_list_field[0][2][0], "m020"); assert.equals(obj.list_of_list_of_list_field[0][2][1], "m021"); assert.equals(obj.list_of_list_of_list_field[0][2][2], "m022"); assert.equals(obj.list_of_list_of_list_field[1][0][0], "m100"); assert.equals(obj.list_of_list_of_list_field[1][0][1], "m101"); assert.equals(obj.list_of_list_of_list_field[1][0][2], "m102"); assert.equals(obj.list_of_list_of_list_field[1][1][0], "m110"); assert.equals(obj.list_of_list_of_list_field[1][1][1], "m111"); assert.equals(obj.list_of_list_of_list_field[1][1][2], "m112"); assert.equals(obj.list_of_list_of_list_field[1][2][0], "m120"); assert.equals(obj.list_of_list_of_list_field[1][2][1], "m121"); assert.equals(obj.list_of_list_of_list_field[1][2][2], "m122"); assert.equals(obj.list_of_list_of_list_field[2][0][0], "m200"); assert.equals(obj.list_of_list_of_list_field[2][0][1], "m201"); assert.equals(obj.list_of_list_of_list_field[2][0][2], "m202"); assert.equals(obj.list_of_list_of_list_field[2][1][0], "m210"); assert.equals(obj.list_of_list_of_list_field[2][1][1], "m211"); assert.equals(obj.list_of_list_of_list_field[2][1][2], "m212"); assert.equals(obj.list_of_list_of_list_field[2][2][0], "m220"); assert.equals(obj.list_of_list_of_list_field[2][2][1], "m221"); assert.equals(obj.list_of_list_of_list_field[2][2][2], "m222"); } function createTestCases(serialize, deserialize) { const cases = { "Serialize/deserialize should return equal object": function(assert) { const tObj = createThriftObj(); const received = deserialize(serialize(tObj), ttypes.Complex); assert.ok(tObj !== received, "not the same object"); assert.deepEqual(tObj, received); assert.end(); }, "Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects": function( assert ) { const tObj1 = createThriftObj(); const tObj2 = new ttypes.Complex(createJsObj()); assertValues(tObj2, assert); const s1 = serialize(tObj1); const s2 = serialize(tObj2); assert.ok(bufferEquals(s1, s2)); assert.end(); }, "Modifications to args object should not affect constructed Thrift object": function( assert ) { const args = createJsObj(); assertValues(args, assert); const tObj = new ttypes.Complex(args); assertValues(tObj, assert); args.struct_field.value = "ZZZ"; args.struct_list_field[0].value = "ZZZ"; args.struct_list_field[1].value = "ZZZ"; args.struct_set_field[0].value = "ZZZ"; args.struct_set_field[1].value = "ZZZ"; args.struct_map_field.A.value = "ZZZ"; args.struct_map_field.B.value = "ZZZ"; args.struct_nested_containers_field[0][0].C[0] = "ZZZ"; args.struct_nested_containers_field[0][0].C[1] = "ZZZ"; args.struct_nested_containers_field2.D[0].DA = "ZZZ"; args.struct_nested_containers_field2.D[0].DB = "ZZZ"; assertValues(tObj, assert); assert.end(); }, "nulls are ok": function(assert) { const tObj = new ttypes.Complex({ struct_field: null, struct_list_field: null, struct_set_field: null, struct_map_field: null, struct_nested_containers_field: null, struct_nested_containers_field2: null }); const received = deserialize(serialize(tObj), ttypes.Complex); assert.strictEqual(tObj.struct_field, null); assert.ok(tObj !== received); assert.deepEqual(tObj, received); assert.end(); }, "Can make list with objects": function(assert) { const tObj = new ttypes.ComplexList({ struct_list_field: [new ttypes.Complex({})] }); const innerObj = tObj.struct_list_field[0]; assert.ok(innerObj instanceof ttypes.Complex); assert.strictEqual(innerObj.struct_field, null); assert.strictEqual(innerObj.struct_list_field, null); assert.strictEqual(innerObj.struct_set_field, null); assert.strictEqual(innerObj.struct_map_field, null); assert.strictEqual(innerObj.struct_nested_containers_field, null); assert.strictEqual(innerObj.struct_nested_containers_field2, null); assert.end(); } }; return cases; } function run(name, cases) { Object.keys(cases).forEach(function(caseName) { test(name + ": " + caseName, cases[caseName]); }); } run("binary", createTestCases(serializeBinary, deserializeBinary)); run("json", createTestCases(serializeJSON, deserializeJSON)); thrift-0.16.0/lib/nodejs/test/episodic-code-generation-test/000077500000000000000000000000001420101504100237065ustar00rootroot00000000000000thrift-0.16.0/lib/nodejs/test/episodic-code-generation-test/client.js000066400000000000000000000045501420101504100255260ustar00rootroot00000000000000#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const assert = require("assert"); const test = require("tape"); const thrift = require("thrift"); const program = require("commander"); program .option("--host ", "Set the thrift server host to connect", "localhost") .option("--port ", "Set the thrift server port number to connect", 9090) .parse(process.argv); const Service = require("./gen-2/second-episode/gen-nodejs/Service"); const Types = require("types-package/first-episode/Types_types"); const host = program.host; const port = program.port; const options = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol }; const connection = thrift.createConnection(host, port, options); const testDriver = function(client, callback) { test("NodeJS episodic compilation client-server test", function(assert) { const type1Object = new Types.Type1(); type1Object.number = 42; type1Object.message = "The answer"; client.testEpisode(type1Object, function(err, response) { assert.error(err, "no callback error"); assert.equal(response.number, type1Object.number + 1); assert.equal( response.message, type1Object.message + " [Hello from the server]" ); assert.end(); callback("Server successfully tested"); }); }); }; connection.on("error", function(err) { assert(false, err); }); const client = thrift.createClient(Service, connection); runTests(); function runTests() { testDriver(client, function(status) { console.log(status); connection.destroy(); }); } exports.expressoTest = function() {}; thrift-0.16.0/lib/nodejs/test/episodic-code-generation-test/episodic_compilation.package.json000066400000000000000000000000401420101504100323620ustar00rootroot00000000000000{ "name": "types-package" } thrift-0.16.0/lib/nodejs/test/episodic-code-generation-test/server.js000066400000000000000000000031621420101504100255540ustar00rootroot00000000000000#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const thrift = require("../../lib/thrift"); const program = require("commander"); program .option("--port ", "Set the thrift server port", 9090) .parse(process.argv); const Service = require("./gen-2/second-episode/gen-nodejs/Service"); const Types = require("types-package/first-episode/Types_types"); const port = program.port; const options = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol }; const ServiceHandler = { testEpisode: function(receivedType1Object) { const type1Object = new Types.Type1(); type1Object.number = receivedType1Object.number + 1; type1Object.message = receivedType1Object.message + " [Hello from the server]"; return type1Object; } }; const server = thrift.createServer(Service, ServiceHandler, options); server.listen(port); thrift-0.16.0/lib/nodejs/test/exceptions.js000066400000000000000000000115521420101504100206140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ "use strict"; const test = require("tape"); const thrift = require("../lib/thrift/thrift.js"); const InputBufferUnderrunError = require("../lib/thrift/input_buffer_underrun_error"); test("TApplicationException", function t(assert) { const e = new thrift.TApplicationException(1, "foo"); assert.ok( e instanceof thrift.TApplicationException, "is instanceof TApplicationException" ); assert.ok(e instanceof thrift.TException, "is instanceof TException"); assert.ok(e instanceof Error, "is instanceof Error"); assert.equal(typeof e.stack, "string", "has stack trace"); assert.ok( /^TApplicationException: foo/.test(e.stack), "Stack trace has correct error name and message" ); assert.ok( e.stack.indexOf("test/exceptions.js:7:11") !== -1, "stack trace starts on correct line and column" ); assert.equal( e.name, "TApplicationException", "has function name TApplicationException" ); assert.equal(e.message, "foo", 'has error message "foo"'); assert.equal(e.type, 1, "has type 1"); assert.end(); }); test("unexpected TApplicationException ", function t(assert) { const e = new thrift.TApplicationException(1, 100); assert.ok( e instanceof thrift.TApplicationException, "is instanceof TApplicationException" ); assert.ok(e instanceof thrift.TException, "is instanceof TException"); assert.ok(e instanceof Error, "is instanceof Error"); assert.equal(typeof e.stack, "string", "has stack trace"); assert.ok( /^TApplicationException: 100/.test(e.stack), "Stack trace has correct error name and message" ); assert.ok( e.stack.indexOf("test/exceptions.js:7:11") !== -1, "stack trace starts on correct line and column" ); assert.equal( e.name, "TApplicationException", "has function name TApplicationException" ); assert.equal(e.message, 100, "has error message 100"); assert.equal(e.type, 1, "has type 1"); assert.end(); }); test("TException", function t(assert) { const e = new thrift.TException("foo"); assert.ok(e instanceof thrift.TException, "is instanceof TException"); assert.ok(e instanceof Error, "is instanceof Error"); assert.equal(typeof e.stack, "string", "has stack trace"); assert.ok( /^TException: foo/.test(e.stack), "Stack trace has correct error name and message" ); assert.ok( e.stack.indexOf("test/exceptions.js:21:11") !== -1, "stack trace starts on correct line and column" ); assert.equal(e.name, "TException", "has function name TException"); assert.equal(e.message, "foo", 'has error message "foo"'); assert.end(); }); test("TProtocolException", function t(assert) { const e = new thrift.TProtocolException(1, "foo"); assert.ok( e instanceof thrift.TProtocolException, "is instanceof TProtocolException" ); assert.ok(e instanceof Error, "is instanceof Error"); assert.equal(typeof e.stack, "string", "has stack trace"); assert.ok( /^TProtocolException: foo/.test(e.stack), "Stack trace has correct error name and message" ); assert.ok( e.stack.indexOf("test/exceptions.js:33:11") !== -1, "stack trace starts on correct line and column" ); assert.equal( e.name, "TProtocolException", "has function name TProtocolException" ); assert.equal(e.message, "foo", 'has error message "foo"'); assert.equal(e.type, 1, "has type 1"); assert.end(); }); test("InputBufferUnderrunError", function t(assert) { const e = new InputBufferUnderrunError("foo"); assert.ok( e instanceof InputBufferUnderrunError, "is instanceof InputBufferUnderrunError" ); assert.ok(e instanceof Error, "is instanceof Error"); assert.equal(typeof e.stack, "string", "has stack trace"); assert.ok( /^InputBufferUnderrunError: foo/.test(e.stack), "Stack trace has correct error name and message" ); assert.ok( e.stack.indexOf("test/exceptions.js:46:11") !== -1, "stack trace starts on correct line and column" ); assert.equal( e.name, "InputBufferUnderrunError", "has function name InputBufferUnderrunError" ); assert.equal(e.message, "foo", 'has error message "foo"'); assert.end(); }); thrift-0.16.0/lib/nodejs/test/header.test.js000066400000000000000000000056011420101504100206370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const TFramedTransport = require("../lib/thrift/framed_transport"); const THeaderTransport = require("../lib/thrift/header_transport"); const THeaderProtocol = require("../lib/thrift/header_protocol"); const thrift = require("../lib/thrift"); const fs = require("fs"); const test = require("tape"); const path = require("path"); const headerPayload = fs.readFileSync( path.join(__dirname, "test_header_payload") ); const cases = { "Should read headers from payload": function(assert) { const transport = new TFramedTransport(); transport.inBuf = Buffer.from(headerPayload); const headers = transport.readHeaders(); assert.equals(headers.Parent, "shoobar"); assert.equals(headers.Trace, "abcde"); assert.end(); }, "Should read headers when reading message begin": function(assert) { const transport = new TFramedTransport(); transport.inBuf = Buffer.from(headerPayload); const protocol = new THeaderProtocol(transport); const result = protocol.readMessageBegin(); const headers = transport.getReadHeaders(); assert.equals(headers.Parent, "shoobar"); assert.equals(headers.Trace, "abcde"); assert.equals(result.fname, "add"); assert.equals(result.mtype, thrift.Thrift.MessageType.CALL); assert.end(); }, "Should be able to write headers": function(assert) { const writeTransport = new TFramedTransport(); writeTransport.setProtocolId(THeaderTransport.SubprotocolId.BINARY); writeTransport.setWriteHeader("Hihihihi", "hohohoho"); writeTransport.setWriteHeader("boobooboo", "fooshoopoo"); writeTransport.setWriteHeader("a", "z"); writeTransport.writeHeaders(); const writeBuffer = writeTransport.outBuffers[0]; const readTransport = new TFramedTransport(); readTransport.inBuf = writeBuffer; readTransport.readHeaders(); const headers = readTransport.getReadHeaders(); assert.equals(headers.Hihihihi, "hohohoho"); assert.equals(headers.boobooboo, "fooshoopoo"); assert.equals(headers.a, "z"); assert.end(); } }; Object.keys(cases).forEach(function(caseName) { test(caseName, cases[caseName]); }); thrift-0.16.0/lib/nodejs/test/helpers.js000066400000000000000000000024271420101504100200760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ "use strict"; const thrift = require("../lib/thrift"); module.exports.transports = { buffered: thrift.TBufferedTransport, framed: thrift.TFramedTransport }; module.exports.protocols = { json: thrift.TJSONProtocol, binary: thrift.TBinaryProtocol, compact: thrift.TCompactProtocol, header: thrift.THeaderProtocol }; module.exports.ecmaMode = process.argv.includes("--es6") ? "es6" : "es5"; module.exports.genPath = process.argv.includes("--es6") ? "gen-nodejs-es6" : "gen-nodejs"; thrift-0.16.0/lib/nodejs/test/int64.test.js000066400000000000000000000065311420101504100203560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const Int64 = require("node-int64"); const JSONInt64 = require("json-int64"); const i64types = require("./gen-nodejs-es6/Int64Test_types.js"); const test = require("tape"); const cases = { "should correctly generate Int64 constants": function(assert) { const EXPECTED_SMALL_INT64_AS_NUMBER = 42; const EXPECTED_SMALL_INT64 = new Int64(42); const EXPECTED_MAX_JS_SAFE_INT64 = new Int64(Number.MAX_SAFE_INTEGER); const EXPECTED_MIN_JS_SAFE_INT64 = new Int64(Number.MIN_SAFE_INTEGER); const EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64 = new Int64("0020000000000000"); // hex-encoded const EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64 = new Int64("ffe0000000000000"); // hex-encoded 2's complement const EXPECTED_MAX_SIGNED_INT64 = new Int64("7fffffffffffffff"); // hex-encoded const EXPECTED_MIN_SIGNED_INT64 = new Int64("8000000000000000"); // hex-encoded 2's complement const EXPECTED_INT64_LIST = [ EXPECTED_SMALL_INT64, EXPECTED_MAX_JS_SAFE_INT64, EXPECTED_MIN_JS_SAFE_INT64, EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64, EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64, EXPECTED_MAX_SIGNED_INT64, EXPECTED_MIN_SIGNED_INT64 ]; assert.ok(EXPECTED_SMALL_INT64.equals(i64types.SMALL_INT64)); assert.ok(EXPECTED_MAX_JS_SAFE_INT64.equals(i64types.MAX_JS_SAFE_INT64)); assert.ok(EXPECTED_MIN_JS_SAFE_INT64.equals(i64types.MIN_JS_SAFE_INT64)); assert.ok( EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64.equals( i64types.MAX_JS_SAFE_PLUS_ONE_INT64 ) ); assert.ok( EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64.equals( i64types.MIN_JS_SAFE_MINUS_ONE_INT64 ) ); assert.ok(EXPECTED_MAX_SIGNED_INT64.equals(i64types.MAX_SIGNED_INT64)); assert.ok(EXPECTED_MIN_SIGNED_INT64.equals(i64types.MIN_SIGNED_INT64)); assert.equal( EXPECTED_SMALL_INT64_AS_NUMBER, i64types.SMALL_INT64.toNumber() ); assert.equal( Number.MAX_SAFE_INTEGER, i64types.MAX_JS_SAFE_INT64.toNumber() ); assert.equal( Number.MIN_SAFE_INTEGER, i64types.MIN_JS_SAFE_INT64.toNumber() ); for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i) { assert.ok(EXPECTED_INT64_LIST[i].equals(i64types.INT64_LIST[i])); } for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i) { const int64Object = EXPECTED_INT64_LIST[i]; assert.ok( i64types.INT64_2_INT64_MAP[ JSONInt64.toDecimalString(int64Object) ].equals(int64Object) ); } assert.end(); } }; Object.keys(cases).forEach(function(caseName) { test(caseName, cases[caseName]); }); thrift-0.16.0/lib/nodejs/test/server.crt000066400000000000000000000027611420101504100201170ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3 DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6 L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg 2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5 U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD 1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0 -----END CERTIFICATE----- thrift-0.16.0/lib/nodejs/test/server.js000066400000000000000000000073151420101504100177430ustar00rootroot00000000000000#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const fs = require("fs"); const path = require("path"); const thrift = require("../lib/thrift"); const program = require("commander"); const helpers = require("./helpers"); program .option( "-p, --protocol ", "Set thrift protocol (binary|compact|json)", "binary" ) .option( "-t, --transport ", "Set thrift transport (buffered|framed|http)", "buffered" ) .option("--ssl", "use ssl transport") .option("--port ", "Set thrift server port", 9090) .option("--domain-socket ", "Set thift server unix domain socket") .option( "-t, --type ", "Select server type (http|multiplex|tcp|websocket)", "tcp" ) .option("--callback", "test with callback style functions") .option("--es6", "Use es6 code") .option("--es5", "Use es5 code") .parse(process.argv); const ThriftTest = require(`./${helpers.genPath}/ThriftTest`); const SecondService = require(`./${helpers.genPath}/SecondService`); const { ThriftTestHandler } = require("./test_handler"); const port = program.port; const domainSocket = program.domainSocket; const ssl = program.ssl; let type = program.type; if (program.transport === "http") { program.transport = "buffered"; type = "http"; } else if (program.transport === "websocket") { program.transport = "buffered"; type = "websocket"; } let options = { transport: helpers.transports[program.transport], protocol: helpers.protocols[program.protocol] }; if (type === "http" || type === "websocket") { options.handler = ThriftTestHandler; options.processor = ThriftTest; options = { services: { "/test": options }, cors: { "*": true } }; } let processor; if (type === "multiplex") { const SecondServiceHandler = { secondtestString: function(thing, result) { console.log('testString("' + thing + '")'); result(null, 'testString("' + thing + '")'); } }; processor = new thrift.MultiplexedProcessor(); processor.registerProcessor( "ThriftTest", new ThriftTest.Processor(ThriftTestHandler) ); processor.registerProcessor( "SecondService", new SecondService.Processor(SecondServiceHandler) ); } if (ssl) { if ( type === "tcp" || type === "multiplex" || type === "http" || type === "websocket" ) { options.tls = { key: fs.readFileSync(path.resolve(__dirname, "server.key")), cert: fs.readFileSync(path.resolve(__dirname, "server.crt")) }; } } let server; if (type === "tcp") { server = thrift.createServer(ThriftTest, ThriftTestHandler, options); } else if (type === "multiplex") { server = thrift.createMultiplexServer(processor, options); } else if (type === "http" || type === "websocket") { server = thrift.createWebServer(options); } if (domainSocket) { server.listen(domainSocket); } else if ( type === "tcp" || type === "multiplex" || type === "http" || type === "websocket" ) { server.listen(port); } thrift-0.16.0/lib/nodejs/test/server.key000066400000000000000000000032501420101504100201110ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq 57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9 7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU 8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/ LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3 SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791 Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1 Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc rdPUV9/uQkdx8VrShxlD8A== -----END PRIVATE KEY----- thrift-0.16.0/lib/nodejs/test/test-cases.js000066400000000000000000000135511420101504100205070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ "use strict"; const helpers = require("./helpers"); const ttypes = require(`./${helpers.genPath}/ThriftTest_types`); const Int64 = require("node-int64"); //all Languages in UTF-8 /*jshint -W100 */ const stringTest = (module.exports.stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " + "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " + "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " + "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " + "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " + "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " + "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " + "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " + "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " + "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " + "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " + "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " + "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " + "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " + "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " + "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" + "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " + "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " + "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " + "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " + "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " + "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " + "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " + "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " + "Bân-lâm-gú, 粵語"); /*jshint +W100 */ const specialCharacters = (module.exports.specialCharacters = 'quote: " backslash:' + " forwardslash-escaped: / " + " backspace: \b formfeed: \f newline: \n return: \r tab: " + ' now-all-of-them-together: "\\/\b\n\r\t' + " now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><" + ' char-to-test-json-parsing: ]] "]] \\" }}}{ [[[ '); const mapTestInput = (module.exports.mapTestInput = { a: "123", "a b": "with spaces ", same: "same", "0": "numeric key", longValue: stringTest, stringTest: "long key" }); const simple = [ ["testVoid", undefined], ["testString", "Test"], ["testString", ""], ["testString", stringTest], ["testString", specialCharacters], ["testBool", true], ["testBool", false], ["testByte", 1], ["testByte", 0], ["testByte", -1], ["testByte", -127], ["testI32", -1], ["testDouble", -5.2098523], ["testDouble", 7.012052175215044], ["testEnum", ttypes.Numberz.ONE], ["testI64", 5], ["testI64", -5], ["testI64", 734359738368], ["testI64", -734359738368], ["testI64", new Int64(new Buffer([0, 0x20, 0, 0, 0, 0, 0, 1]))], // 2^53+1 [ "testI64", new Int64(new Buffer([0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])) ], // -2^53-1 ["testTypedef", 69] ]; const mapout = {}; for (let i = 0; i < 5; ++i) { mapout[i] = i - 10; } const deep = [ [ "testList", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] ] ]; const deepUnordered = [ ["testMap", mapout], ["testSet", [1, 2, 3]], ["testStringMap", mapTestInput] ]; const out = new ttypes.Xtruct({ string_thing: "Zero", byte_thing: 1, i32_thing: -3, i64_thing: 1000000 }); const out2 = new ttypes.Xtruct2(); out2.byte_thing = 1; out2.struct_thing = out; out2.i32_thing = 5; const crazy = new ttypes.Insanity({ userMap: { "5": 5, "8": 8 }, xtructs: [ new ttypes.Xtruct({ string_thing: "Goodbye4", byte_thing: 4, i32_thing: 4, i64_thing: 4 }), new ttypes.Xtruct({ string_thing: "Hello2", byte_thing: 2, i32_thing: 2, i64_thing: 2 }) ] }); const crazy2 = new ttypes.Insanity({ userMap: { "5": 5, "8": 8 }, xtructs: [ { string_thing: "Goodbye4", byte_thing: 4, i32_thing: 4, i64_thing: 4 }, { string_thing: "Hello2", byte_thing: 2, i32_thing: 2, i64_thing: 2 } ] }); const insanity = { "1": { "2": crazy, "3": crazy }, "2": { "6": { userMap: {}, xtructs: [] } } }; module.exports.simple = simple; module.exports.deep = deep; module.exports.deepUnordered = deepUnordered; module.exports.out = out; module.exports.out2 = out2; module.exports.crazy = crazy; module.exports.crazy2 = crazy2; module.exports.insanity = insanity; thrift-0.16.0/lib/nodejs/test/testAll.sh000077500000000000000000000116011420101504100200370ustar00rootroot00000000000000#! /bin/sh # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. if [ -n "${1}" ]; then COVER=${1}; fi DIR="$( cd "$( dirname "$0" )" && pwd )" EPISODIC_DIR=${DIR}/episodic-code-generation-test THRIFT_FILES_DIR=${DIR}/../../../test THRIFT_COMPILER=${DIR}/../../../compiler/cpp/thrift ISTANBUL="$DIR/../../../node_modules/istanbul/lib/cli.js" REPORT_PREFIX="${DIR}/../coverage/report" COUNT=0 export NODE_PATH="${DIR}:${DIR}/../lib:${NODE_PATH}" testServer() { echo " [ECMA $1] Testing $2 Client/Server with protocol $3 and transport $4 $5"; RET=0 if [ -n "${COVER}" ]; then ${ISTANBUL} cover ${DIR}/server.js --dir ${REPORT_PREFIX}${COUNT} --handle-sigint -- --type $2 -p $3 -t $4 $5 & COUNT=$((COUNT+1)) else node ${DIR}/server.js --${1} --type $2 -p $3 -t $4 $5 & fi SERVERPID=$! sleep 0.1 if [ -n "${COVER}" ]; then ${ISTANBUL} cover ${DIR}/client.js --dir ${REPORT_PREFIX}${COUNT} -- --${1} --type $2 -p $3 -t $4 $5 || RET=1 COUNT=$((COUNT+1)) else node ${DIR}/client.js --${1} --type $2 -p $3 -t $4 $5 || RET=1 fi kill -2 $SERVERPID || RET=1 wait $SERVERPID return $RET } testEpisodicCompilation() { RET=0 if [ -n "${COVER}" ]; then ${ISTANBUL} cover ${EPISODIC_DIR}/server.js --dir ${REPORT_PREFIX}${COUNT} --handle-sigint & COUNT=$((COUNT+1)) else node ${EPISODIC_DIR}/server.js & fi SERVERPID=$! sleep 0.1 if [ -n "${COVER}" ]; then ${ISTANBUL} cover ${EPISODIC_DIR}/client.js --dir ${REPORT_PREFIX}${COUNT} || RET=1 COUNT=$((COUNT+1)) else node ${EPISODIC_DIR}/client.js || RET=1 fi kill -2 $SERVERPID || RET=1 wait $SERVERPID return $RET } TESTOK=0 # generating Thrift code ${THRIFT_COMPILER} -o ${DIR} --gen js:node ${THRIFT_FILES_DIR}/ThriftTest.thrift ${THRIFT_COMPILER} -o ${DIR} --gen js:node ${THRIFT_FILES_DIR}/JsDeepConstructorTest.thrift ${THRIFT_COMPILER} -o ${DIR} --gen js:node ${THRIFT_FILES_DIR}/Int64Test.thrift mkdir ${DIR}/gen-nodejs-es6 ${THRIFT_COMPILER} -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${THRIFT_FILES_DIR}/ThriftTest.thrift ${THRIFT_COMPILER} -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${THRIFT_FILES_DIR}/JsDeepConstructorTest.thrift ${THRIFT_COMPILER} -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${THRIFT_FILES_DIR}/Int64Test.thrift # generate episodic compilation test code TYPES_PACKAGE=${EPISODIC_DIR}/node_modules/types-package # generate the first episode mkdir --parents ${EPISODIC_DIR}/gen-1/first-episode ${THRIFT_COMPILER} -o ${EPISODIC_DIR}/gen-1/first-episode --gen js:node,thrift_package_output_directory=first-episode ${THRIFT_FILES_DIR}/Types.thrift # create a "package" from the first episode and "install" it, the episode file must be at the module root mkdir --parents ${TYPES_PACKAGE}/first-episode cp --force ${EPISODIC_DIR}/episodic_compilation.package.json ${TYPES_PACKAGE}/package.json cp --force ${EPISODIC_DIR}/gen-1/first-episode/gen-nodejs/Types_types.js ${TYPES_PACKAGE}/first-episode/ cp --force ${EPISODIC_DIR}/gen-1/first-episode/gen-nodejs/thrift.js.episode ${TYPES_PACKAGE} # generate the second episode mkdir --parents ${EPISODIC_DIR}/gen-2/second-episode ${THRIFT_COMPILER} -o ${EPISODIC_DIR}/gen-2/second-episode --gen js:node,imports=${TYPES_PACKAGE} ${THRIFT_FILES_DIR}/Service.thrift if [ -f ${EPISODIC_DIR}/gen-2/second-episode/Types_types.js ]; then TESTOK=1 fi # unit tests node ${DIR}/binary.test.js || TESTOK=1 node ${DIR}/int64.test.js || TESTOK=1 node ${DIR}/deep-constructor.test.js || TESTOK=1 # integration tests for type in tcp multiplex websocket http do for protocol in compact binary json do for transport in buffered framed do for ecma_version in es5 es6 do testServer $ecma_version $type $protocol $transport || TESTOK=1 testServer $ecma_version $type $protocol $transport --ssl || TESTOK=1 testServer $ecma_version $type $protocol $transport --callback || TESTOK=1 done done done done # episodic compilation test testEpisodicCompilation if [ -n "${COVER}" ]; then ${ISTANBUL} report --dir "${DIR}/../coverage" --include "${DIR}/../coverage/report*/coverage.json" lcov cobertura html rm -r ${DIR}/../coverage/report*/* rmdir ${DIR}/../coverage/report* fi exit $TESTOK thrift-0.16.0/lib/nodejs/test/test_driver.js000066400000000000000000000265411420101504100207710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // This is the Node.js test driver for the standard Apache Thrift // test service. The driver invokes every function defined in the // Thrift Test service with a representative range of parameters. // // The ThriftTestDriver function requires a client object // connected to a server hosting the Thrift Test service and // supports an optional callback function which is called with // a status message when the test is complete. const test = require("tape"); const helpers = require("./helpers"); const ttypes = require(`./${helpers.genPath}/ThriftTest_types`); const TException = require("thrift").Thrift.TException; const Int64 = require("node-int64"); const testCases = require("./test-cases"); exports.ThriftTestDriver = function(client, callback) { test( "NodeJS Style Callback Client Tests", { skip: helpers.ecmaMode === "es6" }, function(assert) { const checkRecursively = makeRecursiveCheck(assert); function makeAsserter(assertionFn) { return function(c) { const fnName = c[0]; const expected = c[1]; client[fnName](expected, function(err, actual) { assert.error(err, fnName + ": no callback error"); assertionFn(actual, expected, fnName); }); }; } testCases.simple.forEach( makeAsserter(function(a, e, m) { if (a instanceof Int64) { const e64 = e instanceof Int64 ? e : new Int64(e); assert.deepEqual(a.buffer, e64.buffer, m); } else { assert.equal(a, e, m); } }) ); testCases.deep.forEach(makeAsserter(assert.deepEqual)); testCases.deepUnordered.forEach( makeAsserter(makeUnorderedDeepEqual(assert)) ); const arr = []; for (let i = 0; i < 256; ++i) { arr[i] = 255 - i; } let buf = new Buffer(arr); client.testBinary(buf, function(err, response) { assert.error(err, "testBinary: no callback error"); assert.equal(response.length, 256, "testBinary"); assert.deepEqual(response, buf, "testBinary(Buffer)"); }); buf = new Buffer(arr); client.testBinary(buf.toString("binary"), function(err, response) { assert.error(err, "testBinary: no callback error"); assert.equal(response.length, 256, "testBinary"); assert.deepEqual(response, buf, "testBinary(string)"); }); client.testMapMap(42, function(err, response) { const expected = { "4": { "1": 1, "2": 2, "3": 3, "4": 4 }, "-4": { "-4": -4, "-3": -3, "-2": -2, "-1": -1 } }; assert.error(err, "testMapMap: no callback error"); assert.deepEqual(expected, response, "testMapMap"); }); client.testStruct(testCases.out, function(err, response) { assert.error(err, "testStruct: no callback error"); checkRecursively(testCases.out, response, "testStruct"); }); client.testNest(testCases.out2, function(err, response) { assert.error(err, "testNest: no callback error"); checkRecursively(testCases.out2, response, "testNest"); }); client.testInsanity(testCases.crazy, function(err, response) { assert.error(err, "testInsanity: no callback error"); checkRecursively(testCases.insanity, response, "testInsanity"); }); client.testInsanity(testCases.crazy2, function(err, response) { assert.error(err, "testInsanity2: no callback error"); checkRecursively(testCases.insanity, response, "testInsanity2"); }); client.testException("TException", function(err, response) { assert.ok( err instanceof TException, "testException: correct error type" ); assert.ok(!response, "testException: no response"); }); client.testException("Xception", function(err, response) { assert.ok( err instanceof ttypes.Xception, "testException: correct error type" ); assert.ok(!response, "testException: no response"); assert.equal(err.errorCode, 1001, "testException: correct error code"); assert.equal( "Xception", err.message, "testException: correct error message" ); }); client.testException("no Exception", function(err, response) { assert.error(err, "testException: no callback error"); assert.ok(!response, "testException: no response"); }); client.testOneway(0, function(err, response) { assert.error(err, "testOneway: no callback error"); assert.strictEqual(response, undefined, "testOneway: void response"); }); checkOffByOne(function(done) { client.testI32(-1, function(err, response) { assert.error(err, "checkOffByOne: no callback error"); assert.equal(-1, response); assert.end(); done(); }); }, callback); } ); // ES6 does not support callback style if (helpers.ecmaMode === "es6") { checkOffByOne(done => done(), callback); } }; exports.ThriftTestDriverPromise = function(client, callback) { test("Promise Client Tests", function(assert) { const checkRecursively = makeRecursiveCheck(assert); function makeAsserter(assertionFn) { return function(c) { const fnName = c[0]; const expected = c[1]; client[fnName](expected) .then(function(actual) { assertionFn(actual, expected, fnName); }) .catch(() => assert.fail("fnName")); }; } testCases.simple.forEach( makeAsserter(function(a, e, m) { if (a instanceof Int64) { const e64 = e instanceof Int64 ? e : new Int64(e); assert.deepEqual(a.buffer, e64.buffer, m); } else { assert.equal(a, e, m); } }) ); testCases.deep.forEach(makeAsserter(assert.deepEqual)); testCases.deepUnordered.forEach( makeAsserter(makeUnorderedDeepEqual(assert)) ); client .testStruct(testCases.out) .then(function(response) { checkRecursively(testCases.out, response, "testStruct"); }) .catch(() => assert.fail("testStruct")); client .testNest(testCases.out2) .then(function(response) { checkRecursively(testCases.out2, response, "testNest"); }) .catch(() => assert.fail("testNest")); client .testInsanity(testCases.crazy) .then(function(response) { checkRecursively(testCases.insanity, response, "testInsanity"); }) .catch(() => assert.fail("testInsanity")); client .testInsanity(testCases.crazy2) .then(function(response) { checkRecursively(testCases.insanity, response, "testInsanity2"); }) .catch(() => assert.fail("testInsanity2")); client .testException("TException") .then(function() { assert.fail("testException: TException"); }) .catch(function(err) { assert.ok(err instanceof TException); }); client .testException("Xception") .then(function() { assert.fail("testException: Xception"); }) .catch(function(err) { assert.ok(err instanceof ttypes.Xception); assert.equal(err.errorCode, 1001); assert.equal("Xception", err.message); }); client .testException("no Exception") .then(function(response) { assert.equal(undefined, response); //void }) .catch(() => assert.fail("testException")); client .testOneway(0) .then(function(response) { assert.strictEqual(response, undefined, "testOneway: void response"); }) .catch(() => assert.fail("testOneway: should not reject")); checkOffByOne(function(done) { client .testI32(-1) .then(function(response) { assert.equal(-1, response); assert.end(); done(); }) .catch(() => assert.fail("checkOffByOne")); }, callback); }); }; // Helper Functions // ========================================================= function makeRecursiveCheck(assert) { return function(map1, map2, msg) { const equal = checkRecursively(map1, map2); assert.ok(equal, msg); // deepEqual doesn't work with fields using node-int64 function checkRecursively(map1, map2) { if (typeof map1 !== "function" && typeof map2 !== "function") { if (!map1 || typeof map1 !== "object") { //Handle int64 types (which use node-int64 in Node.js JavaScript) if ( typeof map1 === "number" && typeof map2 === "object" && map2.buffer && map2.buffer instanceof Buffer && map2.buffer.length === 8 ) { const n = new Int64(map2.buffer); return map1 === n.toNumber(); } else { return map1 == map2; } } else { return Object.keys(map1).every(function(key) { return checkRecursively(map1[key], map2[key]); }); } } } }; } function checkOffByOne(done, callback) { const retry_limit = 30; const retry_interval = 100; let test_complete = false; let retrys = 0; /** * redo a simple test after the oneway to make sure we aren't "off by one" -- * if the server treated oneway void like normal void, this next test will * fail since it will get the void confirmation rather than the correct * result. In this circumstance, the client will throw the exception: * * Because this is the last test against the server, when it completes * the entire suite is complete by definition (the tests run serially). */ done(function() { test_complete = true; }); //We wait up to retry_limit * retry_interval for the test suite to complete function TestForCompletion() { if (test_complete && callback) { callback("Server successfully tested!"); } else { if (++retrys < retry_limit) { setTimeout(TestForCompletion, retry_interval); } else if (callback) { callback( "Server test failed to complete after " + (retry_limit * retry_interval) / 1000 + " seconds" ); } } } setTimeout(TestForCompletion, retry_interval); } function makeUnorderedDeepEqual(assert) { return function(actual, expected, name) { assert.equal(actual.length, expected.length, name); for (const k in actual) { let found = false; for (const k2 in expected) { if (actual[k] === expected[k2]) { found = true; } } if (!found) { assert.fail("Unexpected value " + actual[k] + " with key " + k); } } }; } thrift-0.16.0/lib/nodejs/test/test_handler.js000066400000000000000000000124461420101504100211120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //This is the server side Node test handler for the standard // Apache Thrift test service. const helpers = require("./helpers"); const ttypes = require(`./${helpers.genPath}/ThriftTest_types`); const TException = require("thrift").Thrift.TException; function makeSyncHandler() { return function(thing) { return thing; }; } const syncHandlers = { testVoid: testVoid, testMapMap: testMapMap, testInsanity: testInsanity, testMulti: testMulti, testException: testException, testMultiException: testMultiException, testOneway: testOneway }; function makeAsyncHandler(label) { return function(thing, result) { thing = syncHandlers[label](thing); result(null, thing); }; } const asyncHandlers = { testVoid: testVoidAsync, testMulti: testMultiAsync, testException: testExceptionAsync, testMultiException: testMultiExceptionAsync, testOneway: testOnewayAsync }; const identityHandlers = [ "testString", "testBool", "testByte", "testI32", "testI64", "testDouble", "testBinary", "testStruct", "testNest", "testMap", "testStringMap", "testSet", "testList", "testEnum", "testTypedef" ]; function testVoid() { //console.log('testVoid()'); } function testVoidAsync(result) { result(testVoid()); } function testMapMap() { const mapmap = []; const pos = []; const neg = []; for (let i = 1; i < 5; i++) { pos[i] = i; neg[-i] = -i; } mapmap[4] = pos; mapmap[-4] = neg; return mapmap; } function testInsanity(argument) { //console.log('testInsanity('); //console.log(argument); //console.log(')'); const first_map = []; const second_map = []; first_map[ttypes.Numberz.TWO] = argument; first_map[ttypes.Numberz.THREE] = argument; const looney = new ttypes.Insanity(); second_map[ttypes.Numberz.SIX] = looney; const insane = []; insane[1] = first_map; insane[2] = second_map; //console.log('insane result:'); //console.log(insane); return insane; } function testMulti(arg0, arg1, arg2) { //console.log('testMulti()'); const hello = new ttypes.Xtruct(); hello.string_thing = "Hello2"; hello.byte_thing = arg0; hello.i32_thing = arg1; hello.i64_thing = arg2; return hello; } function testMultiAsync(arg0, arg1, arg2, arg3, arg4, arg5, result) { const hello = testMulti(arg0, arg1, arg2, arg3, arg4, arg5); result(null, hello); } function testException(arg) { //console.log('testException('+arg+')'); if (arg === "Xception") { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = arg; throw x; } else if (arg === "TException") { throw new TException(arg); } else { return; } } function testExceptionAsync(arg, result) { //console.log('testException('+arg+')'); if (arg === "Xception") { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = arg; result(x); } else if (arg === "TException") { result(new TException(arg)); } else { result(null); } } function testMultiException(arg0, arg1) { //console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); if (arg0 === "Xception") { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = "This is an Xception"; throw x; } else if (arg0 === "Xception2") { const x2 = new ttypes.Xception2(); x2.errorCode = 2002; x2.struct_thing = new ttypes.Xtruct(); x2.struct_thing.string_thing = "This is an Xception2"; throw x2; } const res = new ttypes.Xtruct(); res.string_thing = arg1; return res; } function testMultiExceptionAsync(arg0, arg1, result) { //console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); if (arg0 === "Xception") { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = "This is an Xception"; result(x); } else if (arg0 === "Xception2") { const x2 = new ttypes.Xception2(); x2.errorCode = 2002; x2.struct_thing = new ttypes.Xtruct(); x2.struct_thing.string_thing = "This is an Xception2"; result(x2); } else { const res = new ttypes.Xtruct(); res.string_thing = arg1; result(null, res); } } //console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!'); function testOneway() {} function testOnewayAsync(sleepFor) { testOneway(sleepFor); } identityHandlers.forEach(function(label) { syncHandlers[label] = makeSyncHandler(label); asyncHandlers[label] = makeAsyncHandler(label); }); ["testMapMap", "testInsanity"].forEach(function(label) { asyncHandlers[label] = makeAsyncHandler(label); }); exports.ThriftTestHandler = asyncHandlers; thrift-0.16.0/lib/nodejs/test/test_header_payload000066400000000000000000000001141420101504100220100ustar00rootroot00000000000000HParentshoobarTraceabcdeaddthrift-0.16.0/lib/nodets/000077500000000000000000000000001420101504100151245ustar00rootroot00000000000000thrift-0.16.0/lib/nodets/Makefile.am000077500000000000000000000033041420101504100171630ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # We call npm twice to work around npm issues stubs: $(top_srcdir)/test/ThriftTest.thrift mkdir -p test-compiled $(THRIFT) --gen js:node,ts -o test/ $(top_srcdir)/test/ThriftTest.thrift && $(THRIFT) --gen js:node,ts -o test-compiled $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) --gen js:node,ts -o test/ $(top_srcdir)/test/Int64Test.thrift && $(THRIFT) --gen js:node,ts -o test-compiled $(top_srcdir)/test/Int64Test.thrift ts-compile: stubs mkdir -p test-compiled ../../node_modules/typescript/bin/tsc --outDir test-compiled/ --project test/tsconfig.json deps: $(top_srcdir)/package.json $(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/ all-local: deps ts-compile precross: deps stubs ts-compile check: deps ts-compile cd $(top_srcdir) && $(NPM) run test-ts && cd lib/nodets clean-local: $(RM) -r test/gen-nodejs $(RM) -r $(top_srcdir)/node_modules $(RM) -r test-compiled EXTRA_DIST = \ test \ coding_standards.md thrift-0.16.0/lib/nodets/coding_standards.md000066400000000000000000000001031420101504100207460ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/nodets/test/000077500000000000000000000000001420101504100161035ustar00rootroot00000000000000thrift-0.16.0/lib/nodets/test/client.ts000066400000000000000000000040301420101504100177260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import assert = require("assert"); import thrift = require("thrift"); import Thrift = thrift.Thrift; import ThriftTest = require("./gen-nodejs/ThriftTest"); import test_driver = require("./test_driver"); import ThriftTestDriver = test_driver.ThriftTestDriver; import ThriftTestDriverPromise = test_driver.ThriftTestDriverPromise; // var program = require("commander"); import * as program from "commander"; program .option("--port ", "Set thrift server port number to connect", 9090) .option("--promise", "test with promise style functions") .option("--protocol", "Set thrift protocol (binary) [protocol]") .parse(process.argv); var port: number = program.port; var promise = program.promise; var options = { transport: Thrift.TBufferedTransport, protocol: Thrift.TBinaryProtocol }; var testDriver = promise ? ThriftTestDriverPromise : ThriftTestDriver; var connection = thrift.createConnection("localhost", port, options); connection.on("error", function(err: string) { assert(false, err); }); var client = thrift.createClient(ThriftTest.Client, connection); runTests(); function runTests() { testDriver(client, function (status: string) { console.log(status); process.exit(0); }); } exports.expressoTest = function() {}; thrift-0.16.0/lib/nodets/test/int64.test.ts000066400000000000000000000065611420101504100204050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Int64 = require("node-int64"); import JSONInt64 = require('json-int64'); import i64types = require("./gen-nodejs/Int64Test_types"); import test = require("tape"); const cases = { "should correctly generate Int64 constants": function(assert) { const EXPECTED_SMALL_INT64_AS_NUMBER: number = 42; const EXPECTED_SMALL_INT64: Int64 = new Int64(42); const EXPECTED_MAX_JS_SAFE_INT64: Int64 = new Int64(Number.MAX_SAFE_INTEGER); const EXPECTED_MIN_JS_SAFE_INT64: Int64 = new Int64(Number.MIN_SAFE_INTEGER); const EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64: Int64 = new Int64("0020000000000000"); // hex-encoded const EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64: Int64 = new Int64("ffe0000000000000"); // hex-encoded 2's complement const EXPECTED_MAX_SIGNED_INT64: Int64 = new Int64("7fffffffffffffff"); // hex-encoded const EXPECTED_MIN_SIGNED_INT64: Int64 = new Int64("8000000000000000"); // hex-encoded 2's complement const EXPECTED_INT64_LIST: Int64[] = [ EXPECTED_SMALL_INT64, EXPECTED_MAX_JS_SAFE_INT64, EXPECTED_MIN_JS_SAFE_INT64, EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64, EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64, EXPECTED_MAX_SIGNED_INT64, EXPECTED_MIN_SIGNED_INT64 ]; assert.ok(EXPECTED_SMALL_INT64.equals(i64types.SMALL_INT64)); assert.ok(EXPECTED_MAX_JS_SAFE_INT64.equals(i64types.MAX_JS_SAFE_INT64)); assert.ok(EXPECTED_MIN_JS_SAFE_INT64.equals(i64types.MIN_JS_SAFE_INT64)); assert.ok( EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64.equals( i64types.MAX_JS_SAFE_PLUS_ONE_INT64 ) ); assert.ok( EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64.equals( i64types.MIN_JS_SAFE_MINUS_ONE_INT64 ) ); assert.ok(EXPECTED_MAX_SIGNED_INT64.equals(i64types.MAX_SIGNED_INT64)); assert.ok(EXPECTED_MIN_SIGNED_INT64.equals(i64types.MIN_SIGNED_INT64)); assert.equal( EXPECTED_SMALL_INT64_AS_NUMBER, i64types.SMALL_INT64.toNumber() ); assert.equal( Number.MAX_SAFE_INTEGER, i64types.MAX_JS_SAFE_INT64.toNumber() ); assert.equal( Number.MIN_SAFE_INTEGER, i64types.MIN_JS_SAFE_INT64.toNumber() ); for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i) { assert.ok(EXPECTED_INT64_LIST[i].equals(i64types.INT64_LIST[i])); } for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i){ let int64Object = EXPECTED_INT64_LIST[i]; assert.ok(i64types.INT64_2_INT64_MAP[JSONInt64.toDecimalString(int64Object)].equals(int64Object)); } assert.end(); } }; Object.keys(cases).forEach(function(caseName) { test(caseName, cases[caseName]); }); thrift-0.16.0/lib/nodets/test/runClient.sh000077500000000000000000000007671420101504100204170ustar00rootroot00000000000000#! /bin/sh DIR="$( cd "$( dirname "$0" )" && pwd )" mkdir -p $DIR/../test-compiled COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)" export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}" compile() { #generating thrift code ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift } compile node ${COMPILEDDIR}/client.js $* thrift-0.16.0/lib/nodets/test/runServer.sh000077500000000000000000000007711420101504100204420ustar00rootroot00000000000000#! /bin/sh DIR="$( cd "$( dirname "$0" )" && pwd )" mkdir -p $DIR/../test-compiled COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)" export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}" compile() { #generating thrift code ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift } compile node ${COMPILEDDIR}/server.js $* thrift-0.16.0/lib/nodets/test/server.ts000066400000000000000000000015131420101504100177610ustar00rootroot00000000000000import thrift = require("thrift"); var program = require('commander'); import ThriftTest = require('./gen-nodejs/ThriftTest'); import test_handler = require('./test_handler'); program .option('--port ', 'Set thrift server port', 9090) .option('--promise', 'test with promise style functions') .option('--protocol', '"Set thrift protocol (binary) [protocol]"') .parse(process.argv); var port: number = program.port; var options: thrift.ServerOptions = { transport: thrift.TBufferedTransport, protocol: thrift.TBinaryProtocol }; var server: thrift.Server; if (program.promise) { server = thrift.createServer(ThriftTest.Processor, new test_handler.AsyncThriftTestHandler(), options); } else { server = thrift.createServer(ThriftTest.Processor, new test_handler.SyncThriftTestHandler(), options); } server.listen(port); thrift-0.16.0/lib/nodets/test/test-cases.ts000066400000000000000000000105121420101504100205250ustar00rootroot00000000000000'use strict'; import ttypes = require('./gen-nodejs/ThriftTest_types'); import Int64 = require('node-int64'); //all Languages in UTF-8 /*jshint -W100 */ export var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " + "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " + "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " + "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " + "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " + "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " + "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " + "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " + "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " + "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " + "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " + "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " + "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " + "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " + "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " + "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" + "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " + "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " + "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " + "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " + "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " + "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " + "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " + "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " + "Bân-lâm-gú, 粵語"; /*jshint +W100 */ export var specialCharacters = 'quote: \" backslash:' + ' forwardslash-escaped: \/ ' + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + ' now-all-of-them-together: "\\\/\b\n\r\t' + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' + ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ '; export var mapTestInput = { "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key", "longValue":stringTest, stringTest:"long key" }; export var simple = [ ['testVoid', undefined], ['testString', 'Test'], ['testString', ''], ['testString', stringTest], ['testString', specialCharacters], ['testByte', 1], ['testByte', 0], ['testByte', -1], ['testByte', -127], ['testI32', -1], ['testDouble', -5.2098523], ['testDouble', 7.012052175215044], ['testEnum', ttypes.Numberz.ONE] ]; export var simpleLoose = [ ['testI64', 5], ['testI64', -5], ['testI64', 734359738368], ['testI64', -34359738368], ['testI64', -734359738368], ['testTypedef', 69] ] var mapout: {[key: number]: number; } = {}; for (var i = 0; i < 5; ++i) { mapout[i] = i-10; } export var deep = [ ['testMap', mapout], ['testSet', [1,2,3]], ['testList', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]], ['testStringMap', mapTestInput] ]; export var out = new ttypes.Xtruct({ string_thing: 'Zero', byte_thing: 1, i32_thing: -3, i64_thing: new Int64(1000000) }); export var out2 = new ttypes.Xtruct2(); out2.byte_thing = 1; out2.struct_thing = out; out2.i32_thing = 5; export var crazy = new ttypes.Insanity({ "userMap":{ "5":new Int64(5), "8":new Int64(8) }, "xtructs":[new ttypes.Xtruct({ "string_thing":"Goodbye4", "byte_thing":4, "i32_thing":4, "i64_thing":new Int64(4) }), new ttypes.Xtruct({ "string_thing":"Hello2", "byte_thing":2, "i32_thing":2, "i64_thing":new Int64(2) })] }); export var insanity: any = { "1":{ "2": crazy, "3": crazy }, "2":{ "6":{ "userMap":{}, "xtructs":[] } } }; thrift-0.16.0/lib/nodets/test/testAll.sh000077500000000000000000000021211420101504100200460ustar00rootroot00000000000000#! /bin/sh DIR="$( cd "$( dirname "$0" )" && pwd )" mkdir -p $DIR/../test-compiled COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)" export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}" compile() { #generating thrift code ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/Int64Test.thrift ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/Int64Test.thrift tsc --outDir $COMPILEDDIR --project $DIR/tsconfig.json } compile testServer() { echo "start server $1" RET=0 node ${COMPILEDDIR}/server.js $1 & SERVERPID=$! sleep 1 echo "start client $1" node ${COMPILEDDIR}/client.js $1 || RET=1 kill -2 $SERVERPID || RET=1 return $RET } node ${COMPILEDDIR}/int64.test.js || TESTOK=1 #integration tests testServer || TESTOK=1 testServer --promise || TESTOK=1 exit $TESTOK thrift-0.16.0/lib/nodets/test/test_driver.ts000066400000000000000000000224631420101504100210140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // This is the Node.js test driver for the standard Apache Thrift // test service. The driver invokes every function defined in the // Thrift Test service with a representative range of parameters. // // The ThriftTestDriver function requires a client object // connected to a server hosting the Thrift Test service and // supports an optional callback function which is called with // a status message when the test is complete. import test = require("tape"); import ttypes = require("./gen-nodejs/ThriftTest_types"); import ThriftTest = require("./gen-nodejs/ThriftTest"); import thrift = require("thrift"); import Q = thrift.Q; import TException = thrift.Thrift.TException; var Int64 = require("node-int64"); import testCases = require("./test-cases"); export function ThriftTestDriver(client: ThriftTest.Client, callback: (status: string) => void) { test("NodeJS Style Callback Client Tests", function(assert) { var checkRecursively = makeRecursiveCheck(assert); function makeAsserter(assertionFn: (a: any, b: any, msg?: string) => void) { return function(c: (string | any)[]) { var fnName = c[0]; var expected = c[1]; (client)[fnName](expected, function(err: any, actual: any) { assert.error(err, fnName + ": no callback error"); assertionFn(actual, expected, fnName); }) }; } testCases.simple.forEach(makeAsserter(assert.equal)); testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){ assert.ok(a == e, m); })); testCases.deep.forEach(makeAsserter(assert.deepEqual)); client.testMapMap(42, function(err, response) { var expected: typeof response = { "4": {"1":1, "2":2, "3":3, "4":4}, "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1} }; assert.error(err, 'testMapMap: no callback error'); assert.deepEqual(expected, response, "testMapMap"); }); client.testStruct(testCases.out, function(err, response) { assert.error(err, "testStruct: no callback error"); checkRecursively(testCases.out, response, "testStruct"); }); client.testNest(testCases.out2, function(err, response) { assert.error(err, "testNest: no callback error"); checkRecursively(testCases.out2, response, "testNest"); }); client.testInsanity(testCases.crazy, function(err, response) { assert.error(err, "testInsanity: no callback error"); checkRecursively(testCases.insanity, response, "testInsanity"); }); client.testException("TException", function(err, response) { assert.ok(err instanceof TException, 'testException: correct error type'); assert.ok(!Boolean(response), 'testException: no response'); }); client.testException("Xception", function(err, response) { assert.ok(err instanceof ttypes.Xception, 'testException: correct error type'); assert.ok(!Boolean(response), 'testException: no response'); assert.equal(err.errorCode, 1001, 'testException: correct error code'); assert.equal('Xception', err.message, 'testException: correct error message'); }); client.testException("no Exception", function(err, response) { assert.error(err, 'testException: no callback error'); assert.ok(!Boolean(response), 'testException: no response'); }); client.testOneway(0, function(err, response) { assert.error(err, 'testOneway: no callback error'); assert.strictEqual(response, undefined, 'testOneway: void response'); }); checkOffByOne(function(done) { client.testI32(-1, function(err, response) { assert.error(err, "checkOffByOne: no callback error"); assert.equal(-1, response); assert.end(); done(); }); }, callback); }); }; export function ThriftTestDriverPromise(client: ThriftTest.Client, callback: (status: string) => void) { test("Q Promise Client Tests", function(assert) { var checkRecursively = makeRecursiveCheck(assert); function fail(msg: string) { return function(error, response) { if (error !== null) { assert.fail(msg); } } } function makeAsserter(assertionFn: (a: any, b: any, msg?: string) => void) { return function(c: (string | any)[]) { var fnName = c[0]; var expected = c[1]; (client)[fnName](expected) .then(function(actual: any) { assertionFn(actual, expected, fnName); }) .fail(fail("fnName")); }; } testCases.simple.forEach(makeAsserter(assert.equal)); testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){ assert.ok(a == e, m); })); testCases.deep.forEach(makeAsserter(assert.deepEqual)); Q.resolve(client.testStruct(testCases.out)) .then(function(response) { checkRecursively(testCases.out, response, "testStruct"); }) .fail(fail("testStruct")); Q.resolve(client.testNest(testCases.out2)) .then(function(response) { checkRecursively(testCases.out2, response, "testNest"); }) .fail(fail("testNest")); Q.resolve(client.testInsanity(testCases.crazy)) .then(function(response) { checkRecursively(testCases.insanity, response, "testInsanity"); }) .fail(fail("testInsanity")); Q.resolve(client.testException("TException")) .then(function(response) { fail("testException: TException"); }) .fail(function(err) { assert.ok(err instanceof TException); }); Q.resolve(client.testException("Xception")) .then(function(response) { fail("testException: Xception"); }) .fail(function(err) { assert.ok(err instanceof ttypes.Xception); assert.equal(err.errorCode, 1001); assert.equal("Xception", err.message); }); Q.resolve(client.testException("no Exception")) .then(function(response) { assert.equal(undefined, response); //void }) .fail(fail("testException")); client.testOneway(0, fail("testOneway: should not answer")); checkOffByOne(function(done) { Q.resolve(client.testI32(-1)) .then(function(response) { assert.equal(-1, response); assert.end(); done(); }) .fail(fail("checkOffByOne")); }, callback); }); }; // Helper Functions // ========================================================= function makeRecursiveCheck(assert: test.Test) { return function (map1: any, map2: any, msg: string) { var equal = true; var equal = checkRecursively(map1, map2); assert.ok(equal, msg); // deepEqual doesn't work with fields using node-int64 function checkRecursively(map1: any, map2: any) : boolean { if (!(typeof map1 !== "function" && typeof map2 !== "function")) { return false; } if (!map1 || typeof map1 !== "object") { //Handle int64 types (which use node-int64 in Node.js JavaScript) if ((typeof map1 === "number") && (typeof map2 === "object") && (map2.buffer) && (map2.buffer instanceof Buffer) && (map2.buffer.length === 8)) { var n = new Int64(map2.buffer); return map1 === n.toNumber(); } else { return map1 == map2; } } else { return Object.keys(map1).every(function(key) { return checkRecursively(map1[key], map2[key]); }); } } } } function checkOffByOne(done: (callback: () => void) => void, callback: (message: string) => void) { var retry_limit = 30; var retry_interval = 100; var test_complete = false; var retrys = 0; /** * redo a simple test after the oneway to make sure we aren't "off by one" -- * if the server treated oneway void like normal void, this next test will * fail since it will get the void confirmation rather than the correct * result. In this circumstance, the client will throw the exception: * * Because this is the last test against the server, when it completes * the entire suite is complete by definition (the tests run serially). */ done(function() { test_complete = true; }); //We wait up to retry_limit * retry_interval for the test suite to complete function TestForCompletion() { if(test_complete && callback) { callback("Server successfully tested!"); } else { if (++retrys < retry_limit) { setTimeout(TestForCompletion, retry_interval); } else if (callback) { callback("Server test failed to complete after " + (retry_limit * retry_interval / 1000) + " seconds"); } } } setTimeout(TestForCompletion, retry_interval); } thrift-0.16.0/lib/nodets/test/test_handler.ts000066400000000000000000000226011420101504100211300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //This is the server side Node test handler for the standard // Apache Thrift test service. import ttypes = require("./gen-nodejs/ThriftTest_types"); import thrift = require("thrift"); import Thrift = thrift.Thrift; import Q = require("q"); import Int64 = require("node-int64"); export class SyncThriftTestHandler { testVoid(): Q.IPromise { //console.log('testVoid()'); return Q.resolve(undefined); } testMapMap(hello: number) { //console.log('testMapMap(' + hello + ')'); var mapmap: {[key: number]: {[key: number]: number; }} = []; var pos: {[key: number]: number; } = []; var neg: {[key: number]: number; } = []; for (var i = 1; i < 5; i++) { pos[i] = i; neg[-i] = -i; } mapmap[4] = pos; mapmap[-4] = neg; return Q.resolve(mapmap); } testInsanity(argument: ttypes.Insanity): Q.IPromise<{ [k: number]: any; }> { const first_map: { [k: number]: any; } = []; const second_map: { [k: number]: any; } = []; first_map[ttypes.Numberz.TWO] = argument; first_map[ttypes.Numberz.THREE] = argument; const looney = new ttypes.Insanity(); second_map[ttypes.Numberz.SIX] = looney; const insane: { [k: number]: any; } = []; insane[1] = first_map; insane[2] = second_map; return Q.resolve(insane); } testMulti(arg0: any, arg1: number, arg2: Int64, arg3: { [k: number]: string; }, arg4: ttypes.Numberz, arg5: number) { var hello = new ttypes.Xtruct(); hello.string_thing = 'Hello2'; hello.byte_thing = arg0; hello.i32_thing = arg1; hello.i64_thing = arg2; return Q.resolve(hello); } testException(arg: string): Q.IPromise { if (arg === 'Xception') { var x = new ttypes.Xception(); x.errorCode = 1001; x.message = arg; throw x; } else if (arg === 'TException') { throw new Thrift.TException(arg); } else { return Q.resolve(); } } testMultiException(arg0: string, arg1: string) { if (arg0 === ('Xception')) { var x = new ttypes.Xception(); x.errorCode = 1001; x.message = 'This is an Xception'; throw x; } else if (arg0 === ('Xception2')) { var x2 = new ttypes.Xception2(); x2.errorCode = 2002; x2.struct_thing = new ttypes.Xtruct(); x2.struct_thing.string_thing = 'This is an Xception2'; throw x2; } var res = new ttypes.Xtruct(); res.string_thing = arg1; return Q.resolve(res); } testOneway(sleepFor: number) { } testString(thing: string) { return Q.resolve(thing); } testBool(thing: boolean) { return Q.resolve(thing); } testByte(thing: number) { return Q.resolve(thing); } testI32(thing: number) { return Q.resolve(thing); } testI64(thing: number) { return Q.resolve(thing); } testDouble(thing: number) { return Q.resolve(thing); } testBinary(thing: Buffer) { return Q.resolve(thing); } testStruct(thing: ttypes.Xtruct) { return Q.resolve(thing); } testNest(thing: ttypes.Xtruct2) { return Q.resolve(thing); } testMap(thing: { [k: number]: number; }) { return Q.resolve(thing); } testStringMap(thing: { [k: string]: string; }) { return Q.resolve(thing); } testSet(thing: number[]) { return Q.resolve(thing); } testList(thing: number[]) { return Q.resolve(thing); } testEnum(thing: ttypes.Numberz) { return Q.resolve(thing); } testTypedef(thing: number) { return Q.resolve(thing); } } export class AsyncThriftTestHandler { private syncHandler: SyncThriftTestHandler; constructor() { this.syncHandler = new SyncThriftTestHandler(); } testVoid(callback: (result: void) => void): Q.IPromise { callback(undefined); return Q.resolve(); } testMapMap(hello: number, callback: (err: any, result: { [k: number]: { [k: number]: number; }; }) => void): Q.IPromise<{ [k: number]: { [k: number]: number; }; }> { var mapmap: {[key: number]: {[key: number]: number; }} = []; var pos: {[key: number]: number; } = []; var neg: {[key: number]: number; } = []; for (var i = 1; i < 5; i++) { pos[i] = i; neg[-i] = -i; } mapmap[4] = pos; mapmap[-4] = neg; callback(null, mapmap); return Q.resolve(); } testInsanity(argument: ttypes.Insanity, callback?: (err: any, result: { [k: number]: any; }) => void): Q.IPromise<{ [k: number]: any; }> { const first_map: { [k: number]: any; } = []; const second_map: { [k: number]: any; } = []; first_map[ttypes.Numberz.TWO] = argument; first_map[ttypes.Numberz.THREE] = argument; const looney = new ttypes.Insanity(); second_map[ttypes.Numberz.SIX] = looney; const insane: { [k: number]: any; } = []; insane[1] = first_map; insane[2] = second_map; if (callback !== undefined){ callback(null, insane); } return Q.resolve(); } testMulti(arg0: any, arg1: number, arg2: Int64, arg3: { [k: number]: string; }, arg4: ttypes.Numberz, arg5: number, result: Function): Q.IPromise { var hello = this.syncHandler.testMulti(arg0, arg1, arg2, arg3, arg4, arg5); hello.then(hello => result(null, hello)); return Q.resolve(); } testException(arg: string, result: (err: any) => void): Q.IPromise { if (arg === 'Xception') { var x = new ttypes.Xception(); x.errorCode = 1001; x.message = arg; result(x); } else if (arg === 'TException') { result(new Thrift.TException(arg)); } else { result(null); } return Q.resolve(); } testMultiException(arg0: string, arg1: string, result: (err: any, res?: ttypes.Xtruct) => void): Q.IPromise { if (arg0 === ('Xception')) { var x = new ttypes.Xception(); x.errorCode = 1001; x.message = 'This is an Xception'; result(x); } else if (arg0 === ('Xception2')) { var x2 = new ttypes.Xception2(); x2.errorCode = 2002; x2.struct_thing = new ttypes.Xtruct(); x2.struct_thing.string_thing = 'This is an Xception2'; result(x2); } else { var res = new ttypes.Xtruct(); res.string_thing = arg1; result(null, res); } return Q.resolve(); } testOneway(sleepFor: number, result: Function) { this.syncHandler.testOneway(sleepFor); } testString(thing: string, callback: (err: any, result: string) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testByte(thing: number, callback: (err: any, result: number) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testBool(thing: boolean, callback: (err: any, result: boolean) => void ): Q.IPromise { callback(null, thing); return Q.resolve(); } testI32(thing: number, callback: (err: any, result: number) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testI64(thing: number, callback: (err: any, result: number) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testDouble(thing: number, callback: (err: any, result: number) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testBinary(thing: Buffer, callback: (err: any, result: Buffer) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testStruct(thing: ttypes.Xtruct, callback: (err: any, result: ttypes.Xtruct) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testNest(thing: ttypes.Xtruct2, callback: (err: any, result: ttypes.Xtruct2) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testMap(thing: { [k: number]: number; }, callback: (err: any, result: { [k: number]: number; }) => void): Q.IPromise<{ [k: number]: number; }> { callback(null, thing); return Q.resolve(); } testStringMap(thing: { [k: string]: string; }, callback: (err: any, result: { [k: string]: string; }) => void): Q.IPromise<{ [k: string]: string; }> { callback(null, thing); return Q.resolve(); } testSet(thing: number[], callback: (err: any, result: number[]) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testList(thing: number[], callback: (err: any, result: number[]) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testEnum(thing: ttypes.Numberz, callback: (err: any, result: ttypes.Numberz) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } testTypedef(thing: number, callback: (err: any, result: number) => void): Q.IPromise { callback(null, thing); return Q.resolve(); } } thrift-0.16.0/lib/nodets/test/tsconfig.json000066400000000000000000000011241420101504100206100ustar00rootroot00000000000000{ "compilerOptions": { "allowJs": false, "alwaysStrict": true, "baseUrl": ".", "declaration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "module": "commonjs", "moduleResolution": "node", "noImplicitThis": true, "noUnusedLocals": true, "preserveConstEnums": true, "removeComments": true, "strictFunctionTypes": true, "strictNullChecks": true, "target": "es6", "paths": { "thrift": ["../../nodejs/lib/thrift"] } } } thrift-0.16.0/lib/ocaml/000077500000000000000000000000001420101504100147235ustar00rootroot00000000000000thrift-0.16.0/lib/ocaml/DEVELOPMENT000066400000000000000000000040521420101504100164310ustar00rootroot00000000000000Thrift OCaml Development ======================== Prerequisites ------------- In order to build this library, you must have the following installed: * The OCaml compiler, preferably >4.00 * The Oasis build tool In addition you may want to install OPAM, which will allow you to setup an OCaml development environment that's isolated from your system installation, much like virutalenv for Python or the myriad systems available for Ruby. If you have OPAM installed, then installing Oasis is as simple as running: $ opam install oasis Building -------- Once all the prerequisites have been installed, run the following commands: $ oasis setup $ ./configure $ make The `oasis setup` command will generate the configure script and Makefile, along with other files that opam will use to create an installable library. The cofigure script will ensure that all build dependencies are installed, and make will actually build the library. To remove files that the compiler geneates, run: $ make clean To remove those files _as well as_ files that the setup and configure process generates, run: $ rm `cat .gitignore` Installing ---------- If you're using opam, simply run the following command: $ make install While development, you may want to install your latest build on the system to test against other libraries or programs. To do this, use: $ make reinstall Distribution ------------ The de facto preferred method for distributing OCaml libraries is through the OPAM package repository. To publish the latest package, issue a pull request against the following github repository: https://github.com/ocaml/opam-repository The pull requestion should add the following directory structure and files: package |__thrift |__thrift. |__ descr |__ opam |__ url Templates for the following files can be found in the opam/ subdirectory of this library's root, with XXX(...) indicating fields that need to be filled out. You can find further documentation here: http://opam.ocaml.org/doc/Packaging.html thrift-0.16.0/lib/ocaml/README.md000066400000000000000000000055441420101504100162120ustar00rootroot00000000000000Thrift OCaml Software Library License ======= Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Library ======= The library abstract classes, exceptions, and general use functions are mostly jammed in Thrift.ml (an exception being TServer). Generally, classes are used, however they are often put in their own module along with other relevant types and functions. The classes often called t, exceptions are called E. Implementations live in their own files. There is TBinaryProtocol, TSocket, TThreadedServer, TSimpleServer, and TServerSocket. A note on making the library: Running make should create native, debug code libraries, and a toplevel. Struct format ------------- Structs are turned into classes. The fields are all option types and are initially None. Write is a method, but reading is done by a separate function (since there is no such thing as a static class). The class type is t and is in a module with the name of the struct. enum format ----------- Enums are put in their own module along with functions to_i and of_i which convert the ocaml types into ints. For example: enum Numberz { ONE = 1, TWO, THREE, FIVE = 5, SIX, EIGHT = 8 } ==> module Numberz = struct type t = | ONE | TWO | THREE | FIVE | SIX | EIGHT let of_i = ... let to_i = ... end typedef format -------------- Typedef turns into the type declaration: typedef i64 UserId ==> type userid Int64.t exception format ---------------- The same as structs except that the module also has an exception type E of t that is raised/caught. For example, with an exception Xception, raise (Xception.E (new Xception.t)) and try ... with Xception.E e -> ... list format ----------- Lists are turned into OCaml native lists. Map/Set formats --------------- These are both turned into Hashtbl.t's. Set values are bool. Services -------- The client is a class "client" parametrized on input and output protocols. The processor is a class parametrized on a handler. A handler is a class inheriting the iface abstract class. Unlike other implementations, client does not implement iface since iface functions must take option arguments so as to deal with the case where a client does not send all the arguments. thrift-0.16.0/lib/ocaml/TODO000066400000000000000000000001621420101504100154120ustar00rootroot00000000000000Write interfaces Clean up the code generator Avoid capture properly instead of relying on the user not to use _ thrift-0.16.0/lib/ocaml/_oasis000066400000000000000000000010541420101504100161230ustar00rootroot00000000000000Name: libthrift-ocaml Version: 0.16.0 OASISFormat: 0.3 Synopsis: OCaml bindings for the Apache Thrift RPC system Authors: Apache Thrift Developers License: Apache-2.0 Homepage: http://thrift.apache.org BuildTools: ocamlbuild Plugins: META (0.3), DevFiles (0.3) Library "libthrift-ocaml" Path: src FindlibName: thrift buildTools: ocamlbuild BuildDepends: threads Modules: Thrift,TBinaryProtocol,TSocket,TFramedTransport,TChannelTransport,TServer,TSimpleServer,TServerSocket,TThreadedServer XMETARequires: threads thrift-0.16.0/lib/ocaml/coding_standards.md000066400000000000000000000001031420101504100205450ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/ocaml/descr000066400000000000000000000000601420101504100157420ustar00rootroot00000000000000OCaml bindings for the Apache Thrift RPC system thrift-0.16.0/lib/ocaml/opam000066400000000000000000000002431420101504100156010ustar00rootroot00000000000000opam-version: "1" maintainer: "XXX(FILL ME IN WITH EMAIL)" build: [ [make] [make "install"] ] remove: [["ocamlfind" "remove" "thrift"]] depends: ["ocamlfind"] thrift-0.16.0/lib/ocaml/src/000077500000000000000000000000001420101504100155125ustar00rootroot00000000000000thrift-0.16.0/lib/ocaml/src/Makefile000066400000000000000000000021111420101504100171450ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SOURCES = Thrift.ml TBinaryProtocol.ml TSocket.ml TFramedTransport.ml TChannelTransport.ml TServer.ml TSimpleServer.ml TServerSocket.ml TThreadedServer.ml RESULT = thrift LIBS = unix threads THREADS = yes all: native-code-library debug-code-library top OCAMLMAKEFILE = ../OCamlMakefile include $(OCAMLMAKEFILE) thrift-0.16.0/lib/ocaml/src/TBinaryProtocol.ml000066400000000000000000000117051420101504100211420ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Thrift module P = Protocol let get_byte i b = 255 land (i lsr (8*b)) let get_byte32 i b = 255 land (Int32.to_int (Int32.shift_right i (8*b))) let get_byte64 i b = 255 land (Int64.to_int (Int64.shift_right i (8*b))) let tv = P.t_type_to_i let vt = P.t_type_of_i let comp_int b n = let s = ref 0l in let sb = 32 - 8*n in for i=0 to (n-1) do s:= Int32.logor !s (Int32.shift_left (Int32.of_int (int_of_char b.[i])) (8*(n-1-i))) done; Int32.shift_right (Int32.shift_left !s sb) sb let comp_int64 b n = let s = ref 0L in for i=0 to (n-1) do s:=Int64.logor !s (Int64.shift_left (Int64.of_int (int_of_char b.[i])) (8*(n-1-i))) done; !s let version_mask = 0xffff0000l let version_1 = 0x80010000l class t trans = object (self) inherit P.t trans val ibyte = String.create 8 method writeBool b = ibyte.[0] <- char_of_int (if b then 1 else 0); trans#write ibyte 0 1 method writeByte i = ibyte.[0] <- char_of_int (get_byte i 0); trans#write ibyte 0 1 method writeI16 i = let gb = get_byte i in ibyte.[1] <- char_of_int (gb 0); ibyte.[0] <- char_of_int (gb 1); trans#write ibyte 0 2 method writeI32 i = let gb = get_byte32 i in for i=0 to 3 do ibyte.[3-i] <- char_of_int (gb i) done; trans#write ibyte 0 4 method writeI64 i= let gb = get_byte64 i in for i=0 to 7 do ibyte.[7-i] <- char_of_int (gb i) done; trans#write ibyte 0 8 method writeDouble d = self#writeI64 (Int64.bits_of_float d) method writeString s= let n = String.length s in self#writeI32 (Int32.of_int n); trans#write s 0 n method writeBinary a = self#writeString a method writeMessageBegin (n,t,s) = self#writeI32 (Int32.logor version_1 (Int32.of_int (P.message_type_to_i t))); self#writeString n; self#writeI32 (Int32.of_int s) method writeMessageEnd = () method writeStructBegin s = () method writeStructEnd = () method writeFieldBegin (n,t,i) = self#writeByte (tv t); self#writeI16 i method writeFieldEnd = () method writeFieldStop = self#writeByte (tv (P.T_STOP)) method writeMapBegin (k,v,s) = self#writeByte (tv k); self#writeByte (tv v); self#writeI32 (Int32.of_int s) method writeMapEnd = () method writeListBegin (t,s) = self#writeByte (tv t); self#writeI32 (Int32.of_int s) method writeListEnd = () method writeSetBegin (t,s) = self#writeByte (tv t); self#writeI32 (Int32.of_int s) method writeSetEnd = () method readByte = ignore (trans#readAll ibyte 0 1); Int32.to_int (comp_int ibyte 1) method readI16 = ignore (trans#readAll ibyte 0 2); Int32.to_int (comp_int ibyte 2) method readI32 = ignore (trans#readAll ibyte 0 4); comp_int ibyte 4 method readI64 = ignore (trans#readAll ibyte 0 8); comp_int64 ibyte 8 method readDouble = Int64.float_of_bits (self#readI64) method readBool = self#readByte = 1 method readString = let sz = Int32.to_int (self#readI32) in let buf = String.create sz in ignore (trans#readAll buf 0 sz); buf method readBinary = self#readString method readMessageBegin = let ver = self#readI32 in if Int32.compare (Int32.logand ver version_mask) version_1 != 0 then raise (P.E (P.BAD_VERSION, "Missing version identifier")) else let s = self#readString in let mt = P.message_type_of_i (Int32.to_int (Int32.logand ver 0xFFl)) in (s,mt, Int32.to_int self#readI32) method readMessageEnd = () method readStructBegin = "" method readStructEnd = () method readFieldBegin = let t = (vt (self#readByte)) in if t != P.T_STOP then ("",t,self#readI16) else ("",t,0); method readFieldEnd = () method readMapBegin = let kt = vt (self#readByte) in let vt = vt (self#readByte) in (kt,vt, Int32.to_int self#readI32) method readMapEnd = () method readListBegin = let t = vt (self#readByte) in (t, Int32.to_int self#readI32) method readListEnd = () method readSetBegin = let t = vt (self#readByte) in (t, Int32.to_int self#readI32); method readSetEnd = () end class factory = object inherit P.factory method getProtocol tr = new t tr end thrift-0.16.0/lib/ocaml/src/TChannelTransport.ml000066400000000000000000000024631420101504100214620ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Thrift module T = Transport class t (i,o) = object (self) val mutable opened = true inherit Transport.t method isOpen = opened method opn = () method close = close_in i; opened <- false method read buf off len = if opened then try really_input i buf off len; len with _ -> raise (T.E (T.UNKNOWN, ("TChannelTransport: Could not read "^(string_of_int len)))) else raise (T.E (T.NOT_OPEN, "TChannelTransport: Channel was closed")) method write buf off len = output o buf off len method flush = flush o end thrift-0.16.0/lib/ocaml/src/TFramedTransport.ml000066400000000000000000000051151420101504100213050ustar00rootroot00000000000000open Thrift module T = Transport let c_0xff_32 = Int32.of_string "0xff" (* Copied from OCamlnet rtypes.ml *) let encode_frame_size x = let s = String.create 4 in let n3 = Int32.to_int (Int32.shift_right_logical x 24) land 0xff in let n2 = Int32.to_int (Int32.shift_right_logical x 16) land 0xff in let n1 = Int32.to_int (Int32.shift_right_logical x 8) land 0xff in let n0 = Int32.to_int (Int32.logand x c_0xff_32) in String.unsafe_set s 0 (Char.unsafe_chr n3); String.unsafe_set s 1 (Char.unsafe_chr n2); String.unsafe_set s 2 (Char.unsafe_chr n1); String.unsafe_set s 3 (Char.unsafe_chr n0); s let decode_frame_size s = let n3 = Int32.of_int (Char.code s.[0]) in let n2 = Int32.of_int (Char.code s.[1]) in let n1 = Int32.of_int (Char.code s.[2]) in let n0 = Int32.of_int (Char.code s.[3]) in Int32.logor (Int32.shift_left n3 24) (Int32.logor (Int32.shift_left n2 16) (Int32.logor (Int32.shift_left n1 8) n0)) class t ?(max_length=Sys.max_string_length) (transport: T.t) = object (self) inherit T.t method isOpen = transport#isOpen method opn = transport#opn method close = transport#close val mutable read_buf = None val mutable read_buf_offset = 0 val mutable write_buf = "" method private read_frame = let len_buf = String.create 4 in assert (transport#readAll len_buf 0 4 = 4); let size = Int32.to_int (decode_frame_size len_buf) in (if size < 0 then failwith (Printf.sprintf "Read a negative frame size (%i)!" size)); (if size > max_length then failwith (Printf.sprintf "Frame size (%i) larger than max length (%i)!" size max_length)); let buf = String.create size in assert (transport#readAll buf 0 size = size); read_buf <- Some buf; read_buf_offset <- 0 method private read_from_frame frame buf off len = let to_copy = min len ((String.length frame) - read_buf_offset) in String.blit frame read_buf_offset buf off to_copy; read_buf_offset <- read_buf_offset + to_copy; to_copy method read buf off len = match read_buf with | Some frame -> let i = self#read_from_frame frame buf off len in if i > 0 then i else begin self#read_frame; self#read_from_frame frame buf off len end | None -> self#read_frame; self#read buf off len method write buf off len = write_buf <- write_buf ^ (String.sub buf off len) method flush = let encoded_size = encode_frame_size (Int32.of_int (String.length write_buf)) in transport#write encoded_size 0 (String.length encoded_size); transport#write write_buf 0 (String.length write_buf); transport#flush; write_buf <- "" end thrift-0.16.0/lib/ocaml/src/TServer.ml000066400000000000000000000026471420101504100174470ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Thrift class virtual t (pf : Processor.t) (st : Transport.server_t) (tf : Transport.factory) (ipf : Protocol.factory) (opf : Protocol.factory)= object method virtual serve : unit end;; let run_basic_server proc port = Unix.establish_server (fun inp -> fun out -> let trans = new TChannelTransport.t (inp,out) in let proto = new TBinaryProtocol.t (trans :> Transport.t) in try while proc#process proto proto do () done; () with e -> ()) (Unix.ADDR_INET (Unix.inet_addr_of_string "127.0.0.1",port)) thrift-0.16.0/lib/ocaml/src/TServerSocket.ml000066400000000000000000000027251420101504100206150ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Thrift class t port = object inherit Transport.server_t val mutable sock = None method listen = let s = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in sock <- Some s; Unix.bind s (Unix.ADDR_INET (Unix.inet_addr_any, port)); Unix.listen s 256 method close = match sock with Some s -> Unix.shutdown s Unix.SHUTDOWN_ALL; Unix.close s; sock <- None | _ -> () method acceptImpl = match sock with Some s -> let (fd,_) = Unix.accept s in new TChannelTransport.t (Unix.in_channel_of_descr fd,Unix.out_channel_of_descr fd) | _ -> raise (Transport.E (Transport.NOT_OPEN,"TServerSocket: Not listening but tried to accept")) end thrift-0.16.0/lib/ocaml/src/TSimpleServer.ml000066400000000000000000000023371420101504100206150ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Thrift module S = TServer class t pf st tf ipf opf = object inherit S.t pf st tf ipf opf method serve = try st#listen; while true do let c = st#accept in let trans = tf#getTransport c in let inp = ipf#getProtocol trans in let op = opf#getProtocol trans in try while (pf#process inp op) do () done; trans#close with e -> trans#close; raise e done with _ -> () end thrift-0.16.0/lib/ocaml/src/TSocket.ml000066400000000000000000000045141420101504100174240ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Thrift module T = Transport class t host port= object (self) inherit T.t val mutable chans = None method isOpen = chans != None method opn = try let addr = (let {Unix.h_addr_list=x} = Unix.gethostbyname host in x.(0)) in chans <- Some(Unix.open_connection (Unix.ADDR_INET (addr,port))) with Unix.Unix_error (e,fn,_) -> raise (T.E (T.NOT_OPEN, ("TSocket: Could not connect to "^host^":"^(string_of_int port)^" because: "^fn^":"^(Unix.error_message e)))) | _ -> raise (T.E (T.NOT_OPEN, ("TSocket: Could not connect to "^host^":"^(string_of_int port)))) method close = match chans with None -> () | Some(inc,out) -> (Unix.shutdown_connection inc; close_in inc; chans <- None) method read buf off len = match chans with None -> raise (T.E (T.NOT_OPEN, "TSocket: Socket not open")) | Some(i,o) -> try really_input i buf off len; len with Unix.Unix_error (e,fn,_) -> raise (T.E (T.UNKNOWN, ("TSocket: Could not read "^(string_of_int len)^" from "^host^":"^(string_of_int port)^" because: "^fn^":"^(Unix.error_message e)))) | _ -> raise (T.E (T.UNKNOWN, ("TSocket: Could not read "^(string_of_int len)^" from "^host^":"^(string_of_int port)))) method write buf off len = match chans with None -> raise (T.E (T.NOT_OPEN, "TSocket: Socket not open")) | Some(i,o) -> output o buf off len method flush = match chans with None -> raise (T.E (T.NOT_OPEN, "TSocket: Socket not open")) | Some(i,o) -> flush o end thrift-0.16.0/lib/ocaml/src/TThreadedServer.ml000066400000000000000000000025131420101504100211000ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Thrift class t (pf : Processor.t) (st : Transport.server_t) (tf : Transport.factory) (ipf : Protocol.factory) (opf : Protocol.factory)= object inherit TServer.t pf st tf ipf opf method serve = st#listen; while true do let tr = tf#getTransport (st#accept) in ignore (Thread.create (fun _ -> let ip = ipf#getProtocol tr in let op = opf#getProtocol tr in try while pf#process ip op do () done with _ -> ()) ()) done end thrift-0.16.0/lib/ocaml/src/Thrift.ml000066400000000000000000000245251420101504100173140ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) exception Break;; exception Thrift_error;; exception Field_empty of string;; class t_exn = object val mutable message = "" method get_message = message method set_message s = message <- s end;; module Transport = struct type exn_type = | UNKNOWN | NOT_OPEN | ALREADY_OPEN | TIMED_OUT | END_OF_FILE;; exception E of exn_type * string class virtual t = object (self) method virtual isOpen : bool method virtual opn : unit method virtual close : unit method virtual read : string -> int -> int -> int method readAll buf off len = let got = ref 0 in let ret = ref 0 in while !got < len do ret := self#read buf (off+(!got)) (len - (!got)); if !ret <= 0 then raise (E (UNKNOWN, "Cannot read. Remote side has closed.")); got := !got + !ret done; !got method virtual write : string -> int -> int -> unit method virtual flush : unit end class factory = object method getTransport (t : t) = t end class virtual server_t = object (self) method virtual listen : unit method accept = self#acceptImpl method virtual close : unit method virtual acceptImpl : t end end;; module Protocol = struct type t_type = | T_STOP | T_VOID | T_BOOL | T_BYTE | T_I08 | T_I16 | T_I32 | T_U64 | T_I64 | T_DOUBLE | T_STRING | T_UTF7 | T_STRUCT | T_MAP | T_SET | T_LIST | T_UTF8 | T_UTF16 let t_type_to_i = function T_STOP -> 0 | T_VOID -> 1 | T_BOOL -> 2 | T_BYTE -> 3 | T_I08 -> 3 | T_I16 -> 6 | T_I32 -> 8 | T_U64 -> 9 | T_I64 -> 10 | T_DOUBLE -> 4 | T_STRING -> 11 | T_UTF7 -> 11 | T_STRUCT -> 12 | T_MAP -> 13 | T_SET -> 14 | T_LIST -> 15 | T_UTF8 -> 16 | T_UTF16 -> 17 let t_type_of_i = function 0 -> T_STOP | 1 -> T_VOID | 2 -> T_BOOL | 3 -> T_BYTE | 6-> T_I16 | 8 -> T_I32 | 9 -> T_U64 | 10 -> T_I64 | 4 -> T_DOUBLE | 11 -> T_STRING | 12 -> T_STRUCT | 13 -> T_MAP | 14 -> T_SET | 15 -> T_LIST | 16 -> T_UTF8 | 17 -> T_UTF16 | _ -> raise Thrift_error type message_type = | CALL | REPLY | EXCEPTION | ONEWAY let message_type_to_i = function | CALL -> 1 | REPLY -> 2 | EXCEPTION -> 3 | ONEWAY -> 4 let message_type_of_i = function | 1 -> CALL | 2 -> REPLY | 3 -> EXCEPTION | 4 -> ONEWAY | _ -> raise Thrift_error class virtual t (trans: Transport.t) = object (self) val mutable trans_ = trans method getTransport = trans_ (* writing methods *) method virtual writeMessageBegin : string * message_type * int -> unit method virtual writeMessageEnd : unit method virtual writeStructBegin : string -> unit method virtual writeStructEnd : unit method virtual writeFieldBegin : string * t_type * int -> unit method virtual writeFieldEnd : unit method virtual writeFieldStop : unit method virtual writeMapBegin : t_type * t_type * int -> unit method virtual writeMapEnd : unit method virtual writeListBegin : t_type * int -> unit method virtual writeListEnd : unit method virtual writeSetBegin : t_type * int -> unit method virtual writeSetEnd : unit method virtual writeBool : bool -> unit method virtual writeByte : int -> unit method virtual writeI16 : int -> unit method virtual writeI32 : Int32.t -> unit method virtual writeI64 : Int64.t -> unit method virtual writeDouble : float -> unit method virtual writeString : string -> unit method virtual writeBinary : string -> unit (* reading methods *) method virtual readMessageBegin : string * message_type * int method virtual readMessageEnd : unit method virtual readStructBegin : string method virtual readStructEnd : unit method virtual readFieldBegin : string * t_type * int method virtual readFieldEnd : unit method virtual readMapBegin : t_type * t_type * int method virtual readMapEnd : unit method virtual readListBegin : t_type * int method virtual readListEnd : unit method virtual readSetBegin : t_type * int method virtual readSetEnd : unit method virtual readBool : bool method virtual readByte : int method virtual readI16 : int method virtual readI32: Int32.t method virtual readI64 : Int64.t method virtual readDouble : float method virtual readString : string method virtual readBinary : string (* skippage *) method skip typ = match typ with | T_BOOL -> ignore self#readBool | T_BYTE | T_I08 -> ignore self#readByte | T_I16 -> ignore self#readI16 | T_I32 -> ignore self#readI32 | T_U64 | T_I64 -> ignore self#readI64 | T_DOUBLE -> ignore self#readDouble | T_STRING -> ignore self#readString | T_UTF7 -> () | T_STRUCT -> ignore ((ignore self#readStructBegin); (try while true do let (_,t,_) = self#readFieldBegin in if t = T_STOP then raise Break else (self#skip t; self#readFieldEnd) done with Break -> ()); self#readStructEnd) | T_MAP -> ignore (let (k,v,s) = self#readMapBegin in for i=0 to s do self#skip k; self#skip v; done; self#readMapEnd) | T_SET -> ignore (let (t,s) = self#readSetBegin in for i=0 to s do self#skip t done; self#readSetEnd) | T_LIST -> ignore (let (t,s) = self#readListBegin in for i=0 to s do self#skip t done; self#readListEnd) | T_UTF8 -> () | T_UTF16 -> () | _ -> raise (Protocol.E (Protocol.INVALID_DATA, "Invalid data")) end class virtual factory = object method virtual getProtocol : Transport.t -> t end type exn_type = | UNKNOWN | INVALID_DATA | NEGATIVE_SIZE | SIZE_LIMIT | BAD_VERSION | NOT_IMPLEMENTED | DEPTH_LIMIT exception E of exn_type * string;; end;; module Processor = struct class virtual t = object method virtual process : Protocol.t -> Protocol.t -> bool end;; class factory (processor : t) = object val processor_ = processor method getProcessor (trans : Transport.t) = processor_ end;; end (* Ugly *) module Application_Exn = struct type typ= | UNKNOWN | UNKNOWN_METHOD | INVALID_MESSAGE_TYPE | WRONG_METHOD_NAME | BAD_SEQUENCE_ID | MISSING_RESULT | INTERNAL_ERROR | PROTOCOL_ERROR | INVALID_TRANSFORM | INVALID_PROTOCOL | UNSUPPORTED_CLIENT_TYPE let typ_of_i = function 0l -> UNKNOWN | 1l -> UNKNOWN_METHOD | 2l -> INVALID_MESSAGE_TYPE | 3l -> WRONG_METHOD_NAME | 4l -> BAD_SEQUENCE_ID | 5l -> MISSING_RESULT | 6l -> INTERNAL_ERROR | 7l -> PROTOCOL_ERROR | 8l -> INVALID_TRANSFORM | 9l -> INVALID_PROTOCOL | 10l -> UNSUPPORTED_CLIENT_TYPE | _ -> raise Thrift_error;; let typ_to_i = function | UNKNOWN -> 0l | UNKNOWN_METHOD -> 1l | INVALID_MESSAGE_TYPE -> 2l | WRONG_METHOD_NAME -> 3l | BAD_SEQUENCE_ID -> 4l | MISSING_RESULT -> 5l | INTERNAL_ERROR -> 6l | PROTOCOL_ERROR -> 7l | INVALID_TRANSFORM -> 8l | INVALID_PROTOCOL -> 9l | UNSUPPORTED_CLIENT_TYPE -> 10l class t = object (self) inherit t_exn val mutable typ = UNKNOWN method get_type = typ method set_type t = typ <- t method write (oprot : Protocol.t) = oprot#writeStructBegin "TApplicationExeception"; if self#get_message != "" then (oprot#writeFieldBegin ("message",Protocol.T_STRING, 1); oprot#writeString self#get_message; oprot#writeFieldEnd) else (); oprot#writeFieldBegin ("type",Protocol.T_I32,2); oprot#writeI32 (typ_to_i typ); oprot#writeFieldEnd; oprot#writeFieldStop; oprot#writeStructEnd end;; let create typ msg = let e = new t in e#set_type typ; e#set_message msg; e let read (iprot : Protocol.t) = let msg = ref "" in let typ = ref 0l in ignore iprot#readStructBegin; (try while true do let (name,ft,id) =iprot#readFieldBegin in if ft = Protocol.T_STOP then raise Break else (); (match id with | 1 -> (if ft = Protocol.T_STRING then msg := (iprot#readString) else iprot#skip ft) | 2 -> (if ft = Protocol.T_I32 then typ := iprot#readI32 else iprot#skip ft) | _ -> iprot#skip ft); iprot#readFieldEnd done with Break -> ()); iprot#readStructEnd; let e = new t in e#set_type (typ_of_i !typ); e#set_message !msg; e;; exception E of t end;; thrift-0.16.0/lib/ocaml/url000066400000000000000000000001111420101504100154410ustar00rootroot00000000000000archive: "XXX(FILL ME IN WITH URL)" checksum: "XXX(FILL ME IN WITH MD5)" thrift-0.16.0/lib/perl/000077500000000000000000000000001420101504100145725ustar00rootroot00000000000000thrift-0.16.0/lib/perl/MANIFEST.SKIP000066400000000000000000000002661420101504100164740ustar00rootroot00000000000000blib/.*$ build-cpan-dist.sh FixupDist.pl MANIFEST.bak MANIFEST.SKIP MYMETA.json Makefile Makefile.am Makefile.in pm_to_blib t/Makefile t/Makefile.am t/Makefile.in tools/FixupDist.pl thrift-0.16.0/lib/perl/Makefile.PL000066400000000000000000000034731420101504100165530ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use ExtUtils::MakeMaker; WriteMakefile( ABSTRACT => 'Apache Thrift is a software framework for scalable cross-language services development.', AUTHOR => 'Apache Thrift ', LICENSE => 'apache_2_0', MIN_PERL_VERSION => '5.010000', NAME => 'Thrift', NEEDS_LINKING => 0, PREREQ_PM => { 'Bit::Vector' => 0, 'Class::Accessor' => 0 }, # SIGN => 1, TEST_REQUIRES => { 'Test::Exception' => 0, }, VERSION_FROM => 'lib/Thrift.pm' ); # THRIFT-4691 package MY; # so that "SUPER" works right sub test { # Adds gen-perl and gen-perl2 to the test execution as include paths # Could not find anything in MakeMaker that would do this... my @result; for (@result = shift->SUPER::test(@_)) { s/\$\(TEST_FILES\)/-Igen-perl -Igen-perl2 \$(TEST_FILES)/ig; } @result; } thrift-0.16.0/lib/perl/Makefile.am000066400000000000000000000060101420101504100166230ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = t Makefile-perl.mk : Makefile.PL $(PERL) Makefile.PL MAKEFILE=Makefile-perl.mk INSTALLDIRS=$(INSTALLDIRS) INSTALL_BASE=$(PERL_PREFIX) all-local: Makefile-perl.mk $(MAKE) -f $< find blib -name 'Makefile*' -exec rm -f {} \; install-exec-local: Makefile-perl.mk $(MAKE) -f $< install DESTDIR=$(DESTDIR)/ clean-local: if test -f Makefile-perl.mk ; then \ $(MAKE) -f Makefile-perl.mk clean ; \ fi $(RM) Makefile-perl.mk.old $(RM) -r gen-perl gen-perl2 EXTRA_DIST = \ coding_standards.md \ build-cpan-dist.sh \ Makefile.PL \ MANIFEST.SKIP \ test.pl \ lib/Thrift.pm \ lib/Thrift.pm \ lib/Thrift/BinaryProtocol.pm \ lib/Thrift/BufferedTransport.pm \ lib/Thrift/Exception.pm \ lib/Thrift/FramedTransport.pm \ lib/Thrift/HttpClient.pm \ lib/Thrift/MemoryBuffer.pm \ lib/Thrift/MessageType.pm \ lib/Thrift/MultiplexedProcessor.pm \ lib/Thrift/MultiplexedProtocol.pm \ lib/Thrift/Protocol.pm \ lib/Thrift/ProtocolDecorator.pm \ lib/Thrift/Server.pm \ lib/Thrift/ServerSocket.pm \ lib/Thrift/Socket.pm \ lib/Thrift/SSLSocket.pm \ lib/Thrift/SSLServerSocket.pm \ lib/Thrift/UnixServerSocket.pm \ lib/Thrift/UnixSocket.pm \ lib/Thrift/Type.pm \ lib/Thrift/Transport.pm \ tools/FixupDist.pl \ README.md THRIFT = @top_builddir@/compiler/cpp/thrift THRIFT_IF = @top_srcdir@/test/ThriftTest.thrift NAME_BENCHMARKSERVICE = @top_srcdir@/lib/rb/benchmark/Benchmark.thrift NAME_AGGR = @top_srcdir@/contrib/async-test/aggr.thrift THRIFTTEST_GEN = \ gen-perl/ThriftTest/Constants.pm \ gen-perl/ThriftTest/SecondService.pm \ gen-perl/ThriftTest/ThriftTest.pm \ gen-perl/ThriftTest/Types.pm BENCHMARK_GEN = \ gen-perl/BenchmarkService.pm \ gen-perl/Constants.pm \ gen-perl/Types.pm AGGR_GEN = \ gen-perl2/Aggr.pm \ gen-perl2/Constants.pm \ gen-perl2/Types.pm PERL_GEN = \ $(THRIFTTEST_GEN) \ $(BENCHMARK_GEN) \ $(AGGR_GEN) BUILT_SOURCES = $(PERL_GEN) check-local: $(PERL_GEN) $(PERL) -Iblib/lib -I@abs_srcdir@ -I@builddir@/gen-perl2 -I@builddir@/gen-perl \ @abs_srcdir@/test.pl @abs_srcdir@/t/*.t $(THRIFTTEST_GEN): $(THRIFT_IF) $(THRIFT) $(THRIFT) --gen perl $< $(BENCHMARK_GEN): $(NAME_BENCHMARKSERVICE) $(THRIFT) $(THRIFT) --gen perl $< $(AGGR_GEN): $(NAME_AGGR) $(THRIFT) $(MKDIR_P) gen-perl2 $(THRIFT) -out gen-perl2 --gen perl $< thrift-0.16.0/lib/perl/README.md000066400000000000000000000105011420101504100160460ustar00rootroot00000000000000Thrift Perl Software Library # Summary Apache Thrift is a software framework for scalable cross-language services development. It combines a software stack with a code generation engine to build services that work efficiently and seamlessly between many programming languages. A language-neutral IDL is used to generate functioning client libraries and server-side handling frameworks. # License Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. # For More Information See the [Apache Thrift Web Site](http://thrift.apache.org/) for more information. # Using Thrift with Perl Thrift requires Perl >= 5.10.0 Unexpected exceptions in a service handler are converted to TApplicationException with type INTERNAL ERROR and the string of the exception is delivered as the message. On the client side, exceptions are thrown with die, so be sure to wrap eval{} statments around any code that contains exceptions. Please see tutoral and test dirs for examples. The Perl ForkingServer ignores SIGCHLD allowing the forks to be reaped by the operating system naturally when they exit. This means one cannot use a custom SIGCHLD handler in the consuming perl implementation that calls serve(). It is acceptable to use a custom SIGCHLD handler within a thrift handler implementation as the ForkingServer resets the forked child process to use default signal handling. # Dependencies The following modules are not provided by Perl 5.10.0 but are required to use Thrift. ## Runtime * Bit::Vector * Class::Accessor ## Test This is only required when running tests: * Test::Exception ### HttpClient Transport These are only required if using Thrift::HttpClient: * HTTP::Request * IO::String * LWP::UserAgent ### SSL/TLS These are only required if using Thrift::SSLSocket or Thrift::SSLServerSocket: * IO::Socket::SSL # Breaking Changes ## 0.10.0 The socket classes were refactored in 0.10.0 so that there is one package per file. This means `use Socket;` no longer defines SSLSocket. You can use this technique to make your application run against 0.10.0 as well as earlier versions: `eval { require Thrift::SSLSocket; } or do { require Thrift::Socket; }` ## 0.11.0 * Namespaces of packages that were not scoped within Thrift have been fixed. ** TApplicationException is now Thrift::TApplicationException ** TException is now Thrift::TException ** TMessageType is now Thrift::TMessageType ** TProtocolException is now Thrift::TProtocolException ** TProtocolFactory is now Thrift::TProtocolFactory ** TTransportException is now Thrift::TTransportException ** TType is now Thrift::TType If you need a single version of your code to work with both older and newer thrift namespace changes, you can make the new, correct namespaces behave like the old ones in your files with this technique to create an alias, which will allow you code to run against either version of the perl runtime for thrift: `BEGIN {*TType:: = *Thrift::TType::}` * Packages found in Thrift.pm were moved into the Thrift/ directory in separate files: ** Thrift::TApplicationException is now in Thrift/Exception.pm ** Thrift::TException is now in Thrift/Exception.pm ** Thrift::TMessageType is now in Thrift/MessageType.pm ** Thrift::TType is now in Thrift/Type.pm If you need to modify your code to work against both older or newer thrift versions, you can deal with these changes in a backwards compatible way in your projects using eval: `eval { require Thrift::Exception; require Thrift::MessageType; require Thrift::Type; } or do { require Thrift; }` # Deprecations ## 0.11.0 Thrift::HttpClient setRecvTimeout() and setSendTimeout() are deprecated. Use setTimeout instead. thrift-0.16.0/lib/perl/build-cpan-dist.sh000077500000000000000000000023641420101504100201150ustar00rootroot00000000000000#!/bin/bash # # This script is intended to be used after tagging the repository and updating # the version files for a release. It will create a CPAN archive. Run this # from inside a docker image like ubuntu-xenial. # set -e rm -f MANIFEST rm -rf Thrift-* # setup cpan without a prompt echo | cpan cpan install HTTP::Date Log::Log4perl cpan install CPAN cpan install CPAN::Meta ExtUtils::MakeMaker JSON::PP # cpan install Module::Signature perl Makefile.PL rm MYMETA.yml make manifest make dist # # We unpack the archive so we can add version metadata for CPAN # so that it properly indexes Thrift and remove unnecessary files. # echo '-----------------------------------------------------------' set -x DISTFILE=$(ls Thrift*.gz) NEWFILE=${DISTFILE/t-v/t-} if [[ "$DISTFILE" != "$NEWFILE" ]]; then mv $DISTFILE $NEWFILE DISTFILE="$NEWFILE" fi tar xzf $DISTFILE rm $DISTFILE DISTDIR=$(ls -d Thrift*) # cpan doesn't like "Thrift-v0.nn.0 as a directory name # needs to be Thrift-0.nn.0 NEWDIR=${DISTDIR/t-v/t-} if [[ "$DISTDIR" != "$NEWDIR" ]]; then mv $DISTDIR $NEWDIR DISTDIR="$NEWDIR" fi cd $DISTDIR cp -p ../Makefile.PL . cp -pr ../gen-perl . cp -pr ../gen-perl2 . perl ../tools/FixupDist.pl cd .. tar cvzf $DISTFILE $DISTDIR rm -r $DISTDIR thrift-0.16.0/lib/perl/coding_standards.md000066400000000000000000000002521420101504100204210ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md). Additional perl coding standards can be found in [perlstyle](http://perldoc.perl.org/perlstyle.html). thrift-0.16.0/lib/perl/lib/000077500000000000000000000000001420101504100153405ustar00rootroot00000000000000thrift-0.16.0/lib/perl/lib/Thrift.pm000066400000000000000000000021701420101504100171360ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; # # Versioning # # Every perl module for Thrift will have the same version # declaration. For a production build, change it below to # something like "v0.11.0" and all of the packages in all # of the files will pick it up from here. # package Thrift; use version 0.77; our $VERSION = version->declare("v0.16.0"); 1; thrift-0.16.0/lib/perl/lib/Thrift/000077500000000000000000000000001420101504100166005ustar00rootroot00000000000000thrift-0.16.0/lib/perl/lib/Thrift/BinaryProtocol.pm000066400000000000000000000211761420101504100221130ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Bit::Vector; use Encode; use Thrift; use Thrift::Exception; use Thrift::MessageType; use Thrift::Protocol; use Thrift::Type; use utf8; # # Binary implementation of the Thrift protocol. # package Thrift::BinaryProtocol; use base('Thrift::Protocol'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use constant VERSION_MASK => 0xffff0000; use constant VERSION_1 => 0x80010000; use constant IS_BIG_ENDIAN => unpack('h*', pack('s', 1)) =~ m/01/; sub new { my $classname = shift; my $trans = shift; my $self = $classname->SUPER::new($trans); return bless($self,$classname); } sub writeMessageBegin { my $self = shift; my ($name, $type, $seqid) = @_; return $self->writeI32(VERSION_1 | $type) + $self->writeString($name) + $self->writeI32($seqid); } sub writeMessageEnd { my $self = shift; return 0; } sub writeStructBegin { my $self = shift; my $name = shift; return 0; } sub writeStructEnd { my $self = shift; return 0; } sub writeFieldBegin { my $self = shift; my ($fieldName, $fieldType, $fieldId) = @_; return $self->writeByte($fieldType) + $self->writeI16($fieldId); } sub writeFieldEnd { my $self = shift; return 0; } sub writeFieldStop { my $self = shift; return $self->writeByte(Thrift::TType::STOP); } sub writeMapBegin { my $self = shift; my ($keyType, $valType, $size) = @_; return $self->writeByte($keyType) + $self->writeByte($valType) + $self->writeI32($size); } sub writeMapEnd { my $self = shift; return 0; } sub writeListBegin { my $self = shift; my ($elemType, $size) = @_; return $self->writeByte($elemType) + $self->writeI32($size); } sub writeListEnd { my $self = shift; return 0; } sub writeSetBegin { my $self = shift; my ($elemType, $size) = @_; return $self->writeByte($elemType) + $self->writeI32($size); } sub writeSetEnd { my $self = shift; return 0; } sub writeBool { my $self = shift; my $value = shift; my $data = pack('c', $value ? 1 : 0); $self->{trans}->write($data, 1); return 1; } sub writeByte { my $self = shift; my $value= shift; my $data = pack('c', $value); $self->{trans}->write($data, 1); return 1; } sub writeI16 { my $self = shift; my $value= shift; my $data = pack('n', $value); $self->{trans}->write($data, 2); return 2; } sub writeI32 { my $self = shift; my $value= shift; my $data = pack('N', $value); $self->{trans}->write($data, 4); return 4; } sub writeI64 { my $self = shift; my $value= shift; my $data; my $vec; #stop annoying error $vec = Bit::Vector->new_Dec(64, $value); $data = pack 'NN', $vec->Chunk_Read(32, 32), $vec->Chunk_Read(32, 0); $self->{trans}->write($data, 8); return 8; } sub writeDouble { my $self = shift; my $value= shift; my $data = pack('d', $value); if (IS_BIG_ENDIAN) { $self->{trans}->write($data, 8); } else { $self->{trans}->write(scalar reverse($data), 8); } return 8; } sub writeString{ my $self = shift; my $value= shift; if( utf8::is_utf8($value) ){ $value = Encode::encode_utf8($value); } my $len = length($value); my $result = $self->writeI32($len); if ($len) { $self->{trans}->write($value,$len); } return $result + $len; } # #All references # sub readMessageBegin { my $self = shift; my ($name, $type, $seqid) = @_; my $version = 0; my $result = $self->readI32(\$version); if (($version & VERSION_MASK) > 0) { if (($version & VERSION_MASK) != VERSION_1) { die Thrift::TProtocolException->new('Missing version identifier', Thrift::TProtocolException::BAD_VERSION); } $$type = $version & 0x000000ff; return $result + $self->readString($name) + $self->readI32($seqid); } else { # old client support code return $result + $self->readStringBody($name, $version) + # version here holds the size of the string $self->readByte($type) + $self->readI32($seqid); } } sub readMessageEnd { my $self = shift; return 0; } sub readStructBegin { my $self = shift; my $name = shift; $$name = ''; return 0; } sub readStructEnd { my $self = shift; return 0; } sub readFieldBegin { my $self = shift; my ($name, $fieldType, $fieldId) = @_; my $result = $self->readByte($fieldType); if ($$fieldType == Thrift::TType::STOP) { $$fieldId = 0; return $result; } $result += $self->readI16($fieldId); return $result; } sub readFieldEnd() { my $self = shift; return 0; } sub readMapBegin { my $self = shift; my ($keyType, $valType, $size) = @_; return $self->readByte($keyType) + $self->readByte($valType) + $self->readI32($size); } sub readMapEnd() { my $self = shift; return 0; } sub readListBegin { my $self = shift; my ($elemType, $size) = @_; return $self->readByte($elemType) + $self->readI32($size); } sub readListEnd { my $self = shift; return 0; } sub readSetBegin { my $self = shift; my ($elemType, $size) = @_; return $self->readByte($elemType) + $self->readI32($size); } sub readSetEnd { my $self = shift; return 0; } sub readBool { my $self = shift; my $value = shift; my $data = $self->{trans}->readAll(1); my @arr = unpack('c', $data); $$value = $arr[0] == 1; return 1; } sub readByte { my $self = shift; my $value = shift; my $data = $self->{trans}->readAll(1); my @arr = unpack('c', $data); $$value = $arr[0]; return 1; } sub readI16 { my $self = shift; my $value = shift; my $data = $self->{trans}->readAll(2); my @arr = unpack('n', $data); $$value = $arr[0]; if ($$value > 0x7fff) { $$value = 0 - (($$value - 1) ^ 0xffff); } return 2; } sub readI32 { my $self = shift; my $value= shift; my $data = $self->{trans}->readAll(4); my @arr = unpack('N', $data); $$value = $arr[0]; if ($$value > 0x7fffffff) { $$value = 0 - (($$value - 1) ^ 0xffffffff); } return 4; } sub readI64 { my $self = shift; my $value = shift; my $data = $self->{trans}->readAll(8); my ($hi,$lo)=unpack('NN',$data); my $vec = Bit::Vector->new(64); $vec->Chunk_Store(32,32,$hi); $vec->Chunk_Store(32,0,$lo); $$value = $vec->to_Dec(); return 8; } sub readDouble { my $self = shift; my $value = shift; my $data; if (IS_BIG_ENDIAN) { $data = $self->{trans}->readAll(8); } else { $data = scalar reverse($self->{trans}->readAll(8)); } my @arr = unpack('d', $data); $$value = $arr[0]; return 8; } sub readString { my $self = shift; my $value = shift; my $len; my $result = $self->readI32(\$len); if ($len) { $$value = $self->{trans}->readAll($len); } else { $$value = ''; } return $result + $len; } sub readStringBody { my $self = shift; my $value = shift; my $len = shift; if ($len) { $$value = $self->{trans}->readAll($len); } else { $$value = ''; } return $len; } # # Binary Protocol Factory # package Thrift::BinaryProtocolFactory; use base('Thrift::TProtocolFactory'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = $classname->SUPER::new(); return bless($self,$classname); } sub getProtocol{ my $self = shift; my $trans = shift; return Thrift::BinaryProtocol->new($trans); } 1; thrift-0.16.0/lib/perl/lib/Thrift/BufferedTransport.pm000066400000000000000000000054261420101504100226040ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Exception; use Thrift::Transport; package Thrift::BufferedTransport; use base('Thrift::Transport'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $transport = shift; my $rBufSize = shift || 512; my $wBufSize = shift || 512; my $self = { transport => $transport, rBufSize => $rBufSize, wBufSize => $wBufSize, wBuf => '', rBuf => '', }; return bless($self,$classname); } sub isOpen { my $self = shift; return $self->{transport}->isOpen(); } sub open { my $self = shift; $self->{transport}->open(); } sub close() { my $self = shift; $self->{transport}->close(); } sub readAll { my $self = shift; my $len = shift; return $self->{transport}->readAll($len); } sub read { my $self = shift; my $len = shift; my $ret; # Methinks Perl is already buffering these for us return $self->{transport}->read($len); } sub write { my $self = shift; my $buf = shift; $self->{wBuf} .= $buf; if (length($self->{wBuf}) >= $self->{wBufSize}) { $self->{transport}->write($self->{wBuf}); $self->{wBuf} = ''; } } sub flush { my $self = shift; if (length($self->{wBuf}) > 0) { $self->{transport}->write($self->{wBuf}); $self->{wBuf} = ''; } $self->{transport}->flush(); } # # BufferedTransport factory creates buffered transport objects from transports # package Thrift::BufferedTransportFactory; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = {}; return bless($self,$classname); } # # Build a buffered transport from the base transport # # @return Thrift::BufferedTransport transport # sub getTransport { my $self = shift; my $trans = shift; my $buffered = Thrift::BufferedTransport->new($trans); return $buffered; } 1; thrift-0.16.0/lib/perl/lib/Thrift/Exception.pm000066400000000000000000000076051420101504100211040ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Type; package Thrift::TException; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use overload '""' => sub { return sprintf '%s error: %s (code %s)', ref( $_[0] ), ( $_[0]->{message} || 'empty message' ), ( defined $_[0]->{code} ? $_[0]->{code} : 'undefined' ); }; sub new { my $classname = shift; my $self = {message => shift, code => shift || 0}; return bless($self,$classname); } package Thrift::TApplicationException; use parent -norequire, 'Thrift::TException'; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use constant UNKNOWN => 0; use constant UNKNOWN_METHOD => 1; use constant INVALID_MESSAGE_TYPE => 2; use constant WRONG_METHOD_NAME => 3; use constant BAD_SEQUENCE_ID => 4; use constant MISSING_RESULT => 5; use constant INTERNAL_ERROR => 6; use constant PROTOCOL_ERROR => 7; use constant INVALID_TRANSFORM => 8; use constant INVALID_PROTOCOL => 9; use constant UNSUPPORTED_CLIENT_TYPE => 10; sub new { my $classname = shift; my $self = $classname->SUPER::new(@_); return bless($self,$classname); } sub read { my $self = shift; my $input = shift; my $xfer = 0; my $fname = undef; my $ftype = 0; my $fid = 0; $xfer += $input->readStructBegin(\$fname); while (1) { $xfer += $input->readFieldBegin(\$fname, \$ftype, \$fid); if ($ftype == Thrift::TType::STOP) { last; next; } SWITCH: for($fid) { /1/ && do{ if ($ftype == Thrift::TType::STRING) { $xfer += $input->readString(\$self->{message}); } else { $xfer += $input->skip($ftype); } last; }; /2/ && do{ if ($ftype == Thrift::TType::I32) { $xfer += $input->readI32(\$self->{code}); } else { $xfer += $input->skip($ftype); } last; }; $xfer += $input->skip($ftype); } $xfer += $input->readFieldEnd(); } $xfer += $input->readStructEnd(); return $xfer; } sub write { my $self = shift; my $output = shift; my $xfer = 0; $xfer += $output->writeStructBegin('TApplicationException'); if ($self->getMessage()) { $xfer += $output->writeFieldBegin('message', Thrift::TType::STRING, 1); $xfer += $output->writeString($self->getMessage()); $xfer += $output->writeFieldEnd(); } if ($self->getCode()) { $xfer += $output->writeFieldBegin('type', Thrift::TType::I32, 2); $xfer += $output->writeI32($self->getCode()); $xfer += $output->writeFieldEnd(); } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; } sub getMessage { my $self = shift; return $self->{message}; } sub getCode { my $self = shift; return $self->{code}; } 1; thrift-0.16.0/lib/perl/lib/Thrift/FramedTransport.pm000066400000000000000000000076701420101504100222630ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Transport; # # Framed transport. Writes and reads data in chunks that are stamped with # their length. # # @package thrift.transport # package Thrift::FramedTransport; use base('Thrift::Transport'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $transport = shift; my $read = shift || 1; my $write = shift || 1; my $self = { transport => $transport, read => $read, write => $write, wBuf => '', rBuf => '', }; return bless($self,$classname); } sub isOpen { my $self = shift; return $self->{transport}->isOpen(); } sub open { my $self = shift; $self->{transport}->open(); } sub close { my $self = shift; if (defined $self->{transport}) { $self->{transport}->close(); } } # # Reads from the buffer. When more data is required reads another entire # chunk and serves future reads out of that. # # @param int $len How much data # sub read { my $self = shift; my $len = shift; if (!$self->{read}) { return $self->{transport}->read($len); } if (length($self->{rBuf}) == 0) { $self->_readFrame(); } # Just return full buff if ($len > length($self->{rBuf})) { my $out = $self->{rBuf}; $self->{rBuf} = ''; return $out; } # Return substr my $out = substr($self->{rBuf}, 0, $len); $self->{rBuf} = substr($self->{rBuf}, $len); return $out; } # # Reads a chunk of data into the internal read buffer. # (private) sub _readFrame { my $self = shift; my $buf = $self->{transport}->readAll(4); my @val = unpack('N', $buf); my $sz = $val[0]; $self->{rBuf} = $self->{transport}->readAll($sz); } # # Writes some data to the pending output buffer. # # @param string $buf The data # @param int $len Limit of bytes to write # sub write { my $self = shift; my $buf = shift; my $len = shift; unless($self->{write}) { return $self->{transport}->write($buf, $len); } if ( defined $len && $len < length($buf)) { $buf = substr($buf, 0, $len); } $self->{wBuf} .= $buf; } # # Writes the output buffer to the stream in the format of a 4-byte length # followed by the actual data. # sub flush { my $self = shift; unless ($self->{write}) { return $self->{transport}->flush(); } my $out = pack('N', length($self->{wBuf})); $out .= $self->{wBuf}; $self->{transport}->write($out); $self->{transport}->flush(); $self->{wBuf} = ''; } # # FramedTransport factory creates framed transport objects from transports # package Thrift::FramedTransportFactory; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = {}; return bless($self, $classname); } # # Build a framed transport from the base transport # # @return Thrift::FramedTransport transport # sub getTransport { my $self = shift; my $trans = shift; my $buffered = Thrift::FramedTransport->new($trans); return $buffered; } 1; thrift-0.16.0/lib/perl/lib/Thrift/HttpClient.pm000066400000000000000000000106051420101504100212160ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use HTTP::Request; use IO::String; use LWP::UserAgent; use Thrift; use Thrift::Exception; use Thrift::Transport; package Thrift::HttpClient; use base('Thrift::Transport'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $url = shift || 'http://localhost:9090'; my $out = IO::String->new; binmode($out); my $self = { url => $url, out => $out, timeout => 100, handle => undef, headers => {}, }; return bless($self,$classname); } sub setTimeout { my $self = shift; my $timeout = shift; $self->{timeout} = $timeout; } sub setRecvTimeout { warn 'setRecvTimeout is deprecated - use setTimeout instead'; # note: recvTimeout was never used so we do not need to do anything here } sub setSendTimeout { my $self = shift; my $timeout = shift; warn 'setSendTimeout is deprecated - use setTimeout instead'; $self->setTimeout($timeout); } sub setHeader { my $self = shift; my ($name, $value) = @_; $self->{headers}->{$name} = $value; } # # Tests whether this is open # # @return bool true if the socket is open # sub isOpen { return 1; } sub open {} # # Cleans up the buffer. # sub close { my $self = shift; if (defined($self->{io})) { close($self->{io}); $self->{io} = undef; } } # # Guarantees that the full amount of data is read. # # @return string The data, of exact length # @throws TTransportException if cannot read data # sub readAll { my $self = shift; my $len = shift; my $buf = $self->read($len); if (!defined($buf)) { die Thrift::TTransportException->new("TSocket: Could not read $len bytes from input buffer", Thrift::TTransportException::END_OF_FILE); } return $buf; } # # Read and return string # sub read { my $self = shift; my $len = shift; my $buf; my $in = $self->{in}; if (!defined($in)) { die Thrift::TTransportException->new('Response buffer is empty, no request.', Thrift::TTransportException::END_OF_FILE); } eval { my $ret = sysread($in, $buf, $len); if (! defined($ret)) { die Thrift::TTransportException->new('No more data available.', Thrift::TTransportException::TIMED_OUT); } }; if($@){ die Thrift::TTransportException->new("$@", Thrift::TTransportException::UNKNOWN); } return $buf; } # # Write string # sub write { my $self = shift; my $buf = shift; $self->{out}->print($buf); } # # Flush output (do the actual HTTP/HTTPS request) # sub flush { my $self = shift; my $ua = LWP::UserAgent->new( 'timeout' => ($self->{timeout} / 1000), 'agent' => 'Perl/THttpClient' ); $ua->default_header('Accept' => 'application/x-thrift'); $ua->default_header('Content-Type' => 'application/x-thrift'); $ua->cookie_jar({}); # hash to remember cookies between redirects my $out = $self->{out}; $out->setpos(0); # rewind my $buf = join('', <$out>); my $request = HTTP::Request->new(POST => $self->{url}, ($self->{headers} || undef), $buf); my $response = $ua->request($request); my $content_ref = $response->content_ref; my $in = IO::String->new($content_ref); binmode($in); $self->{in} = $in; $in->setpos(0); # rewind # reset write buffer $out = IO::String->new; binmode($out); $self->{out} = $out; } 1; thrift-0.16.0/lib/perl/lib/Thrift/MemoryBuffer.pm000066400000000000000000000052551420101504100215470ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Transport; package Thrift::MemoryBuffer; use base('Thrift::Transport'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $bufferSize= shift || 1024; my $self = { buffer => '', bufferSize => $bufferSize, wPos => 0, rPos => 0, }; return bless($self,$classname); } sub isOpen { return 1; } sub open { } sub close { } sub peek { my $self = shift; return($self->{rPos} < $self->{wPos}); } sub getBuffer { my $self = shift; return $self->{buffer}; } sub resetBuffer { my $self = shift; my $new_buffer = shift || ''; $self->{buffer} = $new_buffer; $self->{bufferSize} = length($new_buffer); $self->{wPos} = length($new_buffer); $self->{rPos} = 0; } sub available { my $self = shift; return ($self->{wPos} - $self->{rPos}); } sub read { my $self = shift; my $len = shift; my $ret; my $avail = ($self->{wPos} - $self->{rPos}); return '' if $avail == 0; #how much to give my $give = $len; $give = $avail if $avail < $len; $ret = substr($self->{buffer},$self->{rPos},$give); $self->{rPos} += $give; return $ret; } sub readAll { my $self = shift; my $len = shift; my $avail = ($self->{wPos} - $self->{rPos}); if ($avail < $len) { die Thrift::TTransportException->new("Attempt to readAll($len) found only $avail available", Thrift::TTransportException::END_OF_FILE); } my $data = ''; my $got = 0; while (($got = length($data)) < $len) { $data .= $self->read($len - $got); } return $data; } sub write { my $self = shift; my $buf = shift; $self->{buffer} .= $buf; $self->{wPos} += length($buf); } sub flush { } 1; thrift-0.16.0/lib/perl/lib/Thrift/MessageType.pm000066400000000000000000000021001420101504100213550ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; # # Message types for RPC # package Thrift::TMessageType; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use constant CALL => 1; use constant REPLY => 2; use constant EXCEPTION => 3; use constant ONEWAY => 4; 1; thrift-0.16.0/lib/perl/lib/Thrift/MultiplexedProcessor.pm000066400000000000000000000074331420101504100233410ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::MessageType; use Thrift::MultiplexedProtocol; use Thrift::Protocol; use Thrift::ProtocolDecorator; package Thrift::StoredMessageProtocol; use base qw(Thrift::ProtocolDecorator); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $protocol = shift; my $fname = shift; my $mtype = shift; my $rseqid = shift; my $self = $classname->SUPER::new($protocol); $self->{fname} = $fname; $self->{mtype} = $mtype; $self->{rseqid} = $rseqid; return bless($self,$classname); } sub readMessageBegin { my $self = shift; my $name = shift; my $type = shift; my $seqid = shift; $$name = $self->{fname}; $$type = $self->{mtype}; $$seqid = $self->{rseqid}; } package Thrift::MultiplexedProcessor; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = {}; $self->{serviceProcessorMap} = {}; $self->{defaultProcessor} = undef; return bless($self,$classname); } sub defaultProcessor { my $self = shift; my $processor = shift; $self->{defaultProcessor} = $processor; } sub registerProcessor { my $self = shift; my $serviceName = shift; my $processor = shift; $self->{serviceProcessorMap}->{$serviceName} = $processor; } sub process { my $self = shift; my $input = shift; my $output = shift; # # Use the actual underlying protocol (e.g. BinaryProtocol) to read the # message header. This pulls the message "off the wire", which we'll # deal with at the end of this method. # my ($fname, $mtype, $rseqid); $input->readMessageBegin(\$fname, \$mtype, \$rseqid); if ($mtype ne Thrift::TMessageType::CALL && $mtype ne Thrift::TMessageType::ONEWAY) { die Thrift::TException->new('This should not have happened!?'); } # Extract the service name and the new Message name. if (index($fname, Thrift::MultiplexedProtocol::SEPARATOR) == -1) { if (defined $self->{defaultProcessor}) { return $self->{defaultProcessor}->process( Thrift::StoredMessageProtocol->new($input, $fname, $mtype, $rseqid), $output ); } else { die Thrift::TException->new("Service name not found in message name: {$fname} and no default processor defined. Did you " . 'forget to use a MultiplexProtocol in your client?'); } } (my $serviceName, my $messageName) = split(':', $fname, 2); if (!exists($self->{serviceProcessorMap}->{$serviceName})) { die Thrift::TException->new("Service name not found: {$serviceName}. Did you forget " . 'to call registerProcessor()?'); } # Dispatch processing to the stored processor my $processor = $self->{serviceProcessorMap}->{$serviceName}; return $processor->process( Thrift::StoredMessageProtocol->new($input, $messageName, $mtype, $rseqid), $output ); } 1; thrift-0.16.0/lib/perl/lib/Thrift/MultiplexedProtocol.pm000066400000000000000000000037131420101504100231600ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::MessageType; use Thrift::Protocol; use Thrift::ProtocolDecorator; package Thrift::MultiplexedProtocol; use base qw(Thrift::ProtocolDecorator); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use constant SEPARATOR => ':'; sub new { my $classname = shift; my $protocol = shift; my $serviceName = shift; my $self = $classname->SUPER::new($protocol); $self->{serviceName} = $serviceName; return bless($self,$classname); } # # Writes the message header. # Prepends the service name to the function name, separated by MultiplexedProtocol::SEPARATOR. # # @param string $name Function name. # @param int $type Message type. # @param int $seqid The sequence id of this message. # sub writeMessageBegin { my $self = shift; my ($name, $type, $seqid) = @_; if ($type == Thrift::TMessageType::CALL || $type == Thrift::TMessageType::ONEWAY) { my $nameWithService = $self->{serviceName}.SEPARATOR.$name; $self->SUPER::writeMessageBegin($nameWithService, $type, $seqid); } else { $self->SUPER::writeMessageBegin($name, $type, $seqid); } } 1; thrift-0.16.0/lib/perl/lib/Thrift/Protocol.pm000066400000000000000000000250021420101504100207360ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Exception; use Thrift::Type; # # Protocol exceptions # package Thrift::TProtocolException; use base('Thrift::TException'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use constant UNKNOWN => 0; use constant INVALID_DATA => 1; use constant NEGATIVE_SIZE => 2; use constant SIZE_LIMIT => 3; use constant BAD_VERSION => 4; use constant NOT_IMPLEMENTED => 5; use constant DEPTH_LIMIT => 6; sub new { my $classname = shift; my $self = $classname->SUPER::new(); return bless($self,$classname); } # # Protocol base class module. # package Thrift::Protocol; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = {}; my $trans = shift; $self->{trans}= $trans; return bless($self,$classname); } sub getTransport { my $self = shift; return $self->{trans}; } # # Writes the message header # # @param string $name Function name # @param int $type message type TMessageType::CALL or TMessageType::REPLY # @param int $seqid The sequence id of this message # sub writeMessageBegin { my ($name, $type, $seqid); die 'abstract'; } # # Close the message # sub writeMessageEnd { die 'abstract'; } # # Writes a struct header. # # @param string $name Struct name # @throws TProtocolException on write error # @return int How many bytes written # sub writeStructBegin { my ($name); die 'abstract'; } # # Close a struct. # # @throws TProtocolException on write error # @return int How many bytes written # sub writeStructEnd { die 'abstract'; } # # Starts a field. # # @param string $name Field name # @param int $type Field type # @param int $fid Field id # @throws TProtocolException on write error # @return int How many bytes written # sub writeFieldBegin { my ($fieldName, $fieldType, $fieldId); die 'abstract'; } sub writeFieldEnd { die 'abstract'; } sub writeFieldStop { die 'abstract'; } sub writeMapBegin { my ($keyType, $valType, $size); die 'abstract'; } sub writeMapEnd { die 'abstract'; } sub writeListBegin { my ($elemType, $size); die 'abstract'; } sub writeListEnd { die 'abstract'; } sub writeSetBegin { my ($elemType, $size); die 'abstract'; } sub writeSetEnd { die 'abstract'; } sub writeBool { my ($bool); die 'abstract'; } sub writeByte { my ($byte); die 'abstract'; } sub writeI16 { my ($i16); die 'abstract'; } sub writeI32 { my ($i32); die 'abstract'; } sub writeI64 { my ($i64); die 'abstract'; } sub writeDouble { my ($dub); die 'abstract'; } sub writeString { my ($str); die 'abstract'; } # # Reads the message header # # @param string $name Function name # @param int $type message type TMessageType::CALL or TMessageType::REPLY # @parem int $seqid The sequence id of this message # sub readMessageBegin { my ($name, $type, $seqid); die 'abstract'; } # # Read the close of message # sub readMessageEnd { die 'abstract'; } sub readStructBegin { my($name); die 'abstract'; } sub readStructEnd { die 'abstract'; } sub readFieldBegin { my ($name, $fieldType, $fieldId); die 'abstract'; } sub readFieldEnd { die 'abstract'; } sub readMapBegin { my ($keyType, $valType, $size); die 'abstract'; } sub readMapEnd { die 'abstract'; } sub readListBegin { my ($elemType, $size); die 'abstract'; } sub readListEnd { die 'abstract'; } sub readSetBegin { my ($elemType, $size); die 'abstract'; } sub readSetEnd { die 'abstract'; } sub readBool { my ($bool); die 'abstract'; } sub readByte { my ($byte); die 'abstract'; } sub readI16 { my ($i16); die 'abstract'; } sub readI32 { my ($i32); die 'abstract'; } sub readI64 { my ($i64); die 'abstract'; } sub readDouble { my ($dub); die 'abstract'; } sub readString { my ($str); die 'abstract'; } # # The skip function is a utility to parse over unrecognized data without # causing corruption. # # @param TType $type What type is it # sub skip { my $self = shift; my $type = shift; my $ref; my $result; my $i; if($type == Thrift::TType::BOOL) { return $self->readBool(\$ref); } elsif($type == Thrift::TType::BYTE){ return $self->readByte(\$ref); } elsif($type == Thrift::TType::I16){ return $self->readI16(\$ref); } elsif($type == Thrift::TType::I32){ return $self->readI32(\$ref); } elsif($type == Thrift::TType::I64){ return $self->readI64(\$ref); } elsif($type == Thrift::TType::DOUBLE){ return $self->readDouble(\$ref); } elsif($type == Thrift::TType::STRING) { return $self->readString(\$ref); } elsif($type == Thrift::TType::STRUCT) { $result = $self->readStructBegin(\$ref); while (1) { my ($ftype,$fid); $result += $self->readFieldBegin(\$ref, \$ftype, \$fid); if ($ftype == Thrift::TType::STOP) { last; } $result += $self->skip($ftype); $result += $self->readFieldEnd(); } $result += $self->readStructEnd(); return $result; } elsif($type == Thrift::TType::MAP) { my($keyType,$valType,$size); $result = $self->readMapBegin(\$keyType, \$valType, \$size); for ($i = 0; $i < $size; $i++) { $result += $self->skip($keyType); $result += $self->skip($valType); } $result += $self->readMapEnd(); return $result; } elsif($type == Thrift::TType::SET) { my ($elemType,$size); $result = $self->readSetBegin(\$elemType, \$size); for ($i = 0; $i < $size; $i++) { $result += $self->skip($elemType); } $result += $self->readSetEnd(); return $result; } elsif($type == Thrift::TType::LIST) { my ($elemType,$size); $result = $self->readListBegin(\$elemType, \$size); for ($i = 0; $i < $size; $i++) { $result += $self->skip($elemType); } $result += $self->readListEnd(); return $result; } die Thrift::TProtocolException->new("Type $type not recognized --- corrupt data?", Thrift::TProtocolException::INVALID_DATA); } # # Utility for skipping binary data # # @param TTransport $itrans TTransport object # @param int $type Field type # sub skipBinary { my $self = shift; my $itrans = shift; my $type = shift; if($type == Thrift::TType::BOOL) { return $itrans->readAll(1); } elsif($type == Thrift::TType::BYTE) { return $itrans->readAll(1); } elsif($type == Thrift::TType::I16) { return $itrans->readAll(2); } elsif($type == Thrift::TType::I32) { return $itrans->readAll(4); } elsif($type == Thrift::TType::I64) { return $itrans->readAll(8); } elsif($type == Thrift::TType::DOUBLE) { return $itrans->readAll(8); } elsif( $type == Thrift::TType::STRING ) { my @len = unpack('N', $itrans->readAll(4)); my $len = $len[0]; if ($len > 0x7fffffff) { $len = 0 - (($len - 1) ^ 0xffffffff); } return 4 + $itrans->readAll($len); } elsif( $type == Thrift::TType::STRUCT ) { my $result = 0; while (1) { my $ftype = 0; my $fid = 0; my $data = $itrans->readAll(1); my @arr = unpack('c', $data); $ftype = $arr[0]; if ($ftype == Thrift::TType::STOP) { last; } # I16 field id $result += $itrans->readAll(2); $result += $self->skipBinary($itrans, $ftype); } return $result; } elsif($type == Thrift::TType::MAP) { # Ktype my $data = $itrans->readAll(1); my @arr = unpack('c', $data); my $ktype = $arr[0]; # Vtype $data = $itrans->readAll(1); @arr = unpack('c', $data); my $vtype = $arr[0]; # Size $data = $itrans->readAll(4); @arr = unpack('N', $data); my $size = $arr[0]; if ($size > 0x7fffffff) { $size = 0 - (($size - 1) ^ 0xffffffff); } my $result = 6; for (my $i = 0; $i < $size; $i++) { $result += $self->skipBinary($itrans, $ktype); $result += $self->skipBinary($itrans, $vtype); } return $result; } elsif($type == Thrift::TType::SET || $type == Thrift::TType::LIST) { # Vtype my $data = $itrans->readAll(1); my @arr = unpack('c', $data); my $vtype = $arr[0]; # Size $data = $itrans->readAll(4); @arr = unpack('N', $data); my $size = $arr[0]; if ($size > 0x7fffffff) { $size = 0 - (($size - 1) ^ 0xffffffff); } my $result = 5; for (my $i = 0; $i < $size; $i++) { $result += $self->skipBinary($itrans, $vtype); } return $result; } die Thrift::TProtocolException->new("Type $type not recognized --- corrupt data?", Thrift::TProtocolException::INVALID_DATA); } # # Protocol factory creates protocol objects from transports # package Thrift::TProtocolFactory; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = {}; return bless($self,$classname); } # # Build a protocol from the base transport # # @return TProtcol protocol # sub getProtocol { my ($trans); die 'interface'; } 1; thrift-0.16.0/lib/perl/lib/Thrift/ProtocolDecorator.pm000066400000000000000000000154421420101504100226100ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Protocol; package Thrift::ProtocolDecorator; use base qw(Thrift::Protocol); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $protocol = shift; my $self = $classname->SUPER::new($protocol->getTransport()); $self->{concreteProtocol} = $protocol; return bless($self,$classname); } # # Writes the message header # # @param string $name Function name # @param int $type message type TMessageType::CALL or TMessageType::REPLY # @param int $seqid The sequence id of this message # sub writeMessageBegin { my $self = shift; my ($name, $type, $seqid) = @_; return $self->{concreteProtocol}->writeMessageBegin($name, $type, $seqid); } # # Close the message # sub writeMessageEnd { my $self = shift; return $self->{concreteProtocol}->writeMessageEnd(); } # # Writes a struct header. # # @param string $name Struct name # @throws TException on write error # @return int How many bytes written # sub writeStructBegin { my $self = shift; my ($name) = @_; return $self->{concreteProtocol}->writeStructBegin($name); } # # Close a struct. # # @throws TException on write error # @return int How many bytes written # sub writeStructEnd { my $self = shift; return $self->{concreteProtocol}->writeStructEnd(); } # # Starts a field. # # @param string $name Field name # @param int $type Field type # @param int $fid Field id # @throws TException on write error # @return int How many bytes written # sub writeFieldBegin { my $self = shift; my ($fieldName, $fieldType, $fieldId) = @_; return $self->{concreteProtocol}->writeFieldBegin($fieldName, $fieldType, $fieldId); } sub writeFieldEnd { my $self = shift; return $self->{concreteProtocol}->writeFieldEnd(); } sub writeFieldStop { my $self = shift; return $self->{concreteProtocol}->writeFieldStop(); } sub writeMapBegin { my $self = shift; my ($keyType, $valType, $size) = @_; return $self->{concreteProtocol}->writeMapBegin($keyType, $valType, $size); } sub writeMapEnd { my $self = shift; return $self->{concreteProtocol}->writeMapEnd(); } sub writeListBegin { my $self = shift; my ($elemType, $size) = @_; return $self->{concreteProtocol}->writeListBegin($elemType, $size); } sub writeListEnd { my $self = shift; return $self->{concreteProtocol}->writeListEnd(); } sub writeSetBegin { my $self = shift; my ($elemType, $size) = @_; return $self->{concreteProtocol}->writeSetBegin($elemType, $size); } sub writeSetEnd { my $self = shift; return $self->{concreteProtocol}->writeListEnd(); } sub writeBool { my $self = shift; my $bool = shift; return $self->{concreteProtocol}->writeBool($bool); } sub writeByte { my $self = shift; my $byte = shift; return $self->{concreteProtocol}->writeByte($byte); } sub writeI16 { my $self = shift; my $i16 = shift; return $self->{concreteProtocol}->writeI16($i16); } sub writeI32 { my $self = shift; my ($i32) = @_; return $self->{concreteProtocol}->writeI32($i32); } sub writeI64 { my $self = shift; my $i64 = shift; return $self->{concreteProtocol}->writeI64($i64); } sub writeDouble { my $self = shift; my $dub = shift; return $self->{concreteProtocol}->writeDouble($dub); } sub writeString { my $self = shift; my $str = shift; return $self->{concreteProtocol}->writeString($str); } # # Reads the message header # # @param string $name Function name # @param int $type message type TMessageType::CALL or TMessageType::REPLY # @parem int $seqid The sequence id of this message # sub readMessageBegin { my $self = shift; my ($name, $type, $seqid) = @_; return $self->{concreteProtocol}->readMessageBegin($name, $type, $seqid); } # # Read the close of message # sub readMessageEnd { my $self = shift; return $self->{concreteProtocol}->readMessageEnd(); } sub readStructBegin { my $self = shift; my $name = shift; return $self->{concreteProtocol}->readStructBegin($name); } sub readStructEnd { my $self = shift; return $self->{concreteProtocol}->readStructEnd(); } sub readFieldBegin { my $self = shift; my ($name, $fieldType, $fieldId) = @_; return $self->{concreteProtocol}->readFieldBegin($name, $fieldType, $fieldId); } sub readFieldEnd { my $self = shift; return $self->{concreteProtocol}->readFieldEnd(); } sub readMapBegin { my $self = shift; my ($keyType, $valType, $size) = @_; return $self->{concreteProtocol}->readMapBegin($keyType, $valType, $size); } sub readMapEnd { my $self = shift; return $self->{concreteProtocol}->readMapEnd(); } sub readListBegin { my $self = shift; my ($elemType, $size) = @_; return $self->{concreteProtocol}->readListBegin($elemType, $size); } sub readListEnd { my $self = shift; return $self->{concreteProtocol}->readListEnd(); } sub readSetBegin { my $self = shift; my ($elemType, $size) = @_; return $self->{concreteProtocol}->readSetBegin($elemType, $size); } sub readSetEnd { my $self = shift; return $self->{concreteProtocol}->readSetEnd(); } sub readBool { my $self = shift; my $bool = shift; return $self->{concreteProtocol}->readBool($bool); } sub readByte { my $self = shift; my $byte = shift; return $self->{concreteProtocol}->readByte($byte); } sub readI16 { my $self = shift; my $i16 = shift; return $self->{concreteProtocol}->readI16($i16); } sub readI32 { my $self = shift; my $i32 = shift; return $self->{concreteProtocol}->readI32($i32); } sub readI64 { my $self = shift; my $i64 = shift; return $self->{concreteProtocol}->readI64($i64); } sub readDouble { my $self = shift; my $dub = shift; return $self->{concreteProtocol}->readDouble($dub); } sub readString { my $self = shift; my $str = shift; return $self->{concreteProtocol}->readString($str); } 1; thrift-0.16.0/lib/perl/lib/Thrift/SSLServerSocket.pm000066400000000000000000000050361420101504100221430ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::SSLSocket; use Thrift::ServerSocket; use IO::Socket::SSL; package Thrift::SSLServerSocket; use base qw( Thrift::ServerSocket ); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # Constructor. # Takes a hash: # See Thrift::Socket for base class parameters. # @param[in] ca certificate authority filename - not required # @param[in] cert certificate filename; may contain key in which case key is not required # @param[in] key private key filename for the certificate if it is not inside the cert file # sub new { my $classname = shift; my $self = $classname->SUPER::new(@_); return bless($self, $classname); } sub __client { return Thrift::SSLSocket->new(); } sub __listen { my $self = shift; my $opts = {Listen => $self->{queue}, LocalAddr => $self->{host}, LocalPort => $self->{port}, Proto => 'tcp', ReuseAddr => 1}; my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE; $opts->{SSL_ca_file} = $self->{ca} if defined $self->{ca}; $opts->{SSL_cert_file} = $self->{cert} if defined $self->{cert}; $opts->{SSL_cipher_list} = $self->{ciphers} if defined $self->{ciphers}; $opts->{SSL_key_file} = $self->{key} if defined $self->{key}; $opts->{SSL_use_cert} = (defined $self->{cert}) ? 1 : 0; $opts->{SSL_verify_mode} = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE; $opts->{SSL_version} = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2'; return IO::Socket::SSL->new(%$opts); } 1; thrift-0.16.0/lib/perl/lib/Thrift/SSLSocket.pm000066400000000000000000000070511420101504100207530ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Socket; use IO::Socket::SSL; package Thrift::SSLSocket; use base qw( Thrift::Socket ); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # Construction and usage # # my $opts = {} # my $socket = Thrift::SSLSocket->new(\%opts); # # options: # # Any option from Socket.pm is valid, and then: # # ca => certificate authority file (PEM file) to authenticate the # server against; if not specified then the server is not # authenticated # cert => certificate to use as the client; if not specified then # the client does not present one but still connects using # secure protocol # ciphers => allowed cipher list # (see http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS) # key => certificate key for "cert" option # version => acceptable SSL/TLS versions - if not specified then the # default is to use SSLv23 handshake but only negotiate # at TLSv1.0 or later # sub new { my $classname = shift; my $self = $classname->SUPER::new(@_); return bless($self, $classname); } sub __open { my $self = shift; my $opts = {PeerAddr => $self->{host}, PeerPort => $self->{port}, Proto => 'tcp', Timeout => $self->{sendTimeout} / 1000}; my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE; $opts->{SSL_ca_file} = $self->{ca} if defined $self->{ca}; $opts->{SSL_cert_file} = $self->{cert} if defined $self->{cert}; $opts->{SSL_cipher_list} = $self->{ciphers} if defined $self->{ciphers}; $opts->{SSL_key_file} = $self->{key} if defined $self->{key}; $opts->{SSL_use_cert} = (defined $self->{cert}) ? 1 : 0; $opts->{SSL_verify_mode} = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE; $opts->{SSL_version} = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2'; return IO::Socket::SSL->new(%$opts); } sub __close { my $self = shift; my $sock = ($self->{handle}->handles())[0]; if ($sock) { $sock->close(SSL_no_shutdown => 1); } } sub __recv { my $self = shift; my $sock = shift; my $len = shift; my $buf = undef; if ($sock) { sysread($sock, $buf, $len); } return $buf; } sub __send { my $self = shift; my $sock = shift; my $buf = shift; return syswrite($sock, $buf); } sub __wait { my $self = shift; my $sock = ($self->{handle}->handles())[0]; if ($sock and $sock->pending() eq 0) { return $self->SUPER::__wait(); } return $sock; } 1; thrift-0.16.0/lib/perl/lib/Thrift/Server.pm000066400000000000000000000166521420101504100204160ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::BinaryProtocol; use Thrift::BufferedTransport; use Thrift::Exception; # # Server base class module # package Thrift::Server; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # 3 possible constructors: # 1. (processor, serverTransport) # Uses a BufferedTransportFactory and a BinaryProtocolFactory. # 2. (processor, serverTransport, transportFactory, protocolFactory) # Uses the same factory for input and output of each type. # 3. (processor, serverTransport, # inputTransportFactory, outputTransportFactory, # inputProtocolFactory, outputProtocolFactory) # sub new { my $classname = shift; my @args = @_; my $self; if (scalar @args == 2) { $self = _init($args[0], $args[1], Thrift::BufferedTransportFactory->new(), Thrift::BufferedTransportFactory->new(), Thrift::BinaryProtocolFactory->new(), Thrift::BinaryProtocolFactory->new()); } elsif (scalar @args == 4) { $self = _init($args[0], $args[1], $args[2], $args[2], $args[3], $args[3]); } elsif (scalar @args == 6) { $self = _init($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); } else { die Thrift::TException->new('Thrift::Server expects exactly 2, 4, or 6 args'); } return bless($self,$classname); } sub _init { my $processor = shift; my $serverTransport = shift; my $inputTransportFactory = shift; my $outputTransportFactory = shift; my $inputProtocolFactory = shift; my $outputProtocolFactory = shift; my $self = { processor => $processor, serverTransport => $serverTransport, inputTransportFactory => $inputTransportFactory, outputTransportFactory => $outputTransportFactory, inputProtocolFactory => $inputProtocolFactory, outputProtocolFactory => $outputProtocolFactory, }; } sub serve { die 'abstract'; } sub _clientBegin { my $self = shift; my $iprot = shift; my $oprot = shift; if (exists $self->{serverEventHandler} and defined $self->{serverEventHandler}) { $self->{serverEventHandler}->clientBegin($iprot, $oprot); } } sub _handleException { my $self = shift; my $e = shift; if ($e->isa('Thrift::TException') and exists $e->{message}) { my $message = $e->{message}; my $code = $e->{code}; my $out = $code . ':' . $message; $message =~ m/TTransportException/ and die $out; if ($message =~ m/Socket/) { # suppress Socket messages } else { warn $out; } } else { warn $e; } } # # SimpleServer from the Server base class that handles one connection at a time # package Thrift::SimpleServer; use parent -norequire, 'Thrift::Server'; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = $classname->SUPER::new(@_); return bless($self,$classname); } sub serve { my $self = shift; my $stop = 0; $self->{serverTransport}->listen(); while (!$stop) { my $client = $self->{serverTransport}->accept(); if (defined $client) { my $itrans = $self->{inputTransportFactory}->getTransport($client); my $otrans = $self->{outputTransportFactory}->getTransport($client); my $iprot = $self->{inputProtocolFactory}->getProtocol($itrans); my $oprot = $self->{outputProtocolFactory}->getProtocol($otrans); eval { $self->_clientBegin($iprot, $oprot); while (1) { $self->{processor}->process($iprot, $oprot); } }; if($@) { $self->_handleException($@); } $itrans->close(); $otrans->close(); } else { $stop = 1; } } } # # ForkingServer that forks a new process for each request # package Thrift::ForkingServer; use parent -norequire, 'Thrift::Server'; use POSIX ':sys_wait_h'; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my @args = @_; my $self = $classname->SUPER::new(@args); return bless($self,$classname); } sub serve { my $self = shift; # THRIFT-3848: without ignoring SIGCHLD, perl ForkingServer goes into a tight loop $SIG{CHLD} = 'IGNORE'; $self->{serverTransport}->listen(); while (1) { my $client = $self->{serverTransport}->accept(); $self->_client($client); } } sub _client { my $self = shift; my $client = shift; eval { my $itrans = $self->{inputTransportFactory}->getTransport($client); my $otrans = $self->{outputTransportFactory}->getTransport($client); my $iprot = $self->{inputProtocolFactory}->getProtocol($itrans); my $oprot = $self->{outputProtocolFactory}->getProtocol($otrans); $self->_clientBegin($iprot, $oprot); my $pid = fork(); if ($pid) { $self->_parent($pid, $itrans, $otrans); } else { $self->_child($itrans, $otrans, $iprot, $oprot); } }; if($@) { $self->_handleException($@); } } sub _parent { my $self = shift; my $pid = shift; my $itrans = shift; my $otrans = shift; # Parent must close socket or the connection may not get closed promptly $self->tryClose($itrans); $self->tryClose($otrans); } sub _child { my $self = shift; my $itrans = shift; my $otrans = shift; my $iprot = shift; my $oprot = shift; my $ecode = 0; eval { # THRIFT-4065 ensure child process has normal signal handling in case thrift handler uses it $SIG{CHLD} = 'DEFAULT'; while (1) { $self->{processor}->process($iprot, $oprot); } }; if($@) { $ecode = 1; $self->_handleException($@); } $self->tryClose($itrans); $self->tryClose($otrans); exit($ecode); } sub tryClose { my $self = shift; my $file = shift; eval { if (defined $file) { $file->close(); } }; if($@) { if ($@->isa('Thrift::TException') and exists $@->{message}) { my $message = $@->{message}; my $code = $@->{code}; my $out = $code . ':' . $message; warn $out; } else { warn $@; } } } 1; thrift-0.16.0/lib/perl/lib/Thrift/ServerSocket.pm000066400000000000000000000060361420101504100215620ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use IO::Socket::INET; use IO::Select; use Thrift; use Thrift::Transport; use Thrift::Socket; package Thrift::ServerSocket; use base qw( Thrift::ServerTransport ); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # Constructor. # Legacy construction takes one argument, port number. # New construction takes a hash: # @param[in] host host interface to listen on (undef = all interfaces) # @param[in] port port number to listen on (required) # @param[in] queue the listen queue size (default if not specified is 128) # @example my $serversock = Thrift::ServerSocket->new(host => undef, port => port) # sub new { my $classname = shift; my $args = shift; my $self; # Support both old-style "port number" construction and newer... if (ref($args) eq 'HASH') { $self = $args; } else { $self = { port => $args }; } if (not defined $self->{queue}) { $self->{queue} = 128; } return bless($self, $classname); } sub listen { my $self = shift; my $sock = $self->__listen() || do { my $error = ref($self) . ': Could not bind to ' . '*:' . $self->{port} . ' (' . $! . ')'; if ($self->{debug}) { $self->{debugHandler}->($error); } die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN); }; $self->{handle} = $sock; } sub accept { my $self = shift; if ( exists $self->{handle} and defined $self->{handle} ) { my $client = $self->{handle}->accept(); my $result = $self->__client(); $result->{handle} = IO::Select->new($client); return $result; } return undef; } sub close { my $self = shift; if ( exists $self->{handle} and defined $self->{handle} ) { $self->{handle}->close(); } } ### ### Overridable methods ### sub __client { return Thrift::Socket->new(); } sub __listen { my $self = shift; return IO::Socket::INET->new(LocalAddr => $self->{host}, LocalPort => $self->{port}, Proto => 'tcp', Listen => $self->{queue}, ReuseAddr => 1); } 1; thrift-0.16.0/lib/perl/lib/Thrift/Socket.pm000066400000000000000000000151671420101504100204000ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Exception; use Thrift::Transport; use IO::Socket::INET; use IO::Select; package Thrift::Socket; use base qw( Thrift::Transport ); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # Construction and usage # # my $opts = {} # my $socket = Thrift::Socket->new(\%opts); # # options: # # host => host to connect to # port => port to connect to # sendTimeout => timeout used for send and for connect # recvTimeout => timeout used for recv # sub new { my $classname = shift; my $opts = shift; # default settings: my $self = { host => 'localhost', port => 9090, recvTimeout => 10000, sendTimeout => 10000, proto => 'tcp', handle => undef }; if (defined $opts and ref $opts eq ref {}) { # argument is a hash of options so override the defaults $self->{$_} = $opts->{$_} for keys %$opts; } else { # older style constructor takes 3 arguments, none of which are required $self->{host} = $opts || 'localhost'; $self->{port} = shift || 9090; } return bless($self,$classname); } sub setSendTimeout { my $self = shift; my $timeout = shift; $self->{sendTimeout} = $timeout; } sub setRecvTimeout { my $self = shift; my $timeout = shift; $self->{recvTimeout} = $timeout; } # # Tests whether this is open # # @return bool true if the socket is open # sub isOpen { my $self = shift; if( defined $self->{handle} ){ return ($self->{handle}->handles())[0]->connected; } return 0; } # # Connects the socket. # sub open { my $self = shift; my $sock = $self->__open() || do { my $error = ref($self).': Could not connect to '.$self->{host}.':'.$self->{port}.' ('.$!.')'; die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN); }; $self->{handle} = IO::Select->new( $sock ); } # # Closes the socket. # sub close { my $self = shift; if( defined $self->{handle} ) { $self->__close(); } } # # Uses stream get contents to do the reading # # @param int $len How many bytes # @return string Binary data # sub readAll { my $self = shift; my $len = shift; return unless defined $self->{handle}; my $pre = ""; while (1) { my $sock = $self->__wait(); my $buf = $self->__recv($sock, $len); if (!defined $buf || $buf eq '') { die Thrift::TTransportException->new(ref($self).': Could not read '.$len.' bytes from '. $self->{host}.':'.$self->{port}, Thrift::TTransportException::END_OF_FILE); } elsif ((my $sz = length($buf)) < $len) { $pre .= $buf; $len -= $sz; } else { return $pre.$buf; } } } # # Read from the socket # # @param int $len How many bytes # @return string Binary data # sub read { my $self = shift; my $len = shift; return unless defined $self->{handle}; my $sock = $self->__wait(); my $buf = $self->__recv($sock, $len); if (!defined $buf || $buf eq '') { die Thrift::TTransportException->new(ref($self).': Could not read '.$len.' bytes from '. $self->{host}.':'.$self->{port}, Thrift::TTransportException::END_OF_FILE); } return $buf; } # # Write to the socket. # # @param string $buf The data to write # sub write { my $self = shift; my $buf = shift; return unless defined $self->{handle}; while (length($buf) > 0) { #check for timeout my @sockets = $self->{handle}->can_write( $self->{sendTimeout} / 1000 ); if(@sockets == 0){ die Thrift::TTransportException->new(ref($self).': timed out writing to bytes from '. $self->{host}.':'.$self->{port}, Thrift::TTransportException::TIMED_OUT); } my $sent = $self->__send($sockets[0], $buf); if (!defined $sent || $sent == 0 ) { die Thrift::TTransportException->new(ref($self).': Could not write '.length($buf).' bytes '. $self->{host}.':'.$self->{host}, Thrift::TTransportException::END_OF_FILE); } $buf = substr($buf, $sent); } } # # Flush output to the socket. # sub flush { my $self = shift; return unless defined $self->{handle}; my $ret = ($self->{handle}->handles())[0]->flush; } ### ### Overridable methods ### # # Open a connection to a server. # sub __open { my $self = shift; return IO::Socket::INET->new(PeerAddr => $self->{host}, PeerPort => $self->{port}, Proto => $self->{proto}, Timeout => $self->{sendTimeout} / 1000); } # # Close the connection # sub __close { my $self = shift; CORE::close(($self->{handle}->handles())[0]); } # # Read data # # @param[in] $sock the socket # @param[in] $len the length to read # @returns the data buffer that was read # sub __recv { my $self = shift; my $sock = shift; my $len = shift; my $buf = undef; $sock->recv($buf, $len); return $buf; } # # Send data # # @param[in] $sock the socket # @param[in] $buf the data buffer # @returns the number of bytes written # sub __send { my $self = shift; my $sock = shift; my $buf = shift; return $sock->send($buf); } # # Wait for data to be readable # # @returns a socket that can be read # sub __wait { my $self = shift; my @sockets = $self->{handle}->can_read( $self->{recvTimeout} / 1000 ); if (@sockets == 0) { die Thrift::TTransportException->new(ref($self).': timed out reading from '. $self->{host}.':'.$self->{port}, Thrift::TTransportException::TIMED_OUT); } return $sockets[0]; } 1; thrift-0.16.0/lib/perl/lib/Thrift/Transport.pm000066400000000000000000000063051420101504100211360ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Exception; # # Transport exceptions # package Thrift::TTransportException; use base('Thrift::TException'); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use constant UNKNOWN => 0; use constant NOT_OPEN => 1; use constant ALREADY_OPEN => 2; use constant TIMED_OUT => 3; use constant END_OF_FILE => 4; sub new { my $classname = shift; my $self = $classname->SUPER::new(@_); return bless($self,$classname); } package Thrift::Transport; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # Whether this transport is open. # # @return boolean true if open # sub isOpen { die 'abstract'; } # # Open the transport for reading/writing # # @throws TTransportException if cannot open # sub open { die 'abstract'; } # # Close the transport. # sub close { die 'abstract'; } # # Read some data into the array. # # @param int $len How much to read # @return string The data that has been read # @throws TTransportException if cannot read any more data # sub read { die 'abstract'; } # # Guarantees that the full amount of data is read. # # @return string The data, of exact length # @throws TTransportException if cannot read data # sub readAll { my $self = shift; my $len = shift; my $data = ''; my $got = 0; while (($got = length($data)) < $len) { $data .= $self->read($len - $got); } return $data; } # # Writes the given data out. # # @param string $buf The data to write # @throws TTransportException if writing fails # sub write { die 'abstract'; } # # Flushes any pending data out of a buffer # # @throws TTransportException if a writing error occurs # sub flush {} # # TransportFactory creates transport objects from transports # package Thrift::TransportFactory; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub new { my $classname = shift; my $self = {}; return bless($self,$classname); } # # Build a transport from the base transport # # @return Thrift::Transport transport # sub getTransport { my $self = shift; my $trans = shift; return $trans; } # # ServerTransport base class module # package Thrift::ServerTransport; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); sub listen { die 'abstract'; } sub accept { die 'abstract'; } sub close { die 'abstract'; } 1; thrift-0.16.0/lib/perl/lib/Thrift/Type.pm000066400000000000000000000026311420101504100200610ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; # # Data types that can be sent via Thrift # package Thrift::TType; use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); use constant STOP => 0; use constant VOID => 1; use constant BOOL => 2; use constant BYTE => 3; use constant I08 => 3; use constant DOUBLE => 4; use constant I16 => 6; use constant I32 => 8; use constant I64 => 10; use constant STRING => 11; use constant UTF7 => 11; use constant STRUCT => 12; use constant MAP => 13; use constant SET => 14; use constant LIST => 15; use constant UTF8 => 16; use constant UTF16 => 17; 1; thrift-0.16.0/lib/perl/lib/Thrift/UnixServerSocket.pm000066400000000000000000000045361420101504100224310ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::ServerSocket; use Thrift::UnixSocket; use IO::Socket::UNIX; package Thrift::UnixServerSocket; use base qw( Thrift::ServerSocket ); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # Constructor. # If a single argument is given that is not a hash, that is the unix domain socket path. # If a single argument is given that is a hash: # @param[in] path unix domain socket file name # @param[in] queue the listen queue size (default is not specified is supplied by ServerSocket) # @example my $serversock = Thrift::UnixServerSocket->new($path); # @example my $serversock = Thrift::UnixServerSocket->new(path => "somepath", queue => 64); # sub new { my $classname = shift; my $args = shift; my $self; if (ref($args) eq 'HASH') { $self = $classname->SUPER::new($args); } else { $self = $classname->SUPER::new(); $self->{path} = $args; } return bless($self, $classname); } sub __client { return Thrift::UnixSocket->new(); } sub __listen { my $self = shift; my $sock = IO::Socket::UNIX->new( Type => IO::Socket::SOCK_STREAM, Local => $self->{path}, Listen => $self->{queue}) || do { my $error = 'UnixServerSocket: Could not bind to ' . $self->{path} . ' (' . $! . ')'; if ($self->{debug}) { $self->{debugHandler}->($error); } die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN); }; return $sock; } 1; thrift-0.16.0/lib/perl/lib/Thrift/UnixSocket.pm000066400000000000000000000034741420101504100212420ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use 5.10.0; use strict; use warnings; use Thrift; use Thrift::Socket; use IO::Socket::UNIX; package Thrift::UnixSocket; use base qw( Thrift::Socket ); use version 0.77; our $VERSION = version->declare("$Thrift::VERSION"); # # Constructor. # Takes a unix domain socket filename. # See Thrift::Socket for base class parameters. # @param[in] path path to unix socket file # @example my $sock = Thrift::UnixSocket->new($path); # sub new { my $classname = shift; my $self = $classname->SUPER::new(); $self->{path} = shift; return bless($self, $classname); } sub __open { my $self = shift; my $sock = IO::Socket::UNIX->new( Type => IO::Socket::SOCK_STREAM, Peer => $self->{path}) || do { my $error = 'UnixSocket: Could not connect to ' . $self->{path} . ' (' . $! . ')'; if ($self->{debug}) { $self->{debugHandler}->($error); } die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN); }; return $sock; } 1; thrift-0.16.0/lib/perl/t/000077500000000000000000000000001420101504100150355ustar00rootroot00000000000000thrift-0.16.0/lib/perl/t/Makefile.am000066400000000000000000000015071420101504100170740ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # EXTRA_DIST = memory_buffer.t processor.t multiplex.t thrift-0.16.0/lib/perl/t/memory_buffer.t000066400000000000000000000031131420101504100200610ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use Test::More tests => 7; use Test::Exception; use strict; use warnings; use Data::Dumper; use Thrift::BinaryProtocol; use Thrift::MemoryBuffer; use ThriftTest::Types; my $transport = Thrift::MemoryBuffer->new(); my $protocol = Thrift::BinaryProtocol->new($transport); throws_ok { $protocol->readByte } 'Thrift::TTransportException'; my $a = ThriftTest::Xtruct->new(); $a->i32_thing(10); $a->i64_thing(30); $a->string_thing('Hello, world!'); $a->write($protocol); my $b = ThriftTest::Xtruct->new(); $b->read($protocol); is($b->i32_thing, $a->i32_thing); is($b->i64_thing, $a->i64_thing); is($b->string_thing, $a->string_thing); $b->write($protocol); my $c = ThriftTest::Xtruct->new(); $c->read($protocol); is($c->i32_thing, $a->i32_thing); is($c->i64_thing, $a->i64_thing); is($c->string_thing, $a->string_thing); thrift-0.16.0/lib/perl/t/multiplex.t000066400000000000000000000117551420101504100172560ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use Test::More tests => 6; use strict; use warnings; use Thrift::BinaryProtocol; use Thrift::FramedTransport; use Thrift::MemoryBuffer; use Thrift::MessageType; use Thrift::MultiplexedProcessor; use Thrift::Server; use Thrift::Socket; use BenchmarkService; use Aggr; use constant NAME_BENCHMARKSERVICE => 'BenchmarkService'; use constant NAME_AGGR => 'Aggr'; my $buffer = Thrift::MemoryBuffer->new(1024); my $aggr_protocol = Thrift::MultiplexedProtocol->new(Thrift::BinaryProtocol->new($buffer), NAME_AGGR); my $aggr_client = AggrClient->new($aggr_protocol); my $benchmark_protocol = Thrift::MultiplexedProtocol->new(Thrift::BinaryProtocol->new($buffer), NAME_BENCHMARKSERVICE); my $benchmark_client = BenchmarkServiceClient->new($benchmark_protocol); $buffer->open(); for(my $i = 1; $i <= 5; $i++) { $aggr_client->send_addValue($i); $aggr_client->{seqid}++; } $aggr_client->send_getValues(); for(my $i = 1; $i <= 5; $i++) { $benchmark_client->send_fibonacci($i); $benchmark_client->{seqid}++; } $benchmark_client->{seqid}--; my $client_command_binary = $buffer->getBuffer; $buffer->resetBuffer; # Process by server my $server_output_binary; { my $benchmark_handler = My::BenchmarkService->new(); my $benchmark_processor = BenchmarkServiceProcessor->new($benchmark_handler); my $aggr_handler = My::Aggr->new(); my $aggr_processor = AggrProcessor->new($aggr_handler); my $protocol_factory = Thrift::BinaryProtocolFactory->new(); my $input_buffer = Thrift::MemoryBuffer->new(); $input_buffer->write($client_command_binary); my $input_protocol = $protocol_factory->getProtocol($input_buffer); my $output_buffer = Thrift::MemoryBuffer->new(); my $output_protocol = $protocol_factory->getProtocol($output_buffer); my $processor = Thrift::MultiplexedProcessor->new(); $processor->registerProcessor(NAME_BENCHMARKSERVICE, $benchmark_processor); $processor->registerProcessor(NAME_AGGR, $aggr_processor); my $result; for(my $i = 1; $i <= 11; $i++) { $result = $processor->process($input_protocol, $output_protocol); print "process resulted in $result\n"; } $server_output_binary = $output_buffer->getBuffer(); } $buffer->write($server_output_binary); for(my $i = 1; $i <= 5; $i++) { my ($function_name, $message_type, $sequence_id); $aggr_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); if ($message_type == Thrift::TMessageType::EXCEPTION) { die; } my $aggr_result = Aggr_addValue_result->new(); $aggr_result->read($aggr_protocol); $aggr_protocol->readMessageEnd(); } my ($function_name, $message_type, $sequence_id); $aggr_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); if ($message_type == Thrift::TMessageType::EXCEPTION) { die; } my $aggr_result = Aggr_getValues_result->new(); $aggr_result->read($aggr_protocol); $aggr_protocol->readMessageEnd(); is_deeply($aggr_result->success(), [1,2,3,4,5]); foreach my $val((1,2,3,5,8)) { my ($function_name, $message_type, $sequence_id); $benchmark_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); if ($message_type == Thrift::TMessageType::EXCEPTION) { die; } my $benchmark_result = BenchmarkService_fibonacci_result->new(); $benchmark_result->read($benchmark_protocol); $benchmark_protocol->readMessageEnd(); is($benchmark_result->success(), $val); } package My::Aggr; use base qw(AggrIf); use strict; use warnings; sub new { my $classname = shift; my $self = {}; $self->{values} = (); return bless($self,$classname); } sub addValue{ my $self = shift; my $value = shift; push (@{$self->{values}}, $value); } sub getValues{ my $self = shift; return $self->{values}; } package My::BenchmarkService; use base qw(BenchmarkServiceIf); use strict; use warnings; sub new { my $class = shift; return bless {}, $class; } sub fibonacci { my ($self, $n) = @_; my $prev = 0; my $next; my $result = 1; while ($n > 0) { $next = $result + $prev; $prev = $result; $result = $next; --$n; } return $result; } thrift-0.16.0/lib/perl/t/processor.t000066400000000000000000000055401420101504100172450ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use Test::More tests => 2; use strict; use warnings; use Thrift::BinaryProtocol; use Thrift::MemoryBuffer; use Thrift::MessageType; use ThriftTest::ThriftTest; use ThriftTest::Types; use Data::Dumper; my $buffer = Thrift::MemoryBuffer->new(1024); my $protocol = Thrift::BinaryProtocol->new($buffer); my $client = ThriftTest::ThriftTestClient->new($protocol); $buffer->open(); $client->send_testString("foo"); $client->{seqid}++; $client->send_testString("bar"); my $client_command_binary = $buffer->getBuffer; $buffer->resetBuffer; # Process by server my $server_output_binary; { my $protocol_factory = Thrift::BinaryProtocolFactory->new(); my $input_buffer = Thrift::MemoryBuffer->new(); $input_buffer->write($client_command_binary); my $input_protocol = $protocol_factory->getProtocol($input_buffer); my $output_buffer = Thrift::MemoryBuffer->new(); my $output_protocol = $protocol_factory->getProtocol($output_buffer); my $processor = ThriftTest::ThriftTestProcessor->new( My::ThriftTest->new() ); my $result = $processor->process($input_protocol, $output_protocol); print "process resulted in $result\n"; $result = $processor->process($input_protocol, $output_protocol); print "process resulted in $result\n"; $server_output_binary = $output_buffer->getBuffer(); } $buffer->write($server_output_binary); foreach my $val (("got foo","got bar")){ my ($function_name, $message_type, $sequence_id); $protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id); print " $function_name, $message_type, $sequence_id\n"; if ($message_type == Thrift::TMessageType::EXCEPTION) { die; } my $result = ThriftTest::ThriftTest_testString_result->new(); $result->read($protocol); $protocol->readMessageEnd(); is($result->success(),$val); } package My::ThriftTest; use strict; use warnings; use Data::Dumper; sub new { my $class = shift; return bless {}, $class; } sub testString { my ($self, $string) = @_; print __PACKAGE__ . "->testString()\n"; return "got ".$string; } thrift-0.16.0/lib/perl/test.pl000066400000000000000000000015221420101504100161060ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use strict; use warnings; use Test::Harness; runtests(@ARGV); thrift-0.16.0/lib/perl/tools/000077500000000000000000000000001420101504100157325ustar00rootroot00000000000000thrift-0.16.0/lib/perl/tools/FixupDist.pl000066400000000000000000000021441420101504100202070ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # This will fix up the distribution so that CPAN properly # indexes Thrift. # use 5.10.0; use strict; use warnings; use utf8; use Data::Dumper; use CPAN::Meta; my $meta = CPAN::Meta->load_file('META.json'); $meta->{'provides'} = { 'Thrift' => { 'file' => 'lib/Thrift.pm', 'version' => $meta->version() } }; $meta->save('META.json'); thrift-0.16.0/lib/php/000077500000000000000000000000001420101504100144175ustar00rootroot00000000000000thrift-0.16.0/lib/php/Makefile.am000077500000000000000000000114461420101504100164640ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # if WITH_TESTS SUBDIRS = test endif if WITH_PHP_EXTENSION %.so: cd src/ext/thrift_protocol/ && $(MAKE) phpconfdir=$(PHP_CONFIG_PREFIX) phpconf_DATA=thrift_protocol.ini phpmoduledir = `php-config --extension-dir` phpmodule_SCRIPTS = src/ext/thrift_protocol/modules/thrift_protocol.so distclean-local: if [ -f src/ext/thrift_protocol/Makefile ]; then cd src/ext/thrift_protocol/ && $(MAKE) distclean; fi cd $(phpmodule_SCRIPTS) && $(PHPIZE) --clean endif phpdir = $(PHP_PREFIX)/ php_DATA = \ lib/TMultiplexedProcessor.php phpbasedir = $(phpdir)/Base phpbase_DATA = \ lib/Base/TBase.php phpclassloaderdir = $(phpdir)/ClassLoader phpclassloader_DATA = \ lib/ClassLoader/ThriftClassLoader.php phpexceptiondir = $(phpdir)/Exception phpexception_DATA = \ lib/Exception/TApplicationException.php \ lib/Exception/TException.php \ lib/Exception/TProtocolException.php \ lib/Exception/TTransportException.php phpfactorydir = $(phpdir)/Factory phpfactory_DATA = \ lib/Factory/TBinaryProtocolFactory.php \ lib/Factory/TCompactProtocolFactory.php \ lib/Factory/TJSONProtocolFactory.php \ lib/Factory/TProtocolFactory.php \ lib/Factory/TStringFuncFactory.php \ lib/Factory/TTransportFactory.php phpprotocoldir = $(phpdir)/Protocol phpprotocol_DATA = \ lib/Protocol/TBinaryProtocolAccelerated.php \ lib/Protocol/TBinaryProtocol.php \ lib/Protocol/TCompactProtocol.php \ lib/Protocol/TJSONProtocol.php \ lib/Protocol/TMultiplexedProtocol.php \ lib/Protocol/TProtocol.php \ lib/Protocol/TProtocolDecorator.php \ lib/Protocol/TSimpleJSONProtocol.php phpprotocoljsondir = $(phpprotocoldir)/JSON phpprotocoljson_DATA = \ lib/Protocol/JSON/BaseContext.php \ lib/Protocol/JSON/ListContext.php \ lib/Protocol/JSON/LookaheadReader.php \ lib/Protocol/JSON/PairContext.php phpprotocolsimplejsondir = $(phpprotocoldir)/SimpleJSON phpprotocolsimplejson_DATA = \ lib/Protocol/SimpleJSON/CollectionMapKeyException.php \ lib/Protocol/SimpleJSON/Context.php \ lib/Protocol/SimpleJSON/ListContext.php \ lib/Protocol/SimpleJSON/MapContext.php \ lib/Protocol/SimpleJSON/StructContext.php phpserializerdir = $(phpdir)/Serializer phpserializer_DATA = \ lib/Serializer/TBinarySerializer.php phpserverdir = $(phpdir)/Server phpserver_DATA = \ lib/Server/TServerSocket.php \ lib/Server/TForkingServer.php \ lib/Server/TServer.php \ lib/Server/TServerTransport.php \ lib/Server/TSimpleServer.php phpstringfuncdir = $(phpdir)/StringFunc phpstringfunc_DATA = \ lib/StringFunc/Mbstring.php \ lib/StringFunc/Core.php \ lib/StringFunc/TStringFunc.php phptransportdir = $(phpdir)/Transport phptransport_DATA = \ lib/Transport/TBufferedTransport.php \ lib/Transport/TCurlClient.php \ lib/Transport/TFramedTransport.php \ lib/Transport/THttpClient.php \ lib/Transport/TMemoryBuffer.php \ lib/Transport/TNullTransport.php \ lib/Transport/TPhpStream.php \ lib/Transport/TSocket.php \ lib/Transport/TSocketPool.php \ lib/Transport/TTransport.php phptypedir = $(phpdir)/Type phptype_DATA = \ lib/Type/TMessageType.php \ lib/Type/TType.php \ lib/Type/TConstant.php clean-local: if [ -f src/ext/thrift_protocol/Makefile ]; then cd src/ext/thrift_protocol/ && $(MAKE) clean; fi EXTRA_DIST = \ lib \ src/autoload.php \ src/ext/thrift_protocol/config.m4 \ src/ext/thrift_protocol/config.w32 \ src/ext/thrift_protocol/php_thrift_protocol.cpp \ src/ext/thrift_protocol/php_thrift_protocol.h \ src/ext/thrift_protocol/php_thrift_protocol.stub.php \ src/ext/thrift_protocol/php_thrift_protocol_arginfo.h \ src/Thrift.php \ src/TStringUtils.php \ coding_standards.md \ thrift_protocol.ini \ README.apache.md \ README.md \ test/Fixtures.php \ test/TestValidators.thrift \ test/JsonSerialize/JsonSerializeTest.php \ test/Protocol/BinarySerializerTest.php \ test/Protocol/TJSONProtocolFixtures.php \ test/Protocol/TJSONProtocolTest.php \ test/Protocol/TSimpleJSONProtocolFixtures.php \ test/Protocol/TSimpleJSONProtocolTest.php \ test/Validator/BaseValidatorTest.php \ test/Validator/ValidatorTest.php \ test/Validator/ValidatorTestOop.php MAINTAINERCLEANFILES = \ Makefile.in thrift-0.16.0/lib/php/README.apache.md000066400000000000000000000040511420101504100171160ustar00rootroot00000000000000Thrift PHP/Apache Integration License ======= Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Building PHP Thrift Services with Apache ======================================== Thrift can be embedded in the Apache webserver with PHP installed. Sample code is provided below. Note that to make requests to this type of server you must use a THttpClient transport. Sample Code =========== registerNamespace('Thrift', $THRIFT_ROOT); $loader->registerDefinition('Thrift', $THRIFT_ROOT . '/packages'); $loader->register(); use Thrift\Transport\TPhpStream; use Thrift\Protocol\TBinaryProtocol; /** * Example of how to build a Thrift server in Apache/PHP */ class ServiceHandler implements ServiceIf { // Implement your interface and methods here } header('Content-Type: application/x-thrift'); $handler = new ServiceHandler(); $processor = new ServiceProcessor($handler); // Use the TPhpStream transport to read/write directly from HTTP $transport = new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W); $protocol = new TBinaryProtocol($transport); $transport->open(); $processor->process($protocol, $protocol); $transport->close(); thrift-0.16.0/lib/php/README.md000066400000000000000000000040621420101504100157000ustar00rootroot00000000000000Thrift PHP Software Library # License Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. # Using Thrift with PHP Thrift requires PHP 5. Thrift makes as few assumptions about your PHP environment as possible while trying to make some more advanced PHP features (i.e. APCu cacheing using asbolute path URLs) as simple as possible. To use Thrift in your PHP codebase, take the following steps: 1. Copy all of thrift/lib/php/lib into your PHP codebase 2. Configure Symfony Autoloader (or whatever you usually use) After that, you have to manually include the Thrift package created by the compiler: ``` require_once 'packages/Service/Service.php'; require_once 'packages/Service/Types.php'; ``` # Dependencies PHP_INT_SIZE This built-in signals whether your architecture is 32 or 64 bit and is used by the TBinaryProtocol to properly use pack() and unpack() to serialize data. apcu_fetch(), apcu_store() APCu cache is used by the TSocketPool class. If you do not have APCu installed, Thrift will fill in null stub function definitions. # Breaking Changes ## 0.12.0 1. [PSR-4](https://www.php-fig.org/psr/psr-4/) loader is now the default. If you want to use class maps instead, use `-gen php:classmap`. 2. If using PSR-4, use `$thriftClassLoader->registerNamespace('namespace', '')` instead of `$thriftClassLoader->registerDefinition('namespace', '')`. thrift-0.16.0/lib/php/coding_standards.md000066400000000000000000000002251420101504100202460ustar00rootroot00000000000000## PHP Coding Standards Please follow: * [Thrift General Coding Standards](/doc/coding_standards.md) * [PSR-2](http://www.php-fig.org/psr/psr-2/) thrift-0.16.0/lib/php/lib/000077500000000000000000000000001420101504100151655ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Base/000077500000000000000000000000001420101504100160375ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Base/TBase.php000066400000000000000000000321441420101504100175520ustar00rootroot00000000000000 'Bool', TType::BYTE => 'Byte', TType::I16 => 'I16', TType::I32 => 'I32', TType::I64 => 'I64', TType::DOUBLE => 'Double', TType::STRING => 'String' ); abstract public function read($input); abstract public function write($output); public function __construct($spec = null, $vals = null) { if (is_array($spec) && is_array($vals)) { foreach ($spec as $fid => $fspec) { $var = $fspec['var']; if (isset($vals[$var])) { $this->$var = $vals[$var]; } } } } public function __wakeup() { $this->__construct(get_object_vars($this)); } private function _readMap(&$var, $spec, $input) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kread = $vread = null; if (isset(TBase::$tmethod[$ktype])) { $kread = 'read' . TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vread = 'read' . TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $var = array(); $_ktype = $_vtype = $size = 0; $xfer += $input->readMapBegin($_ktype, $_vtype, $size); for ($i = 0; $i < $size; ++$i) { $key = $val = null; if ($kread !== null) { $xfer += $input->$kread($key); } else { switch ($ktype) { case TType::STRUCT: $class = $kspec['class']; $key = new $class(); $xfer += $key->read($input); break; case TType::MAP: $xfer += $this->_readMap($key, $kspec, $input); break; case TType::LST: $xfer += $this->_readList($key, $kspec, $input, false); break; case TType::SET: $xfer += $this->_readList($key, $kspec, $input, true); break; } } if ($vread !== null) { $xfer += $input->$vread($val); } else { switch ($vtype) { case TType::STRUCT: $class = $vspec['class']; $val = new $class(); $xfer += $val->read($input); break; case TType::MAP: $xfer += $this->_readMap($val, $vspec, $input); break; case TType::LST: $xfer += $this->_readList($val, $vspec, $input, false); break; case TType::SET: $xfer += $this->_readList($val, $vspec, $input, true); break; } } $var[$key] = $val; } $xfer += $input->readMapEnd(); return $xfer; } private function _readList(&$var, $spec, $input, $set = false) { $xfer = 0; $etype = $spec['etype']; $eread = $vread = null; if (isset(TBase::$tmethod[$etype])) { $eread = 'read' . TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } $var = array(); $_etype = $size = 0; if ($set) { $xfer += $input->readSetBegin($_etype, $size); } else { $xfer += $input->readListBegin($_etype, $size); } for ($i = 0; $i < $size; ++$i) { $elem = null; if ($eread !== null) { $xfer += $input->$eread($elem); } else { $espec = $spec['elem']; switch ($etype) { case TType::STRUCT: $class = $espec['class']; $elem = new $class(); $xfer += $elem->read($input); break; case TType::MAP: $xfer += $this->_readMap($elem, $espec, $input); break; case TType::LST: $xfer += $this->_readList($elem, $espec, $input, false); break; case TType::SET: $xfer += $this->_readList($elem, $espec, $input, true); break; } } if ($set) { $var[$elem] = true; } else { $var [] = $elem; } } if ($set) { $xfer += $input->readSetEnd(); } else { $xfer += $input->readListEnd(); } return $xfer; } protected function _read($class, $spec, $input) { $xfer = 0; $fname = null; $ftype = 0; $fid = 0; $xfer += $input->readStructBegin($fname); while (true) { $xfer += $input->readFieldBegin($fname, $ftype, $fid); if ($ftype == TType::STOP) { break; } if (isset($spec[$fid])) { $fspec = $spec[$fid]; $var = $fspec['var']; if ($ftype == $fspec['type']) { $xfer = 0; if (isset(TBase::$tmethod[$ftype])) { $func = 'read' . TBase::$tmethod[$ftype]; $xfer += $input->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $class = $fspec['class']; $this->$var = new $class(); $xfer += $this->$var->read($input); break; case TType::MAP: $xfer += $this->_readMap($this->$var, $fspec, $input); break; case TType::LST: $xfer += $this->_readList($this->$var, $fspec, $input, false); break; case TType::SET: $xfer += $this->_readList($this->$var, $fspec, $input, true); break; } } } else { $xfer += $input->skip($ftype); } } else { $xfer += $input->skip($ftype); } $xfer += $input->readFieldEnd(); } $xfer += $input->readStructEnd(); return $xfer; } private function _writeMap($var, $spec, $output) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kwrite = $vwrite = null; if (isset(TBase::$tmethod[$ktype])) { $kwrite = 'write' . TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vwrite = 'write' . TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); foreach ($var as $key => $val) { if (isset($kwrite)) { $xfer += $output->$kwrite($key); } else { switch ($ktype) { case TType::STRUCT: $xfer += $key->write($output); break; case TType::MAP: $xfer += $this->_writeMap($key, $kspec, $output); break; case TType::LST: $xfer += $this->_writeList($key, $kspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($key, $kspec, $output, true); break; } } if (isset($vwrite)) { $xfer += $output->$vwrite($val); } else { switch ($vtype) { case TType::STRUCT: $xfer += $val->write($output); break; case TType::MAP: $xfer += $this->_writeMap($val, $vspec, $output); break; case TType::LST: $xfer += $this->_writeList($val, $vspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($val, $vspec, $output, true); break; } } } $xfer += $output->writeMapEnd(); return $xfer; } private function _writeList($var, $spec, $output, $set = false) { $xfer = 0; $etype = $spec['etype']; $ewrite = null; if (isset(TBase::$tmethod[$etype])) { $ewrite = 'write' . TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } if ($set) { $xfer += $output->writeSetBegin($etype, count($var)); } else { $xfer += $output->writeListBegin($etype, count($var)); } foreach ($var as $key => $val) { $elem = $set ? $key : $val; if (isset($ewrite)) { $xfer += $output->$ewrite($elem); } else { switch ($etype) { case TType::STRUCT: $xfer += $elem->write($output); break; case TType::MAP: $xfer += $this->_writeMap($elem, $espec, $output); break; case TType::LST: $xfer += $this->_writeList($elem, $espec, $output, false); break; case TType::SET: $xfer += $this->_writeList($elem, $espec, $output, true); break; } } } if ($set) { $xfer += $output->writeSetEnd(); } else { $xfer += $output->writeListEnd(); } return $xfer; } protected function _write($class, $spec, $output) { $xfer = 0; $xfer += $output->writeStructBegin($class); foreach ($spec as $fid => $fspec) { $var = $fspec['var']; if ($this->$var !== null) { $ftype = $fspec['type']; $xfer += $output->writeFieldBegin($var, $ftype, $fid); if (isset(TBase::$tmethod[$ftype])) { $func = 'write' . TBase::$tmethod[$ftype]; $xfer += $output->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $xfer += $this->$var->write($output); break; case TType::MAP: $xfer += $this->_writeMap($this->$var, $fspec, $output); break; case TType::LST: $xfer += $this->_writeList($this->$var, $fspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($this->$var, $fspec, $output, true); break; } } $xfer += $output->writeFieldEnd(); } } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; } } thrift-0.16.0/lib/php/lib/ClassLoader/000077500000000000000000000000001420101504100173615ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/ClassLoader/ThriftClassLoader.php000066400000000000000000000135211420101504100234510ustar00rootroot00000000000000apcu = $apc; $this->apcu_prefix = $apcu_prefix; } /** * Registers a namespace. * * @param string $namespace The namespace * @param array|string $paths The location(s) of the namespace */ public function registerNamespace($namespace, $paths) { $this->namespaces[$namespace] = (array)$paths; } /** * Registers a Thrift definition namespace. * * @param string $namespace The definition namespace * @param array|string $paths The location(s) of the definition namespace */ public function registerDefinition($namespace, $paths) { $this->definitions[$namespace] = (array)$paths; } /** * Registers this instance as an autoloader. * * @param Boolean $prepend Whether to prepend the autoloader or not */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } /** * Loads the given class, definition or interface. * * @param string $class The name of the class */ public function loadClass($class) { if ((true === $this->apcu && ($file = $this->findFileInApcu($class))) or ($file = $this->findFile($class)) ) { require_once $file; } } /** * Loads the given class or interface in APCu. * @param string $class The name of the class * @return string */ protected function findFileInApcu($class) { if (false === $file = apcu_fetch($this->apcu_prefix . $class)) { apcu_store($this->apcu_prefix . $class, $file = $this->findFile($class)); } return $file; } /** * Find class in namespaces or definitions directories * @param string $class * @return string */ public function findFile($class) { // Remove first backslash if ('\\' == $class[0]) { $class = substr($class, 1); } if (false !== $pos = strrpos($class, '\\')) { // Namespaced class name $namespace = substr($class, 0, $pos); // Iterate in normal namespaces foreach ($this->namespaces as $ns => $dirs) { //Don't interfere with other autoloaders if (0 !== strpos($namespace, $ns)) { continue; } foreach ($dirs as $dir) { $className = substr($class, $pos + 1); $file = $dir . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR . $className . '.php'; if (file_exists($file)) { return $file; } } } // Iterate in Thrift namespaces // Remove first part of namespace $m = explode('\\', $class); // Ignore wrong call if (count($m) <= 1) { return; } $class = array_pop($m); $namespace = implode('\\', $m); foreach ($this->definitions as $ns => $dirs) { //Don't interfere with other autoloaders if (0 !== strpos($namespace, $ns)) { continue; } foreach ($dirs as $dir) { /** * Available in service: Interface, Client, Processor, Rest * And every service methods (_.+) */ if (0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and 0 === preg_match('#(.+)_[a-z0-9]+_(args|result)$#i', $class, $n) ) { $className = 'Types'; } else { $className = $n[1]; } $file = $dir . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR . $className . '.php'; if (file_exists($file)) { return $file; } } } } } } thrift-0.16.0/lib/php/lib/Exception/000077500000000000000000000000001420101504100171235ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Exception/TApplicationException.php000066400000000000000000000045561420101504100241140ustar00rootroot00000000000000 array('var' => 'message', 'type' => TType::STRING), 2 => array('var' => 'code', 'type' => TType::I32)); const UNKNOWN = 0; const UNKNOWN_METHOD = 1; const INVALID_MESSAGE_TYPE = 2; const WRONG_METHOD_NAME = 3; const BAD_SEQUENCE_ID = 4; const MISSING_RESULT = 5; const INTERNAL_ERROR = 6; const PROTOCOL_ERROR = 7; const INVALID_TRANSFORM = 8; const INVALID_PROTOCOL = 9; const UNSUPPORTED_CLIENT_TYPE = 10; public function __construct($message = null, $code = 0) { parent::__construct($message, $code); } public function read($output) { return $this->_read('TApplicationException', self::$_TSPEC, $output); } public function write($output) { $xfer = 0; $xfer += $output->writeStructBegin('TApplicationException'); if ($message = $this->getMessage()) { $xfer += $output->writeFieldBegin('message', TType::STRING, 1); $xfer += $output->writeString($message); $xfer += $output->writeFieldEnd(); } if ($code = $this->getCode()) { $xfer += $output->writeFieldBegin('type', TType::I32, 2); $xfer += $output->writeI32($code); $xfer += $output->writeFieldEnd(); } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; } } thrift-0.16.0/lib/php/lib/Exception/TException.php000066400000000000000000000324231420101504100217220ustar00rootroot00000000000000 $fspec) { $var = $fspec['var']; if (isset($vals[$var])) { $this->$var = $vals[$var]; } } } else { parent::__construct($p1, $p2); } } public static $tmethod = array( TType::BOOL => 'Bool', TType::BYTE => 'Byte', TType::I16 => 'I16', TType::I32 => 'I32', TType::I64 => 'I64', TType::DOUBLE => 'Double', TType::STRING => 'String' ); private function _readMap(&$var, $spec, $input) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kread = $vread = null; if (isset(TBase::$tmethod[$ktype])) { $kread = 'read' . TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vread = 'read' . TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $var = array(); $_ktype = $_vtype = $size = 0; $xfer += $input->readMapBegin($_ktype, $_vtype, $size); for ($i = 0; $i < $size; ++$i) { $key = $val = null; if ($kread !== null) { $xfer += $input->$kread($key); } else { switch ($ktype) { case TType::STRUCT: $class = $kspec['class']; $key = new $class(); $xfer += $key->read($input); break; case TType::MAP: $xfer += $this->_readMap($key, $kspec, $input); break; case TType::LST: $xfer += $this->_readList($key, $kspec, $input, false); break; case TType::SET: $xfer += $this->_readList($key, $kspec, $input, true); break; } } if ($vread !== null) { $xfer += $input->$vread($val); } else { switch ($vtype) { case TType::STRUCT: $class = $vspec['class']; $val = new $class(); $xfer += $val->read($input); break; case TType::MAP: $xfer += $this->_readMap($val, $vspec, $input); break; case TType::LST: $xfer += $this->_readList($val, $vspec, $input, false); break; case TType::SET: $xfer += $this->_readList($val, $vspec, $input, true); break; } } $var[$key] = $val; } $xfer += $input->readMapEnd(); return $xfer; } private function _readList(&$var, $spec, $input, $set = false) { $xfer = 0; $etype = $spec['etype']; $eread = $vread = null; if (isset(TBase::$tmethod[$etype])) { $eread = 'read' . TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } $var = array(); $_etype = $size = 0; if ($set) { $xfer += $input->readSetBegin($_etype, $size); } else { $xfer += $input->readListBegin($_etype, $size); } for ($i = 0; $i < $size; ++$i) { $elem = null; if ($eread !== null) { $xfer += $input->$eread($elem); } else { $espec = $spec['elem']; switch ($etype) { case TType::STRUCT: $class = $espec['class']; $elem = new $class(); $xfer += $elem->read($input); break; case TType::MAP: $xfer += $this->_readMap($elem, $espec, $input); break; case TType::LST: $xfer += $this->_readList($elem, $espec, $input, false); break; case TType::SET: $xfer += $this->_readList($elem, $espec, $input, true); break; } } if ($set) { $var[$elem] = true; } else { $var [] = $elem; } } if ($set) { $xfer += $input->readSetEnd(); } else { $xfer += $input->readListEnd(); } return $xfer; } protected function _read($class, $spec, $input) { $xfer = 0; $fname = null; $ftype = 0; $fid = 0; $xfer += $input->readStructBegin($fname); while (true) { $xfer += $input->readFieldBegin($fname, $ftype, $fid); if ($ftype == TType::STOP) { break; } if (isset($spec[$fid])) { $fspec = $spec[$fid]; $var = $fspec['var']; if ($ftype == $fspec['type']) { $xfer = 0; if (isset(TBase::$tmethod[$ftype])) { $func = 'read' . TBase::$tmethod[$ftype]; $xfer += $input->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $class = $fspec['class']; $this->$var = new $class(); $xfer += $this->$var->read($input); break; case TType::MAP: $xfer += $this->_readMap($this->$var, $fspec, $input); break; case TType::LST: $xfer += $this->_readList($this->$var, $fspec, $input, false); break; case TType::SET: $xfer += $this->_readList($this->$var, $fspec, $input, true); break; } } } else { $xfer += $input->skip($ftype); } } else { $xfer += $input->skip($ftype); } $xfer += $input->readFieldEnd(); } $xfer += $input->readStructEnd(); return $xfer; } private function _writeMap($var, $spec, $output) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kwrite = $vwrite = null; if (isset(TBase::$tmethod[$ktype])) { $kwrite = 'write' . TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vwrite = 'write' . TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); foreach ($var as $key => $val) { if (isset($kwrite)) { $xfer += $output->$kwrite($key); } else { switch ($ktype) { case TType::STRUCT: $xfer += $key->write($output); break; case TType::MAP: $xfer += $this->_writeMap($key, $kspec, $output); break; case TType::LST: $xfer += $this->_writeList($key, $kspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($key, $kspec, $output, true); break; } } if (isset($vwrite)) { $xfer += $output->$vwrite($val); } else { switch ($vtype) { case TType::STRUCT: $xfer += $val->write($output); break; case TType::MAP: $xfer += $this->_writeMap($val, $vspec, $output); break; case TType::LST: $xfer += $this->_writeList($val, $vspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($val, $vspec, $output, true); break; } } } $xfer += $output->writeMapEnd(); return $xfer; } private function _writeList($var, $spec, $output, $set = false) { $xfer = 0; $etype = $spec['etype']; $ewrite = null; if (isset(TBase::$tmethod[$etype])) { $ewrite = 'write' . TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } if ($set) { $xfer += $output->writeSetBegin($etype, count($var)); } else { $xfer += $output->writeListBegin($etype, count($var)); } foreach ($var as $key => $val) { $elem = $set ? $key : $val; if (isset($ewrite)) { $xfer += $output->$ewrite($elem); } else { switch ($etype) { case TType::STRUCT: $xfer += $elem->write($output); break; case TType::MAP: $xfer += $this->_writeMap($elem, $espec, $output); break; case TType::LST: $xfer += $this->_writeList($elem, $espec, $output, false); break; case TType::SET: $xfer += $this->_writeList($elem, $espec, $output, true); break; } } } if ($set) { $xfer += $output->writeSetEnd(); } else { $xfer += $output->writeListEnd(); } return $xfer; } protected function _write($class, $spec, $output) { $xfer = 0; $xfer += $output->writeStructBegin($class); foreach ($spec as $fid => $fspec) { $var = $fspec['var']; if ($this->$var !== null) { $ftype = $fspec['type']; $xfer += $output->writeFieldBegin($var, $ftype, $fid); if (isset(TBase::$tmethod[$ftype])) { $func = 'write' . TBase::$tmethod[$ftype]; $xfer += $output->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $xfer += $this->$var->write($output); break; case TType::MAP: $xfer += $this->_writeMap($this->$var, $fspec, $output); break; case TType::LST: $xfer += $this->_writeList($this->$var, $fspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($this->$var, $fspec, $output, true); break; } } $xfer += $output->writeFieldEnd(); } } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; } } thrift-0.16.0/lib/php/lib/Exception/TProtocolException.php000066400000000000000000000026571420101504100234520ustar00rootroot00000000000000strictRead_ = $strictRead; $this->strictWrite_ = $strictWrite; } public function getProtocol($trans) { return new TBinaryProtocol($trans, $this->strictRead_, $this->strictWrite_); } } thrift-0.16.0/lib/php/lib/Factory/TCompactProtocolFactory.php000066400000000000000000000021761420101504100240770ustar00rootroot00000000000000p_ = $p; } public function write() { if ($this->first_) { $this->first_ = false; } else { $this->p_->getTransport()->write(TJSONProtocol::COMMA); } } public function read() { if ($this->first_) { $this->first_ = false; } else { $this->p_->readJSONSyntaxChar(TJSONProtocol::COMMA); } } } thrift-0.16.0/lib/php/lib/Protocol/JSON/LookaheadReader.php000066400000000000000000000027621420101504100232710ustar00rootroot00000000000000p_ = $p; } public function read() { if ($this->hasData_) { $this->hasData_ = false; } else { $this->data_ = $this->p_->getTransport()->readAll(1); } return substr($this->data_, 0, 1); } public function peek() { if (!$this->hasData_) { $this->data_ = $this->p_->getTransport()->readAll(1); } $this->hasData_ = true; return substr($this->data_, 0, 1); } } thrift-0.16.0/lib/php/lib/Protocol/JSON/PairContext.php000066400000000000000000000034231420101504100225120ustar00rootroot00000000000000p_ = $p; } public function write() { if ($this->first_) { $this->first_ = false; $this->colon_ = true; } else { $this->p_->getTransport()->write($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA); $this->colon_ = !$this->colon_; } } public function read() { if ($this->first_) { $this->first_ = false; $this->colon_ = true; } else { $this->p_->readJSONSyntaxChar($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA); $this->colon_ = !$this->colon_; } } public function escapeNum() { return $this->colon_; } } thrift-0.16.0/lib/php/lib/Protocol/SimpleJSON/000077500000000000000000000000001420101504100207115ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Protocol/SimpleJSON/CollectionMapKeyException.php000066400000000000000000000020471420101504100265060ustar00rootroot00000000000000p_ = $p; } public function write() { if ($this->first_) { $this->first_ = false; } else { $this->p_->getTransport()->write(TSimpleJSONProtocol::COMMA); } } } thrift-0.16.0/lib/php/lib/Protocol/SimpleJSON/MapContext.php000066400000000000000000000024471420101504100235130ustar00rootroot00000000000000isKey = !$this->isKey; } public function isMapKey() { // we want to coerce map keys to json strings regardless // of their type return $this->isKey; } } thrift-0.16.0/lib/php/lib/Protocol/SimpleJSON/StructContext.php000066400000000000000000000027501420101504100242570ustar00rootroot00000000000000p_ = $p; } public function write() { if ($this->first_) { $this->first_ = false; $this->colon_ = true; } else { $this->p_->getTransport()->write( $this->colon_ ? TSimpleJSONProtocol::COLON : TSimpleJSONProtocol::COMMA ); $this->colon_ = !$this->colon_; } } } thrift-0.16.0/lib/php/lib/Protocol/TBinaryProtocol.php000066400000000000000000000250501420101504100225730ustar00rootroot00000000000000strictRead_ = $strictRead; $this->strictWrite_ = $strictWrite; } public function writeMessageBegin($name, $type, $seqid) { if ($this->strictWrite_) { $version = self::VERSION_1 | $type; return $this->writeI32($version) + $this->writeString($name) + $this->writeI32($seqid); } else { return $this->writeString($name) + $this->writeByte($type) + $this->writeI32($seqid); } } public function writeMessageEnd() { return 0; } public function writeStructBegin($name) { return 0; } public function writeStructEnd() { return 0; } public function writeFieldBegin($fieldName, $fieldType, $fieldId) { return $this->writeByte($fieldType) + $this->writeI16($fieldId); } public function writeFieldEnd() { return 0; } public function writeFieldStop() { return $this->writeByte(TType::STOP); } public function writeMapBegin($keyType, $valType, $size) { return $this->writeByte($keyType) + $this->writeByte($valType) + $this->writeI32($size); } public function writeMapEnd() { return 0; } public function writeListBegin($elemType, $size) { return $this->writeByte($elemType) + $this->writeI32($size); } public function writeListEnd() { return 0; } public function writeSetBegin($elemType, $size) { return $this->writeByte($elemType) + $this->writeI32($size); } public function writeSetEnd() { return 0; } public function writeBool($value) { $data = pack('c', $value ? 1 : 0); $this->trans_->write($data, 1); return 1; } public function writeByte($value) { $data = pack('c', $value); $this->trans_->write($data, 1); return 1; } public function writeI16($value) { $data = pack('n', $value); $this->trans_->write($data, 2); return 2; } public function writeI32($value) { $data = pack('N', $value); $this->trans_->write($data, 4); return 4; } public function writeI64($value) { // If we are on a 32bit architecture we have to explicitly deal with // 64-bit twos-complement arithmetic since PHP wants to treat all ints // as signed and any int over 2^31 - 1 as a float if (PHP_INT_SIZE == 4) { $neg = $value < 0; if ($neg) { $value *= -1; } $hi = (int)($value / 4294967296); $lo = (int)$value; if ($neg) { $hi = ~$hi; $lo = ~$lo; if (($lo & (int)0xffffffff) == (int)0xffffffff) { $lo = 0; $hi++; } else { $lo++; } } $data = pack('N2', $hi, $lo); } else { $hi = $value >> 32; $lo = $value & 0xFFFFFFFF; $data = pack('N2', $hi, $lo); } $this->trans_->write($data, 8); return 8; } public function writeDouble($value) { $data = pack('d', $value); $this->trans_->write(strrev($data), 8); return 8; } public function writeString($value) { $len = TStringFuncFactory::create()->strlen($value); $result = $this->writeI32($len); if ($len) { $this->trans_->write($value, $len); } return $result + $len; } public function readMessageBegin(&$name, &$type, &$seqid) { $result = $this->readI32($sz); if ($sz < 0) { $version = (int)($sz & self::VERSION_MASK); if ($version != (int)self::VERSION_1) { throw new TProtocolException('Bad version identifier: ' . $sz, TProtocolException::BAD_VERSION); } $type = $sz & 0x000000ff; $result += $this->readString($name) + $this->readI32($seqid); } else { if ($this->strictRead_) { throw new TProtocolException( 'No version identifier, old protocol client?', TProtocolException::BAD_VERSION ); } else { // Handle pre-versioned input $name = $this->trans_->readAll($sz); $result += $sz + $this->readByte($type) + $this->readI32($seqid); } } return $result; } public function readMessageEnd() { return 0; } public function readStructBegin(&$name) { $name = ''; return 0; } public function readStructEnd() { return 0; } public function readFieldBegin(&$name, &$fieldType, &$fieldId) { $result = $this->readByte($fieldType); if ($fieldType == TType::STOP) { $fieldId = 0; return $result; } $result += $this->readI16($fieldId); return $result; } public function readFieldEnd() { return 0; } public function readMapBegin(&$keyType, &$valType, &$size) { return $this->readByte($keyType) + $this->readByte($valType) + $this->readI32($size); } public function readMapEnd() { return 0; } public function readListBegin(&$elemType, &$size) { return $this->readByte($elemType) + $this->readI32($size); } public function readListEnd() { return 0; } public function readSetBegin(&$elemType, &$size) { return $this->readByte($elemType) + $this->readI32($size); } public function readSetEnd() { return 0; } public function readBool(&$value) { $data = $this->trans_->readAll(1); $arr = unpack('c', $data); $value = $arr[1] == 1; return 1; } public function readByte(&$value) { $data = $this->trans_->readAll(1); $arr = unpack('c', $data); $value = $arr[1]; return 1; } public function readI16(&$value) { $data = $this->trans_->readAll(2); $arr = unpack('n', $data); $value = $arr[1]; if ($value > 0x7fff) { $value = 0 - (($value - 1) ^ 0xffff); } return 2; } public function readI32(&$value) { $data = $this->trans_->readAll(4); $arr = unpack('N', $data); $value = $arr[1]; if ($value > 0x7fffffff) { $value = 0 - (($value - 1) ^ 0xffffffff); } return 4; } public function readI64(&$value) { $data = $this->trans_->readAll(8); $arr = unpack('N2', $data); // If we are on a 32bit architecture we have to explicitly deal with // 64-bit twos-complement arithmetic since PHP wants to treat all ints // as signed and any int over 2^31 - 1 as a float if (PHP_INT_SIZE == 4) { $hi = $arr[1]; $lo = $arr[2]; $isNeg = $hi < 0; // Check for a negative if ($isNeg) { $hi = ~$hi & (int)0xffffffff; $lo = ~$lo & (int)0xffffffff; if ($lo == (int)0xffffffff) { $hi++; $lo = 0; } else { $lo++; } } // Force 32bit words in excess of 2G to pe positive - we deal wigh sign // explicitly below if ($hi & (int)0x80000000) { $hi &= (int)0x7fffffff; $hi += 0x80000000; } if ($lo & (int)0x80000000) { $lo &= (int)0x7fffffff; $lo += 0x80000000; } $value = $hi * 4294967296 + $lo; if ($isNeg) { $value = 0 - $value; } } else { // Upcast negatives in LSB bit if ($arr[2] & 0x80000000) { $arr[2] = $arr[2] & 0xffffffff; } // Check for a negative if ($arr[1] & 0x80000000) { $arr[1] = $arr[1] & 0xffffffff; $arr[1] = $arr[1] ^ 0xffffffff; $arr[2] = $arr[2] ^ 0xffffffff; $value = 0 - $arr[1] * 4294967296 - $arr[2] - 1; } else { $value = $arr[1] * 4294967296 + $arr[2]; } } return 8; } public function readDouble(&$value) { $data = strrev($this->trans_->readAll(8)); $arr = unpack('d', $data); $value = $arr[1]; return 8; } public function readString(&$value) { $result = $this->readI32($len); if ($len) { $value = $this->trans_->readAll($len); } else { $value = ''; } return $result + $len; } } thrift-0.16.0/lib/php/lib/Protocol/TBinaryProtocolAccelerated.php000066400000000000000000000051321420101504100247070ustar00rootroot00000000000000strictRead_; } public function isStrictWrite() { return $this->strictWrite_; } } thrift-0.16.0/lib/php/lib/Protocol/TCompactProtocol.php000066400000000000000000000470071420101504100227430ustar00rootroot00000000000000 TCompactProtocol::COMPACT_STOP, TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection TType::BYTE => TCompactProtocol::COMPACT_BYTE, TType::I16 => TCompactProtocol::COMPACT_I16, TType::I32 => TCompactProtocol::COMPACT_I32, TType::I64 => TCompactProtocol::COMPACT_I64, TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE, TType::STRING => TCompactProtocol::COMPACT_BINARY, TType::STRUCT => TCompactProtocol::COMPACT_STRUCT, TType::LST => TCompactProtocol::COMPACT_LIST, TType::SET => TCompactProtocol::COMPACT_SET, TType::MAP => TCompactProtocol::COMPACT_MAP, ); protected static $ttypes = array( TCompactProtocol::COMPACT_STOP => TType::STOP, TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection TCompactProtocol::COMPACT_FALSE => TType::BOOL, TCompactProtocol::COMPACT_BYTE => TType::BYTE, TCompactProtocol::COMPACT_I16 => TType::I16, TCompactProtocol::COMPACT_I32 => TType::I32, TCompactProtocol::COMPACT_I64 => TType::I64, TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE, TCompactProtocol::COMPACT_BINARY => TType::STRING, TCompactProtocol::COMPACT_STRUCT => TType::STRUCT, TCompactProtocol::COMPACT_LIST => TType::LST, TCompactProtocol::COMPACT_SET => TType::SET, TCompactProtocol::COMPACT_MAP => TType::MAP, ); protected $state = TCompactProtocol::STATE_CLEAR; protected $lastFid = 0; protected $boolFid = null; protected $boolValue = null; protected $structs = array(); protected $containers = array(); // Some varint / zigzag helper methods public function toZigZag($n, $bits) { return ($n << 1) ^ ($n >> ($bits - 1)); } public function fromZigZag($n) { return ($n >> 1) ^ -($n & 1); } public function getVarint($data) { $out = ""; while (true) { if (($data & ~0x7f) === 0) { $out .= chr($data); break; } else { $out .= chr(($data & 0xff) | 0x80); $data = $data >> 7; } } return $out; } public function writeVarint($data) { $out = $this->getVarint($data); $result = TStringFuncFactory::create()->strlen($out); $this->trans_->write($out, $result); return $result; } public function readVarint(&$result) { $idx = 0; $shift = 0; $result = 0; while (true) { $x = $this->trans_->readAll(1); $arr = unpack('C', $x); $byte = $arr[1]; $idx += 1; $result |= ($byte & 0x7f) << $shift; if (($byte >> 7) === 0) { return $idx; } $shift += 7; } return $idx; } public function __construct($trans) { parent::__construct($trans); } public function writeMessageBegin($name, $type, $seqid) { $written = $this->writeUByte(TCompactProtocol::PROTOCOL_ID) + $this->writeUByte(TCompactProtocol::VERSION | ($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) + $this->writeVarint($seqid) + $this->writeString($name); $this->state = TCompactProtocol::STATE_VALUE_WRITE; return $written; } public function writeMessageEnd() { $this->state = TCompactProtocol::STATE_CLEAR; return 0; } public function writeStructBegin($name) { $this->structs[] = array($this->state, $this->lastFid); $this->state = TCompactProtocol::STATE_FIELD_WRITE; $this->lastFid = 0; return 0; } public function writeStructEnd() { $old_values = array_pop($this->structs); $this->state = $old_values[0]; $this->lastFid = $old_values[1]; return 0; } public function writeFieldStop() { return $this->writeByte(0); } public function writeFieldHeader($type, $fid) { $written = 0; $delta = $fid - $this->lastFid; if (0 < $delta && $delta <= 15) { $written = $this->writeUByte(($delta << 4) | $type); } else { $written = $this->writeByte($type) + $this->writeI16($fid); } $this->lastFid = $fid; return $written; } public function writeFieldBegin($field_name, $field_type, $field_id) { if ($field_type == TTYPE::BOOL) { $this->state = TCompactProtocol::STATE_BOOL_WRITE; $this->boolFid = $field_id; return 0; } else { $this->state = TCompactProtocol::STATE_VALUE_WRITE; return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id); } } public function writeFieldEnd() { $this->state = TCompactProtocol::STATE_FIELD_WRITE; return 0; } public function writeCollectionBegin($etype, $size) { $written = 0; if ($size <= 14) { $written = $this->writeUByte($size << 4 | self::$ctypes[$etype]); } else { $written = $this->writeUByte(0xf0 | self::$ctypes[$etype]) + $this->writeVarint($size); } $this->containers[] = $this->state; $this->state = TCompactProtocol::STATE_CONTAINER_WRITE; return $written; } public function writeMapBegin($key_type, $val_type, $size) { $written = 0; if ($size == 0) { $written = $this->writeByte(0); } else { $written = $this->writeVarint($size) + $this->writeUByte(self::$ctypes[$key_type] << 4 | self::$ctypes[$val_type]); } $this->containers[] = $this->state; return $written; } public function writeCollectionEnd() { $this->state = array_pop($this->containers); return 0; } public function writeMapEnd() { return $this->writeCollectionEnd(); } public function writeListBegin($elem_type, $size) { return $this->writeCollectionBegin($elem_type, $size); } public function writeListEnd() { return $this->writeCollectionEnd(); } public function writeSetBegin($elem_type, $size) { return $this->writeCollectionBegin($elem_type, $size); } public function writeSetEnd() { return $this->writeCollectionEnd(); } public function writeBool($value) { if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) { $ctype = TCompactProtocol::COMPACT_FALSE; if ($value) { $ctype = TCompactProtocol::COMPACT_TRUE; } return $this->writeFieldHeader($ctype, $this->boolFid); } elseif ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) { return $this->writeByte($value ? 1 : 0); } else { throw new TProtocolException('Invalid state in compact protocol'); } } public function writeByte($value) { $data = pack('c', $value); $this->trans_->write($data, 1); return 1; } public function writeUByte($byte) { $this->trans_->write(pack('C', $byte), 1); return 1; } public function writeI16($value) { $thing = $this->toZigZag($value, 16); return $this->writeVarint($thing); } public function writeI32($value) { $thing = $this->toZigZag($value, 32); return $this->writeVarint($thing); } public function writeDouble($value) { $data = pack('d', $value); $this->trans_->write($data, 8); return 8; } public function writeString($value) { $len = TStringFuncFactory::create()->strlen($value); $result = $this->writeVarint($len); if ($len) { $this->trans_->write($value, $len); } return $result + $len; } public function readFieldBegin(&$name, &$field_type, &$field_id) { $result = $this->readUByte($compact_type_and_delta); $compact_type = $compact_type_and_delta & 0x0f; if ($compact_type == TType::STOP) { $field_type = $compact_type; $field_id = 0; return $result; } $delta = $compact_type_and_delta >> 4; if ($delta == 0) { $result += $this->readI16($field_id); } else { $field_id = $this->lastFid + $delta; } $this->lastFid = $field_id; $field_type = $this->getTType($compact_type); if ($compact_type == TCompactProtocol::COMPACT_TRUE) { $this->state = TCompactProtocol::STATE_BOOL_READ; $this->boolValue = true; } elseif ($compact_type == TCompactProtocol::COMPACT_FALSE) { $this->state = TCompactProtocol::STATE_BOOL_READ; $this->boolValue = false; } else { $this->state = TCompactProtocol::STATE_VALUE_READ; } return $result; } public function readFieldEnd() { $this->state = TCompactProtocol::STATE_FIELD_READ; return 0; } public function readUByte(&$value) { $data = $this->trans_->readAll(1); $arr = unpack('C', $data); $value = $arr[1]; return 1; } public function readByte(&$value) { $data = $this->trans_->readAll(1); $arr = unpack('c', $data); $value = $arr[1]; return 1; } public function readZigZag(&$value) { $result = $this->readVarint($value); $value = $this->fromZigZag($value); return $result; } public function readMessageBegin(&$name, &$type, &$seqid) { $protoId = 0; $result = $this->readUByte($protoId); if ($protoId != TCompactProtocol::PROTOCOL_ID) { throw new TProtocolException('Bad protocol id in TCompact message'); } $verType = 0; $result += $this->readUByte($verType); $type = ($verType >> TCompactProtocol::TYPE_SHIFT_AMOUNT) & TCompactProtocol::TYPE_BITS; $version = $verType & TCompactProtocol::VERSION_MASK; if ($version != TCompactProtocol::VERSION) { throw new TProtocolException('Bad version in TCompact message'); } $result += $this->readVarint($seqid); $result += $this->readString($name); return $result; } public function readMessageEnd() { return 0; } public function readStructBegin(&$name) { $name = ''; // unused $this->structs[] = array($this->state, $this->lastFid); $this->state = TCompactProtocol::STATE_FIELD_READ; $this->lastFid = 0; return 0; } public function readStructEnd() { $last = array_pop($this->structs); $this->state = $last[0]; $this->lastFid = $last[1]; return 0; } public function readCollectionBegin(&$type, &$size) { $sizeType = 0; $result = $this->readUByte($sizeType); $size = $sizeType >> 4; $type = $this->getTType($sizeType); if ($size == 15) { $result += $this->readVarint($size); } $this->containers[] = $this->state; $this->state = TCompactProtocol::STATE_CONTAINER_READ; return $result; } public function readMapBegin(&$key_type, &$val_type, &$size) { $result = $this->readVarint($size); $types = 0; if ($size > 0) { $result += $this->readUByte($types); } $val_type = $this->getTType($types); $key_type = $this->getTType($types >> 4); $this->containers[] = $this->state; $this->state = TCompactProtocol::STATE_CONTAINER_READ; return $result; } public function readCollectionEnd() { $this->state = array_pop($this->containers); return 0; } public function readMapEnd() { return $this->readCollectionEnd(); } public function readListBegin(&$elem_type, &$size) { return $this->readCollectionBegin($elem_type, $size); } public function readListEnd() { return $this->readCollectionEnd(); } public function readSetBegin(&$elem_type, &$size) { return $this->readCollectionBegin($elem_type, $size); } public function readSetEnd() { return $this->readCollectionEnd(); } public function readBool(&$value) { if ($this->state == TCompactProtocol::STATE_BOOL_READ) { $value = $this->boolValue; return 0; } elseif ($this->state == TCompactProtocol::STATE_CONTAINER_READ) { return $this->readByte($value); } else { throw new TProtocolException('Invalid state in compact protocol'); } } public function readI16(&$value) { return $this->readZigZag($value); } public function readI32(&$value) { return $this->readZigZag($value); } public function readDouble(&$value) { $data = $this->trans_->readAll(8); $arr = unpack('d', $data); $value = $arr[1]; return 8; } public function readString(&$value) { $result = $this->readVarint($len); if ($len) { $value = $this->trans_->readAll($len); } else { $value = ''; } return $result + $len; } public function getTType($byte) { return self::$ttypes[$byte & 0x0f]; } // If we are on a 32bit architecture we have to explicitly deal with // 64-bit twos-complement arithmetic since PHP wants to treat all ints // as signed and any int over 2^31 - 1 as a float // Read and write I64 as two 32 bit numbers $hi and $lo public function readI64(&$value) { // Read varint from wire $hi = 0; $lo = 0; $idx = 0; $shift = 0; while (true) { $x = $this->trans_->readAll(1); $arr = unpack('C', $x); $byte = $arr[1]; $idx += 1; // Shift hi and lo together. if ($shift < 28) { $lo |= (($byte & 0x7f) << $shift); } elseif ($shift == 28) { $lo |= (($byte & 0x0f) << 28); $hi |= (($byte & 0x70) >> 4); } else { $hi |= (($byte & 0x7f) << ($shift - 32)); } if (($byte >> 7) === 0) { break; } $shift += 7; } // Now, unzig it. $xorer = 0; if ($lo & 1) { $xorer = 0xffffffff; } $lo = ($lo >> 1) & 0x7fffffff; $lo = $lo | (($hi & 1) << 31); $hi = ($hi >> 1) ^ $xorer; $lo = $lo ^ $xorer; // Now put $hi and $lo back together $isNeg = $hi < 0 || $hi & 0x80000000; // Check for a negative if ($isNeg) { $hi = ~$hi & (int)0xffffffff; $lo = ~$lo & (int)0xffffffff; if ($lo == (int)0xffffffff) { $hi++; $lo = 0; } else { $lo++; } } // Force 32bit words in excess of 2G to be positive - we deal with sign // explicitly below if ($hi & (int)0x80000000) { $hi &= (int)0x7fffffff; $hi += 0x80000000; } if ($lo & (int)0x80000000) { $lo &= (int)0x7fffffff; $lo += 0x80000000; } // Create as negative value first, since we can store -2^63 but not 2^63 $value = -$hi * 4294967296 - $lo; if (!$isNeg) { $value = -$value; } return $idx; } public function writeI64($value) { // If we are in an I32 range, use the easy method below. if (($value > 4294967296) || ($value < -4294967296)) { // Convert $value to $hi and $lo $neg = $value < 0; if ($neg) { $value *= -1; } $hi = (int)$value >> 32; $lo = (int)$value & 0xffffffff; if ($neg) { $hi = ~$hi; $lo = ~$lo; if (($lo & (int)0xffffffff) == (int)0xffffffff) { $lo = 0; $hi++; } else { $lo++; } } // Now do the zigging and zagging. $xorer = 0; if ($neg) { $xorer = 0xffffffff; } $lowbit = ($lo >> 31) & 1; $hi = ($hi << 1) | $lowbit; $lo = ($lo << 1); $lo = ($lo ^ $xorer) & 0xffffffff; $hi = ($hi ^ $xorer) & 0xffffffff; // now write out the varint, ensuring we shift both hi and lo $out = ""; while (true) { if (($lo & ~0x7f) === 0 && $hi === 0) { $out .= chr($lo); break; } else { $out .= chr(($lo & 0xff) | 0x80); $lo = $lo >> 7; $lo = $lo | ($hi << 25); $hi = $hi >> 7; // Right shift carries sign, but we don't want it to. $hi = $hi & (127 << 25); } } $ret = TStringFuncFactory::create()->strlen($out); $this->trans_->write($out, $ret); return $ret; } else { return $this->writeVarint($this->toZigZag($value, 64)); } } } thrift-0.16.0/lib/php/lib/Protocol/TJSONProtocol.php000066400000000000000000000510731420101504100221240ustar00rootroot00000000000000 1) { switch (substr($name, 0, 1)) { case 'd': $result = TType::DOUBLE; break; case 'i': switch (substr($name, 1, 1)) { case '8': $result = TType::BYTE; break; case '1': $result = TType::I16; break; case '3': $result = TType::I32; break; case '6': $result = TType::I64; break; } break; case 'l': $result = TType::LST; break; case 'm': $result = TType::MAP; break; case 'r': $result = TType::STRUCT; break; case 's': if (substr($name, 1, 1) == 't') { $result = TType::STRING; } elseif (substr($name, 1, 1) == 'e') { $result = TType::SET; } break; case 't': $result = TType::BOOL; break; } } if ($result == TType::STOP) { throw new TProtocolException("Unrecognized type", TProtocolException::INVALID_DATA); } return $result; } public $contextStack_ = array(); public $context_; public $reader_; private function pushContext($c) { array_push($this->contextStack_, $this->context_); $this->context_ = $c; } private function popContext() { $this->context_ = array_pop($this->contextStack_); } public function __construct($trans) { parent::__construct($trans); $this->context_ = new BaseContext(); $this->reader_ = new LookaheadReader($this); } public function reset() { $this->contextStack_ = array(); $this->context_ = new BaseContext(); $this->reader_ = new LookaheadReader($this); } private $tmpbuf_ = array(4); public function readJSONSyntaxChar($b) { $ch = $this->reader_->read(); if (substr($ch, 0, 1) != $b) { throw new TProtocolException("Unexpected character: " . $ch, TProtocolException::INVALID_DATA); } } private function hexVal($s) { for ($i = 0; $i < strlen($s); $i++) { $ch = substr($s, $i, 1); if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) { throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA); } } return hexdec($s); } private function hexChar($val) { return dechex($val); } private function hasJSONUnescapedUnicode() { if (PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4)) { return true; } return false; } private function unescapedUnicode($str) { if ($this->hasJSONUnescapedUnicode()) { return json_encode($str, JSON_UNESCAPED_UNICODE); } $json = json_encode($str); /* * Unescaped character outside the Basic Multilingual Plane * High surrogate: 0xD800 - 0xDBFF * Low surrogate: 0xDC00 - 0xDFFF */ $json = preg_replace_callback( '/\\\\u(d[89ab][0-9a-f]{2})\\\\u(d[cdef][0-9a-f]{2})/i', function ($matches) { return mb_convert_encoding(pack('H*', $matches[1] . $matches[2]), 'UTF-8', 'UTF-16BE'); }, $json ); /* * Unescaped characters within the Basic Multilingual Plane */ $json = preg_replace_callback( '/\\\\u([0-9a-f]{4})/i', function ($matches) { return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE'); }, $json ); return $json; } private function writeJSONString($b) { $this->context_->write(); if (is_numeric($b) && $this->context_->escapeNum()) { $this->trans_->write(self::QUOTE); } $this->trans_->write($this->unescapedUnicode($b)); if (is_numeric($b) && $this->context_->escapeNum()) { $this->trans_->write(self::QUOTE); } } private function writeJSONInteger($num) { $this->context_->write(); if ($this->context_->escapeNum()) { $this->trans_->write(self::QUOTE); } $this->trans_->write($num); if ($this->context_->escapeNum()) { $this->trans_->write(self::QUOTE); } } private function writeJSONDouble($num) { $this->context_->write(); if ($this->context_->escapeNum()) { $this->trans_->write(self::QUOTE); } $this->trans_->write(json_encode($num)); if ($this->context_->escapeNum()) { $this->trans_->write(self::QUOTE); } } private function writeJSONBase64($data) { $this->context_->write(); $this->trans_->write(self::QUOTE); $this->trans_->write(json_encode(base64_encode($data))); $this->trans_->write(self::QUOTE); } private function writeJSONObjectStart() { $this->context_->write(); $this->trans_->write(self::LBRACE); $this->pushContext(new PairContext($this)); } private function writeJSONObjectEnd() { $this->popContext(); $this->trans_->write(self::RBRACE); } private function writeJSONArrayStart() { $this->context_->write(); $this->trans_->write(self::LBRACKET); $this->pushContext(new ListContext($this)); } private function writeJSONArrayEnd() { $this->popContext(); $this->trans_->write(self::RBRACKET); } private function readJSONString($skipContext) { if (!$skipContext) { $this->context_->read(); } $jsonString = ''; $lastChar = null; while (true) { $ch = $this->reader_->read(); $jsonString .= $ch; if ($ch == self::QUOTE && $lastChar !== null && $lastChar !== self::ESCSEQ) { break; } if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) { $lastChar = self::DOUBLEESC; } else { $lastChar = $ch; } } return json_decode($jsonString); } private function isJSONNumeric($b) { switch ($b) { case '+': case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'E': case 'e': return true; } return false; } private function readJSONNumericChars() { $strbld = array(); while (true) { $ch = $this->reader_->peek(); if (!$this->isJSONNumeric($ch)) { break; } $strbld[] = $this->reader_->read(); } return implode("", $strbld); } private function readJSONInteger() { $this->context_->read(); if ($this->context_->escapeNum()) { $this->readJSONSyntaxChar(self::QUOTE); } $str = $this->readJSONNumericChars(); if ($this->context_->escapeNum()) { $this->readJSONSyntaxChar(self::QUOTE); } if (!is_numeric($str)) { throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); } return intval($str); } /** * Identical to readJSONInteger but without the final cast. * Needed for proper handling of i64 on 32 bit machines. Why a * separate function? So we don't have to force the rest of the * use cases through the extra conditional. */ private function readJSONIntegerAsString() { $this->context_->read(); if ($this->context_->escapeNum()) { $this->readJSONSyntaxChar(self::QUOTE); } $str = $this->readJSONNumericChars(); if ($this->context_->escapeNum()) { $this->readJSONSyntaxChar(self::QUOTE); } if (!is_numeric($str)) { throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); } return $str; } private function readJSONDouble() { $this->context_->read(); if (substr($this->reader_->peek(), 0, 1) == self::QUOTE) { $arr = $this->readJSONString(true); if ($arr == "NaN") { return NAN; } elseif ($arr == "Infinity") { return INF; } elseif (!$this->context_->escapeNum()) { throw new TProtocolException( "Numeric data unexpectedly quoted " . $arr, TProtocolException::INVALID_DATA ); } return floatval($arr); } else { if ($this->context_->escapeNum()) { $this->readJSONSyntaxChar(self::QUOTE); } return floatval($this->readJSONNumericChars()); } } private function readJSONBase64() { $arr = $this->readJSONString(false); $data = base64_decode($arr, true); if ($data === false) { throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA); } return $data; } private function readJSONObjectStart() { $this->context_->read(); $this->readJSONSyntaxChar(self::LBRACE); $this->pushContext(new PairContext($this)); } private function readJSONObjectEnd() { $this->readJSONSyntaxChar(self::RBRACE); $this->popContext(); } private function readJSONArrayStart() { $this->context_->read(); $this->readJSONSyntaxChar(self::LBRACKET); $this->pushContext(new ListContext($this)); } private function readJSONArrayEnd() { $this->readJSONSyntaxChar(self::RBRACKET); $this->popContext(); } /** * Writes the message header * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @param int $seqid The sequence id of this message */ public function writeMessageBegin($name, $type, $seqid) { $this->writeJSONArrayStart(); $this->writeJSONInteger(self::VERSION); $this->writeJSONString($name); $this->writeJSONInteger($type); $this->writeJSONInteger($seqid); } /** * Close the message */ public function writeMessageEnd() { $this->writeJSONArrayEnd(); } /** * Writes a struct header. * * @param string $name Struct name * @throws TException on write error * @return int How many bytes written */ public function writeStructBegin($name) { $this->writeJSONObjectStart(); } /** * Close a struct. * * @throws TException on write error * @return int How many bytes written */ public function writeStructEnd() { $this->writeJSONObjectEnd(); } public function writeFieldBegin($fieldName, $fieldType, $fieldId) { $this->writeJSONInteger($fieldId); $this->writeJSONObjectStart(); $this->writeJSONString($this->getTypeNameForTypeID($fieldType)); } public function writeFieldEnd() { $this->writeJsonObjectEnd(); } public function writeFieldStop() { } public function writeMapBegin($keyType, $valType, $size) { $this->writeJSONArrayStart(); $this->writeJSONString($this->getTypeNameForTypeID($keyType)); $this->writeJSONString($this->getTypeNameForTypeID($valType)); $this->writeJSONInteger($size); $this->writeJSONObjectStart(); } public function writeMapEnd() { $this->writeJSONObjectEnd(); $this->writeJSONArrayEnd(); } public function writeListBegin($elemType, $size) { $this->writeJSONArrayStart(); $this->writeJSONString($this->getTypeNameForTypeID($elemType)); $this->writeJSONInteger($size); } public function writeListEnd() { $this->writeJSONArrayEnd(); } public function writeSetBegin($elemType, $size) { $this->writeJSONArrayStart(); $this->writeJSONString($this->getTypeNameForTypeID($elemType)); $this->writeJSONInteger($size); } public function writeSetEnd() { $this->writeJSONArrayEnd(); } public function writeBool($bool) { $this->writeJSONInteger($bool ? 1 : 0); } public function writeByte($byte) { $this->writeJSONInteger($byte); } public function writeI16($i16) { $this->writeJSONInteger($i16); } public function writeI32($i32) { $this->writeJSONInteger($i32); } public function writeI64($i64) { $this->writeJSONInteger($i64); } public function writeDouble($dub) { $this->writeJSONDouble($dub); } public function writeString($str) { $this->writeJSONString($str); } /** * Reads the message header * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @parem int $seqid The sequence id of this message */ public function readMessageBegin(&$name, &$type, &$seqid) { $this->readJSONArrayStart(); if ($this->readJSONInteger() != self::VERSION) { throw new TProtocolException("Message contained bad version", TProtocolException::BAD_VERSION); } $name = $this->readJSONString(false); $type = $this->readJSONInteger(); $seqid = $this->readJSONInteger(); return true; } /** * Read the close of message */ public function readMessageEnd() { $this->readJSONArrayEnd(); } public function readStructBegin(&$name) { $this->readJSONObjectStart(); return 0; } public function readStructEnd() { $this->readJSONObjectEnd(); } public function readFieldBegin(&$name, &$fieldType, &$fieldId) { $ch = $this->reader_->peek(); $name = ""; if (substr($ch, 0, 1) == self::RBRACE) { $fieldType = TType::STOP; } else { $fieldId = $this->readJSONInteger(); $this->readJSONObjectStart(); $fieldType = $this->getTypeIDForTypeName($this->readJSONString(false)); } } public function readFieldEnd() { $this->readJSONObjectEnd(); } public function readMapBegin(&$keyType, &$valType, &$size) { $this->readJSONArrayStart(); $keyType = $this->getTypeIDForTypeName($this->readJSONString(false)); $valType = $this->getTypeIDForTypeName($this->readJSONString(false)); $size = $this->readJSONInteger(); $this->readJSONObjectStart(); } public function readMapEnd() { $this->readJSONObjectEnd(); $this->readJSONArrayEnd(); } public function readListBegin(&$elemType, &$size) { $this->readJSONArrayStart(); $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); $size = $this->readJSONInteger(); return true; } public function readListEnd() { $this->readJSONArrayEnd(); } public function readSetBegin(&$elemType, &$size) { $this->readJSONArrayStart(); $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); $size = $this->readJSONInteger(); return true; } public function readSetEnd() { $this->readJSONArrayEnd(); } public function readBool(&$bool) { $bool = $this->readJSONInteger() == 0 ? false : true; return true; } public function readByte(&$byte) { $byte = $this->readJSONInteger(); return true; } public function readI16(&$i16) { $i16 = $this->readJSONInteger(); return true; } public function readI32(&$i32) { $i32 = $this->readJSONInteger(); return true; } public function readI64(&$i64) { if (PHP_INT_SIZE === 4) { $i64 = $this->readJSONIntegerAsString(); } else { $i64 = $this->readJSONInteger(); } return true; } public function readDouble(&$dub) { $dub = $this->readJSONDouble(); return true; } public function readString(&$str) { $str = $this->readJSONString(false); return true; } } thrift-0.16.0/lib/php/lib/Protocol/TMultiplexedProtocol.php000066400000000000000000000054671420101504100236550ustar00rootroot00000000000000TMultiplexedProtocol is a protocol-independent concrete decorator * that allows a Thrift client to communicate with a multiplexing Thrift server, * by prepending the service name to the function name during function calls. * * @package Thrift\Protocol */ class TMultiplexedProtocol extends TProtocolDecorator { /** * Separator between service name and function name. * Should be the same as used at multiplexed Thrift server. * * @var string */ const SEPARATOR = ":"; /** * The name of service. * * @var string */ private $serviceName_; /** * Constructor of TMultiplexedProtocol class. * * Wrap the specified protocol, allowing it to be used to communicate with a * multiplexing server. The $serviceName is required as it is * prepended to the message header so that the multiplexing server can broker * the function call to the proper service. * * @param TProtocol $protocol * @param string $serviceName The name of service. */ public function __construct(TProtocol $protocol, $serviceName) { parent::__construct($protocol); $this->serviceName_ = $serviceName; } /** * Writes the message header. * Prepends the service name to the function name, separated by TMultiplexedProtocol::SEPARATOR. * * @param string $name Function name. * @param int $type Message type. * @param int $seqid The sequence id of this message. */ public function writeMessageBegin($name, $type, $seqid) { if ($type == TMessageType::CALL || $type == TMessageType::ONEWAY) { $nameWithService = $this->serviceName_ . self::SEPARATOR . $name; parent::writeMessageBegin($nameWithService, $type, $seqid); } else { parent::writeMessageBegin($name, $type, $seqid); } } } thrift-0.16.0/lib/php/lib/Protocol/TProtocol.php000066400000000000000000000242151420101504100214300ustar00rootroot00000000000000trans_ = $trans; } /** * Accessor for transport * * @return TTransport */ public function getTransport() { return $this->trans_; } /** * Writes the message header * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @param int $seqid The sequence id of this message */ abstract public function writeMessageBegin($name, $type, $seqid); /** * Close the message */ abstract public function writeMessageEnd(); /** * Writes a struct header. * * @param string $name Struct name * @throws TException on write error * @return int How many bytes written */ abstract public function writeStructBegin($name); /** * Close a struct. * * @throws TException on write error * @return int How many bytes written */ abstract public function writeStructEnd(); /* * Starts a field. * * @param string $name Field name * @param int $type Field type * @param int $fid Field id * @throws TException on write error * @return int How many bytes written */ abstract public function writeFieldBegin($fieldName, $fieldType, $fieldId); abstract public function writeFieldEnd(); abstract public function writeFieldStop(); abstract public function writeMapBegin($keyType, $valType, $size); abstract public function writeMapEnd(); abstract public function writeListBegin($elemType, $size); abstract public function writeListEnd(); abstract public function writeSetBegin($elemType, $size); abstract public function writeSetEnd(); abstract public function writeBool($bool); abstract public function writeByte($byte); abstract public function writeI16($i16); abstract public function writeI32($i32); abstract public function writeI64($i64); abstract public function writeDouble($dub); abstract public function writeString($str); /** * Reads the message header * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @parem int $seqid The sequence id of this message */ abstract public function readMessageBegin(&$name, &$type, &$seqid); /** * Read the close of message */ abstract public function readMessageEnd(); abstract public function readStructBegin(&$name); abstract public function readStructEnd(); abstract public function readFieldBegin(&$name, &$fieldType, &$fieldId); abstract public function readFieldEnd(); abstract public function readMapBegin(&$keyType, &$valType, &$size); abstract public function readMapEnd(); abstract public function readListBegin(&$elemType, &$size); abstract public function readListEnd(); abstract public function readSetBegin(&$elemType, &$size); abstract public function readSetEnd(); abstract public function readBool(&$bool); abstract public function readByte(&$byte); abstract public function readI16(&$i16); abstract public function readI32(&$i32); abstract public function readI64(&$i64); abstract public function readDouble(&$dub); abstract public function readString(&$str); /** * The skip function is a utility to parse over unrecognized date without * causing corruption. * * @param TType $type What type is it */ public function skip($type) { switch ($type) { case TType::BOOL: return $this->readBool($bool); case TType::BYTE: return $this->readByte($byte); case TType::I16: return $this->readI16($i16); case TType::I32: return $this->readI32($i32); case TType::I64: return $this->readI64($i64); case TType::DOUBLE: return $this->readDouble($dub); case TType::STRING: return $this->readString($str); case TType::STRUCT: $result = $this->readStructBegin($name); while (true) { $result += $this->readFieldBegin($name, $ftype, $fid); if ($ftype == TType::STOP) { break; } $result += $this->skip($ftype); $result += $this->readFieldEnd(); } $result += $this->readStructEnd(); return $result; case TType::MAP: $result = $this->readMapBegin($keyType, $valType, $size); for ($i = 0; $i < $size; $i++) { $result += $this->skip($keyType); $result += $this->skip($valType); } $result += $this->readMapEnd(); return $result; case TType::SET: $result = $this->readSetBegin($elemType, $size); for ($i = 0; $i < $size; $i++) { $result += $this->skip($elemType); } $result += $this->readSetEnd(); return $result; case TType::LST: $result = $this->readListBegin($elemType, $size); for ($i = 0; $i < $size; $i++) { $result += $this->skip($elemType); } $result += $this->readListEnd(); return $result; default: throw new TProtocolException( 'Unknown field type: ' . $type, TProtocolException::INVALID_DATA ); } } /** * Utility for skipping binary data * * @param TTransport $itrans TTransport object * @param int $type Field type */ public static function skipBinary($itrans, $type) { switch ($type) { case TType::BOOL: return $itrans->readAll(1); case TType::BYTE: return $itrans->readAll(1); case TType::I16: return $itrans->readAll(2); case TType::I32: return $itrans->readAll(4); case TType::I64: return $itrans->readAll(8); case TType::DOUBLE: return $itrans->readAll(8); case TType::STRING: $len = unpack('N', $itrans->readAll(4)); $len = $len[1]; if ($len > 0x7fffffff) { $len = 0 - (($len - 1) ^ 0xffffffff); } return 4 + $itrans->readAll($len); case TType::STRUCT: $result = 0; while (true) { $ftype = 0; $fid = 0; $data = $itrans->readAll(1); $arr = unpack('c', $data); $ftype = $arr[1]; if ($ftype == TType::STOP) { break; } // I16 field id $result += $itrans->readAll(2); $result += self::skipBinary($itrans, $ftype); } return $result; case TType::MAP: // Ktype $data = $itrans->readAll(1); $arr = unpack('c', $data); $ktype = $arr[1]; // Vtype $data = $itrans->readAll(1); $arr = unpack('c', $data); $vtype = $arr[1]; // Size $data = $itrans->readAll(4); $arr = unpack('N', $data); $size = $arr[1]; if ($size > 0x7fffffff) { $size = 0 - (($size - 1) ^ 0xffffffff); } $result = 6; for ($i = 0; $i < $size; $i++) { $result += self::skipBinary($itrans, $ktype); $result += self::skipBinary($itrans, $vtype); } return $result; case TType::SET: case TType::LST: // Vtype $data = $itrans->readAll(1); $arr = unpack('c', $data); $vtype = $arr[1]; // Size $data = $itrans->readAll(4); $arr = unpack('N', $data); $size = $arr[1]; if ($size > 0x7fffffff) { $size = 0 - (($size - 1) ^ 0xffffffff); } $result = 5; for ($i = 0; $i < $size; $i++) { $result += self::skipBinary($itrans, $vtype); } return $result; default: throw new TProtocolException( 'Unknown field type: ' . $type, TProtocolException::INVALID_DATA ); } } } thrift-0.16.0/lib/php/lib/Protocol/TProtocolDecorator.php000066400000000000000000000163731420101504100233010ustar00rootroot00000000000000TProtocolDecorator forwards all requests to an enclosed * TProtocol instance, providing a way to author concise * concrete decorator subclasses. While it has no abstract methods, it * is marked abstract as a reminder that by itself, it does not modify * the behaviour of the enclosed TProtocol. * * @package Thrift\Protocol */ abstract class TProtocolDecorator extends TProtocol { /** * Instance of protocol, to which all operations will be forwarded. * * @var TProtocol */ private $concreteProtocol_; /** * Constructor of TProtocolDecorator class. * Encloses the specified protocol. * * @param TProtocol $protocol All operations will be forward to this instance. Must be non-null. */ protected function __construct(TProtocol $protocol) { parent::__construct($protocol->getTransport()); $this->concreteProtocol_ = $protocol; } /** * Writes the message header. * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @param int $seqid The sequence id of this message */ public function writeMessageBegin($name, $type, $seqid) { return $this->concreteProtocol_->writeMessageBegin($name, $type, $seqid); } /** * Closes the message. */ public function writeMessageEnd() { return $this->concreteProtocol_->writeMessageEnd(); } /** * Writes a struct header. * * @param string $name Struct name * * @throws TException on write error * @return int How many bytes written */ public function writeStructBegin($name) { return $this->concreteProtocol_->writeStructBegin($name); } /** * Close a struct. * * @throws TException on write error * @return int How many bytes written */ public function writeStructEnd() { return $this->concreteProtocol_->writeStructEnd(); } public function writeFieldBegin($fieldName, $fieldType, $fieldId) { return $this->concreteProtocol_->writeFieldBegin($fieldName, $fieldType, $fieldId); } public function writeFieldEnd() { return $this->concreteProtocol_->writeFieldEnd(); } public function writeFieldStop() { return $this->concreteProtocol_->writeFieldStop(); } public function writeMapBegin($keyType, $valType, $size) { return $this->concreteProtocol_->writeMapBegin($keyType, $valType, $size); } public function writeMapEnd() { return $this->concreteProtocol_->writeMapEnd(); } public function writeListBegin($elemType, $size) { return $this->concreteProtocol_->writeListBegin($elemType, $size); } public function writeListEnd() { return $this->concreteProtocol_->writeListEnd(); } public function writeSetBegin($elemType, $size) { return $this->concreteProtocol_->writeSetBegin($elemType, $size); } public function writeSetEnd() { return $this->concreteProtocol_->writeSetEnd(); } public function writeBool($bool) { return $this->concreteProtocol_->writeBool($bool); } public function writeByte($byte) { return $this->concreteProtocol_->writeByte($byte); } public function writeI16($i16) { return $this->concreteProtocol_->writeI16($i16); } public function writeI32($i32) { return $this->concreteProtocol_->writeI32($i32); } public function writeI64($i64) { return $this->concreteProtocol_->writeI64($i64); } public function writeDouble($dub) { return $this->concreteProtocol_->writeDouble($dub); } public function writeString($str) { return $this->concreteProtocol_->writeString($str); } /** * Reads the message header * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @param int $seqid The sequence id of this message */ public function readMessageBegin(&$name, &$type, &$seqid) { return $this->concreteProtocol_->readMessageBegin($name, $type, $seqid); } /** * Read the close of message */ public function readMessageEnd() { return $this->concreteProtocol_->readMessageEnd(); } public function readStructBegin(&$name) { return $this->concreteProtocol_->readStructBegin($name); } public function readStructEnd() { return $this->concreteProtocol_->readStructEnd(); } public function readFieldBegin(&$name, &$fieldType, &$fieldId) { return $this->concreteProtocol_->readFieldBegin($name, $fieldType, $fieldId); } public function readFieldEnd() { return $this->concreteProtocol_->readFieldEnd(); } public function readMapBegin(&$keyType, &$valType, &$size) { $this->concreteProtocol_->readMapBegin($keyType, $valType, $size); } public function readMapEnd() { return $this->concreteProtocol_->readMapEnd(); } public function readListBegin(&$elemType, &$size) { $this->concreteProtocol_->readListBegin($elemType, $size); } public function readListEnd() { return $this->concreteProtocol_->readListEnd(); } public function readSetBegin(&$elemType, &$size) { return $this->concreteProtocol_->readSetBegin($elemType, $size); } public function readSetEnd() { return $this->concreteProtocol_->readSetEnd(); } public function readBool(&$bool) { return $this->concreteProtocol_->readBool($bool); } public function readByte(&$byte) { return $this->concreteProtocol_->readByte($byte); } public function readI16(&$i16) { return $this->concreteProtocol_->readI16($i16); } public function readI32(&$i32) { return $this->concreteProtocol_->readI32($i32); } public function readI64(&$i64) { return $this->concreteProtocol_->readI64($i64); } public function readDouble(&$dub) { return $this->concreteProtocol_->readDouble($dub); } public function readString(&$str) { return $this->concreteProtocol_->readString($str); } } thrift-0.16.0/lib/php/lib/Protocol/TSimpleJSONProtocol.php000066400000000000000000000213431420101504100232730ustar00rootroot00000000000000writeContextStack_[] = $this->writeContext_; $this->writeContext_ = $c; } /** * Pop the last write context off the stack */ protected function popWriteContext() { $this->writeContext_ = array_pop($this->writeContextStack_); } /** * Used to make sure that we are not encountering a map whose keys are containers */ protected function assertContextIsNotMapKey($invalidKeyType) { if ($this->writeContext_->isMapKey()) { throw new CollectionMapKeyException( "Cannot serialize a map with keys that are of type " . $invalidKeyType ); } } private function writeJSONString($b) { $this->writeContext_->write(); $this->trans_->write(json_encode((string)$b)); } private function writeJSONInteger($num) { $isMapKey = $this->writeContext_->isMapKey(); $this->writeContext_->write(); if ($isMapKey) { $this->trans_->write(self::QUOTE); } $this->trans_->write((int)$num); if ($isMapKey) { $this->trans_->write(self::QUOTE); } } private function writeJSONDouble($num) { $isMapKey = $this->writeContext_->isMapKey(); $this->writeContext_->write(); if ($isMapKey) { $this->trans_->write(self::QUOTE); } $this->trans_->write(json_encode((float)$num)); if ($isMapKey) { $this->trans_->write(self::QUOTE); } } /** * Constructor */ public function __construct($trans) { parent::__construct($trans); $this->writeContext_ = new Context(); } /** * Writes the message header * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @param int $seqid The sequence id of this message */ public function writeMessageBegin($name, $type, $seqid) { $this->trans_->write(self::LBRACKET); $this->pushWriteContext(new ListContext($this)); $this->writeJSONString($name); $this->writeJSONInteger($type); $this->writeJSONInteger($seqid); } /** * Close the message */ public function writeMessageEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACKET); } /** * Writes a struct header. * * @param string $name Struct name */ public function writeStructBegin($name) { $this->writeContext_->write(); $this->trans_->write(self::LBRACE); $this->pushWriteContext(new StructContext($this)); } /** * Close a struct. */ public function writeStructEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACE); } public function writeFieldBegin($fieldName, $fieldType, $fieldId) { $this->writeJSONString($fieldName); } public function writeFieldEnd() { } public function writeFieldStop() { } public function writeMapBegin($keyType, $valType, $size) { $this->assertContextIsNotMapKey(self::NAME_MAP); $this->writeContext_->write(); $this->trans_->write(self::LBRACE); $this->pushWriteContext(new MapContext($this)); } public function writeMapEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACE); } public function writeListBegin($elemType, $size) { $this->assertContextIsNotMapKey(self::NAME_LIST); $this->writeContext_->write(); $this->trans_->write(self::LBRACKET); $this->pushWriteContext(new ListContext($this)); // No metadata! } public function writeListEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACKET); } public function writeSetBegin($elemType, $size) { $this->assertContextIsNotMapKey(self::NAME_SET); $this->writeContext_->write(); $this->trans_->write(self::LBRACKET); $this->pushWriteContext(new ListContext($this)); // No metadata! } public function writeSetEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACKET); } public function writeBool($bool) { $this->writeJSONInteger($bool ? 1 : 0); } public function writeByte($byte) { $this->writeJSONInteger($byte); } public function writeI16($i16) { $this->writeJSONInteger($i16); } public function writeI32($i32) { $this->writeJSONInteger($i32); } public function writeI64($i64) { $this->writeJSONInteger($i64); } public function writeDouble($dub) { $this->writeJSONDouble($dub); } public function writeString($str) { $this->writeJSONString($str); } /** * Reading methods. * * simplejson is not meant to be read back into thrift * - see http://wiki.apache.org/thrift/ThriftUsageJava * - use JSON instead */ public function readMessageBegin(&$name, &$type, &$seqid) { throw new TException("Not implemented"); } public function readMessageEnd() { throw new TException("Not implemented"); } public function readStructBegin(&$name) { throw new TException("Not implemented"); } public function readStructEnd() { throw new TException("Not implemented"); } public function readFieldBegin(&$name, &$fieldType, &$fieldId) { throw new TException("Not implemented"); } public function readFieldEnd() { throw new TException("Not implemented"); } public function readMapBegin(&$keyType, &$valType, &$size) { throw new TException("Not implemented"); } public function readMapEnd() { throw new TException("Not implemented"); } public function readListBegin(&$elemType, &$size) { throw new TException("Not implemented"); } public function readListEnd() { throw new TException("Not implemented"); } public function readSetBegin(&$elemType, &$size) { throw new TException("Not implemented"); } public function readSetEnd() { throw new TException("Not implemented"); } public function readBool(&$bool) { throw new TException("Not implemented"); } public function readByte(&$byte) { throw new TException("Not implemented"); } public function readI16(&$i16) { throw new TException("Not implemented"); } public function readI32(&$i32) { throw new TException("Not implemented"); } public function readI64(&$i64) { throw new TException("Not implemented"); } public function readDouble(&$dub) { throw new TException("Not implemented"); } public function readString(&$str) { throw new TException("Not implemented"); } } thrift-0.16.0/lib/php/lib/Serializer/000077500000000000000000000000001420101504100172765ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Serializer/TBinarySerializer.php000066400000000000000000000062731420101504100234210ustar00rootroot00000000000000getName(), TMessageType::REPLY, $object, 0, $protocol->isStrictWrite() ); $protocol->readMessageBegin($unused_name, $unused_type, $unused_seqid); } else { $object->write($protocol); } $protocol->getTransport()->flush(); return $transport->getBuffer(); } public static function deserialize($string_object, $class_name, $buffer_size = 8192) { $transport = new TMemoryBuffer(); $protocol = new TBinaryProtocolAccelerated($transport); if (function_exists('thrift_protocol_read_binary')) { // NOTE (t.heintz) TBinaryProtocolAccelerated internally wraps our TMemoryBuffer in a // TBufferedTransport, so we have to retrieve it again or risk losing data when writing // less than 512 bytes to the transport (see the comment there as well). // @see THRIFT-1579 $protocol->writeMessageBegin('', TMessageType::REPLY, 0); $protocolTransport = $protocol->getTransport(); $protocolTransport->write($string_object); $protocolTransport->flush(); return thrift_protocol_read_binary($protocol, $class_name, $protocol->isStrictRead(), $buffer_size); } else { $transport->write($string_object); $object = new $class_name(); $object->read($protocol); return $object; } } } thrift-0.16.0/lib/php/lib/Server/000077500000000000000000000000001420101504100164335ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Server/TForkingServer.php000066400000000000000000000057101420101504100220610ustar00rootroot00000000000000transport_->listen(); while (!$this->stop_) { try { $transport = $this->transport_->accept(); if ($transport != null) { $pid = pcntl_fork(); if ($pid > 0) { $this->handleParent($transport, $pid); } elseif ($pid === 0) { $this->handleChild($transport); } else { throw new TException('Failed to fork'); } } } catch (TTransportException $e) { } $this->collectChildren(); } } /** * Code run by the parent * * @param TTransport $transport * @param int $pid * @return void */ private function handleParent(TTransport $transport, $pid) { $this->children_[$pid] = $transport; } /** * Code run by the child. * * @param TTransport $transport * @return void */ private function handleChild(TTransport $transport) { try { $inputTransport = $this->inputTransportFactory_->getTransport($transport); $outputTransport = $this->outputTransportFactory_->getTransport($transport); $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); while ($this->processor_->process($inputProtocol, $outputProtocol)) { } @$transport->close(); } catch (TTransportException $e) { } exit(0); } /** * Collects any children we may have * * @return void */ private function collectChildren() { foreach ($this->children_ as $pid => $transport) { if (pcntl_waitpid($pid, $status, WNOHANG) > 0) { unset($this->children_[$pid]); if ($transport) { @$transport->close(); } } } } /** * Stops the server running. Kills the transport * and then stops the main serving loop * * @return void */ public function stop() { $this->transport_->close(); $this->stop_ = true; } } thrift-0.16.0/lib/php/lib/Server/TSSLServerSocket.php000066400000000000000000000047551420101504100223040ustar00rootroot00000000000000getSSLHost($host); parent::__construct($ssl_host, $port); $this->context_ = $context; } public function getSSLHost($host) { $transport_protocol_loc = strpos($host, "://"); if ($transport_protocol_loc === false) { $host = 'ssl://' . $host; } return $host; } /** * Opens a new socket server handle * * @return void */ public function listen() { $this->listener_ = @stream_socket_server( $this->host_ . ':' . $this->port_, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $this->context_ ); } /** * Implementation of accept. If not client is accepted in the given time * * @return TSocket */ protected function acceptImpl() { $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0); if (!$handle) { return null; } $socket = new TSSLSocket(); $socket->setHandle($handle); return $socket; } } thrift-0.16.0/lib/php/lib/Server/TServer.php000066400000000000000000000044641420101504100205460ustar00rootroot00000000000000processor_ = $processor; $this->transport_ = $transport; $this->inputTransportFactory_ = $inputTransportFactory; $this->outputTransportFactory_ = $outputTransportFactory; $this->inputProtocolFactory_ = $inputProtocolFactory; $this->outputProtocolFactory_ = $outputProtocolFactory; } /** * Serves the server. This should never return * unless a problem permits it to do so or it * is interrupted intentionally * * @abstract * @return void */ abstract public function serve(); /** * Stops the server serving * * @abstract * @return void */ abstract public function stop(); } thrift-0.16.0/lib/php/lib/Server/TServerSocket.php000066400000000000000000000053751420101504100217210ustar00rootroot00000000000000host_ = $host; $this->port_ = $port; } /** * Sets the accept timeout * * @param int $acceptTimeout * @return void */ public function setAcceptTimeout($acceptTimeout) { $this->acceptTimeout_ = $acceptTimeout; } /** * Opens a new socket server handle * * @return void */ public function listen() { $this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_); } /** * Closes the socket server handle * * @return void */ public function close() { @fclose($this->listener_); $this->listener_ = null; } /** * Implementation of accept. If not client is accepted in the given time * * @return TSocket */ protected function acceptImpl() { $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0); if (!$handle) { return null; } $socket = new TSocket(); $socket->setHandle($handle); return $socket; } } thrift-0.16.0/lib/php/lib/Server/TServerTransport.php000066400000000000000000000017711420101504100224610ustar00rootroot00000000000000acceptImpl(); if ($transport == null) { throw new TTransportException("accept() may not return NULL"); } return $transport; } } thrift-0.16.0/lib/php/lib/Server/TSimpleServer.php000066400000000000000000000030151420101504100217070ustar00rootroot00000000000000transport_->listen(); while (!$this->stop_) { try { $transport = $this->transport_->accept(); if ($transport != null) { $inputTransport = $this->inputTransportFactory_->getTransport($transport); $outputTransport = $this->outputTransportFactory_->getTransport($transport); $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); while ($this->processor_->process($inputProtocol, $outputProtocol)) { } } } catch (TTransportException $e) { } } } /** * Stops the server running. Kills the transport * and then stops the main serving loop * * @return void */ public function stop() { $this->transport_->close(); $this->stop_ = true; } } thrift-0.16.0/lib/php/lib/StoredMessageProtocol.php000066400000000000000000000032441420101504100221700ustar00rootroot00000000000000fname_ = $fname; $this->mtype_ = $mtype; $this->rseqid_ = $rseqid; } public function readMessageBegin(&$name, &$type, &$seqid) { $name = $this->fname_; $type = $this->mtype_; $seqid = $this->rseqid_; } } thrift-0.16.0/lib/php/lib/StringFunc/000077500000000000000000000000001420101504100172475ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/StringFunc/Core.php000066400000000000000000000023061420101504100206510ustar00rootroot00000000000000strlen($str) - $start; } return mb_substr($str, $start, $length, '8bit'); } public function strlen($str) { return mb_strlen($str, '8bit'); } } thrift-0.16.0/lib/php/lib/StringFunc/TStringFunc.php000066400000000000000000000017021420101504100221660ustar00rootroot00000000000000TMultiplexedProcessor is a Processor allowing * a single TServer to provide multiple services. * *

To do so, you instantiate the processor and then register additional * processors with it, as shown in the following example:

* *
* $processor = new TMultiplexedProcessor(); * * processor->registerProcessor( * "Calculator", * new \tutorial\CalculatorProcessor(new CalculatorHandler())); * * processor->registerProcessor( * "WeatherReport", * new \tutorial\WeatherReportProcessor(new WeatherReportHandler())); * * $processor->process($protocol, $protocol); *
*/ class TMultiplexedProcessor { private $serviceProcessorMap_; /** * 'Register' a service with this TMultiplexedProcessor. This * allows us to broker requests to individual services by using the service * name to select them at request time. * * @param serviceName Name of a service, has to be identical to the name * declared in the Thrift IDL, e.g. "WeatherReport". * @param processor Implementation of a service, usually referred to * as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface. */ public function registerProcessor($serviceName, $processor) { $this->serviceProcessorMap_[$serviceName] = $processor; } /** * This implementation of process performs the following steps: * *
    *
  1. Read the beginning of the message.
  2. *
  3. Extract the service name from the message.
  4. *
  5. Using the service name to locate the appropriate processor.
  6. *
  7. Dispatch to the processor, with a decorated instance of TProtocol * that allows readMessageBegin() to return the original Message.
  8. *
* * @throws TException If the message type is not CALL or ONEWAY, if * the service name was not found in the message, or if the service * name was not found in the service map. */ public function process(TProtocol $input, TProtocol $output) { /* Use the actual underlying protocol (e.g. TBinaryProtocol) to read the message header. This pulls the message "off the wire", which we'll deal with at the end of this method. */ $input->readMessageBegin($fname, $mtype, $rseqid); if ($mtype !== TMessageType::CALL && $mtype != TMessageType::ONEWAY) { throw new TException("This should not have happened!?"); } // Extract the service name and the new Message name. if (strpos($fname, TMultiplexedProtocol::SEPARATOR) === false) { throw new TException("Service name not found in message name: {$fname}. Did you " . "forget to use a TMultiplexProtocol in your client?"); } list($serviceName, $messageName) = explode(':', $fname, 2); if (!array_key_exists($serviceName, $this->serviceProcessorMap_)) { throw new TException("Service name not found: {$serviceName}. Did you forget " . "to call registerProcessor()?"); } // Dispatch processing to the stored processor $processor = $this->serviceProcessorMap_[$serviceName]; return $processor->process( new StoredMessageProtocol($input, $messageName, $mtype, $rseqid), $output ); } } thrift-0.16.0/lib/php/lib/Transport/000077500000000000000000000000001420101504100171615ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Transport/TBufferedTransport.php000066400000000000000000000127301420101504100234600ustar00rootroot00000000000000transport_ = $transport; $this->rBufSize_ = $rBufSize; $this->wBufSize_ = $wBufSize; } public function isOpen() { return $this->transport_->isOpen(); } /** * @inheritdoc * * @throws TTransportException */ public function open() { $this->transport_->open(); } public function close() { $this->transport_->close(); } public function putBack($data) { if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->rBuf_ = $data; } else { $this->rBuf_ = ($data . $this->rBuf_); } } /** * The reason that we customize readAll here is that the majority of PHP * streams are already internally buffered by PHP. The socket stream, for * example, buffers internally and blocks if you call read with $len greater * than the amount of data available, unlike recv() in C. * * Therefore, use the readAll method of the wrapped transport inside * the buffered readAll. * * @throws TTransportException */ public function readAll($len) { $have = TStringFuncFactory::create()->strlen($this->rBuf_); if ($have == 0) { $data = $this->transport_->readAll($len); } elseif ($have < $len) { $data = $this->rBuf_; $this->rBuf_ = ''; $data .= $this->transport_->readAll($len - $have); } elseif ($have == $len) { $data = $this->rBuf_; $this->rBuf_ = ''; } elseif ($have > $len) { $data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); } return $data; } /** * @inheritdoc * * @param int $len * @return string * @throws TTransportException */ public function read($len) { if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->rBuf_ = $this->transport_->read($this->rBufSize_); } if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) { $ret = $this->rBuf_; $this->rBuf_ = ''; return $ret; } $ret = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); return $ret; } /** * @inheritdoc * * @param string $buf * @throws TTransportException */ public function write($buf) { $this->wBuf_ .= $buf; if (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) { $out = $this->wBuf_; // Note that we clear the internal wBuf_ prior to the underlying write // to ensure we're in a sane state (i.e. internal buffer cleaned) // if the underlying write throws up an exception $this->wBuf_ = ''; $this->transport_->write($out); } } /** * @inheritdoc * * @throws TTransportException */ public function flush() { if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) { $out = $this->wBuf_; // Note that we clear the internal wBuf_ prior to the underlying write // to ensure we're in a sane state (i.e. internal buffer cleaned) // if the underlying write throws up an exception $this->wBuf_ = ''; $this->transport_->write($out); } $this->transport_->flush(); } } thrift-0.16.0/lib/php/lib/Transport/TCurlClient.php000066400000000000000000000205341420101504100220660ustar00rootroot00000000000000strlen($uri) > 0) && ($uri[0] != '/')) { $uri = '/' . $uri; } $this->scheme_ = $scheme; $this->host_ = $host; $this->port_ = $port; $this->uri_ = $uri; $this->request_ = ''; $this->response_ = null; $this->timeout_ = null; $this->connectionTimeout_ = null; $this->headers_ = array(); } /** * Set read timeout * * @param float $timeout */ public function setTimeoutSecs($timeout) { $this->timeout_ = $timeout; } /** * Set connection timeout * * @param float $connectionTimeout */ public function setConnectionTimeoutSecs($connectionTimeout) { $this->connectionTimeout_ = $connectionTimeout; } /** * Whether this transport is open. * * @return boolean true if open */ public function isOpen() { return true; } /** * Open the transport for reading/writing * * @throws TTransportException if cannot open */ public function open() { } /** * Close the transport. */ public function close() { $this->request_ = ''; $this->response_ = null; } /** * Read some data into the array. * * @param int $len How much to read * @return string The data that has been read * @throws TTransportException if cannot read any more data */ public function read($len) { if ($len >= strlen($this->response_)) { return $this->response_; } else { $ret = substr($this->response_, 0, $len); $this->response_ = substr($this->response_, $len); return $ret; } } /** * Guarantees that the full amount of data is read. Since TCurlClient gets entire payload at * once, parent readAll cannot be used. * * @return string The data, of exact length * @throws TTransportException if cannot read data */ public function readAll($len) { $data = $this->read($len); if (TStringFuncFactory::create()->strlen($data) !== $len) { throw new TTransportException('TCurlClient could not read '.$len.' bytes'); } return $data; } /** * Writes some data into the pending buffer * * @param string $buf The data to write * @throws TTransportException if writing fails */ public function write($buf) { $this->request_ .= $buf; } /** * Opens and sends the actual request over the HTTP connection * * @throws TTransportException if a writing error occurs */ public function flush() { if (!self::$curlHandle) { register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle')); self::$curlHandle = curl_init(); curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true); curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true); curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient'); curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true); curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1); } // God, PHP really has some esoteric ways of doing simple things. $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : ''); $fullUrl = $this->scheme_ . "://" . $host . $this->uri_; $headers = array(); $defaultHeaders = array('Accept' => 'application/x-thrift', 'Content-Type' => 'application/x-thrift', 'Content-Length' => TStringFuncFactory::create()->strlen($this->request_)); foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) { $headers[] = "$key: $value"; } curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers); if ($this->timeout_ > 0) { if ($this->timeout_ < 1.0) { // Timestamps smaller than 1 second are ignored when CURLOPT_TIMEOUT is used curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT_MS, 1000 * $this->timeout_); } else { curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_); } } if ($this->connectionTimeout_ > 0) { if ($this->connectionTimeout_ < 1.0) { // Timestamps smaller than 1 second are ignored when CURLOPT_CONNECTTIMEOUT is used curl_setopt(self::$curlHandle, CURLOPT_CONNECTTIMEOUT_MS, 1000 * $this->connectionTimeout_); } else { curl_setopt(self::$curlHandle, CURLOPT_CONNECTTIMEOUT, $this->connectionTimeout_); } } curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_); $this->request_ = ''; curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl); $this->response_ = curl_exec(self::$curlHandle); $responseError = curl_error(self::$curlHandle); $code = curl_getinfo(self::$curlHandle, CURLINFO_HTTP_CODE); // Handle non 200 status code / connect failure if ($this->response_ === false || $code !== 200) { curl_close(self::$curlHandle); self::$curlHandle = null; $this->response_ = null; $error = 'TCurlClient: Could not connect to ' . $fullUrl; if ($responseError) { $error .= ', ' . $responseError; } if ($code) { $error .= ', HTTP status code: ' . $code; } throw new TTransportException($error, TTransportException::UNKNOWN); } } public static function closeCurlHandle() { try { if (self::$curlHandle) { curl_close(self::$curlHandle); self::$curlHandle = null; } } catch (\Exception $x) { error_log('There was an error closing the curl handle: ' . $x->getMessage()); } } public function addHeaders($headers) { $this->headers_ = array_merge($this->headers_, $headers); } } thrift-0.16.0/lib/php/lib/Transport/TFramedTransport.php000066400000000000000000000114061420101504100231330ustar00rootroot00000000000000transport_ = $transport; $this->read_ = $read; $this->write_ = $write; } public function isOpen() { return $this->transport_->isOpen(); } public function open() { $this->transport_->open(); } public function close() { $this->transport_->close(); } /** * Reads from the buffer. When more data is required reads another entire * chunk and serves future reads out of that. * * @param int $len How much data */ public function read($len) { if (!$this->read_) { return $this->transport_->read($len); } if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->readFrame(); } // Just return full buff if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) { $out = $this->rBuf_; $this->rBuf_ = null; return $out; } // Return TStringFuncFactory::create()->substr $out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); return $out; } /** * Put previously read data back into the buffer * * @param string $data data to return */ public function putBack($data) { if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->rBuf_ = $data; } else { $this->rBuf_ = ($data . $this->rBuf_); } } /** * Reads a chunk of data into the internal read buffer. */ private function readFrame() { $buf = $this->transport_->readAll(4); $val = unpack('N', $buf); $sz = $val[1]; $this->rBuf_ = $this->transport_->readAll($sz); } /** * Writes some data to the pending output buffer. * * @param string $buf The data * @param int $len Limit of bytes to write */ public function write($buf, $len = null) { if (!$this->write_) { return $this->transport_->write($buf, $len); } if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) { $buf = TStringFuncFactory::create()->substr($buf, 0, $len); } $this->wBuf_ .= $buf; } /** * Writes the output buffer to the stream in the format of a 4-byte length * followed by the actual data. */ public function flush() { if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) { return $this->transport_->flush(); } $out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_)); $out .= $this->wBuf_; // Note that we clear the internal wBuf_ prior to the underlying write // to ensure we're in a sane state (i.e. internal buffer cleaned) // if the underlying write throws up an exception $this->wBuf_ = ''; $this->transport_->write($out); $this->transport_->flush(); } } thrift-0.16.0/lib/php/lib/Transport/THttpClient.php000066400000000000000000000145531420101504100221040ustar00rootroot00000000000000strlen($uri) > 0) && ($uri[0] != '/')) { $uri = '/' . $uri; } $this->scheme_ = $scheme; $this->host_ = $host; $this->port_ = $port; $this->uri_ = $uri; $this->buf_ = ''; $this->handle_ = null; $this->timeout_ = null; $this->headers_ = array(); $this->context_ = $context; } /** * Set read timeout * * @param float $timeout */ public function setTimeoutSecs($timeout) { $this->timeout_ = $timeout; } /** * Whether this transport is open. * * @return boolean true if open */ public function isOpen() { return true; } /** * Open the transport for reading/writing * * @throws TTransportException if cannot open */ public function open() { } /** * Close the transport. */ public function close() { if ($this->handle_) { @fclose($this->handle_); $this->handle_ = null; } } /** * Read some data into the array. * * @param int $len How much to read * @return string The data that has been read * @throws TTransportException if cannot read any more data */ public function read($len) { $data = @fread($this->handle_, $len); if ($data === false || $data === '') { $md = stream_get_meta_data($this->handle_); if ($md['timed_out']) { throw new TTransportException( 'THttpClient: timed out reading ' . $len . ' bytes from ' . $this->host_ . ':' . $this->port_ . $this->uri_, TTransportException::TIMED_OUT ); } else { throw new TTransportException( 'THttpClient: Could not read ' . $len . ' bytes from ' . $this->host_ . ':' . $this->port_ . $this->uri_, TTransportException::UNKNOWN ); } } return $data; } /** * Writes some data into the pending buffer * * @param string $buf The data to write * @throws TTransportException if writing fails */ public function write($buf) { $this->buf_ .= $buf; } /** * Opens and sends the actual request over the HTTP connection * * @throws TTransportException if a writing error occurs */ public function flush() { // God, PHP really has some esoteric ways of doing simple things. $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : ''); $headers = array(); $defaultHeaders = array('Host' => $host, 'Accept' => 'application/x-thrift', 'User-Agent' => 'PHP/THttpClient', 'Content-Type' => 'application/x-thrift', 'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_)); foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) { $headers[] = "$key: $value"; } $options = $this->context_; $baseHttpOptions = isset($options["http"]) ? $options["http"] : array(); $httpOptions = $baseHttpOptions + array('method' => 'POST', 'header' => implode("\r\n", $headers), 'max_redirects' => 1, 'content' => $this->buf_); if ($this->timeout_ > 0) { $httpOptions['timeout'] = $this->timeout_; } $this->buf_ = ''; $options["http"] = $httpOptions; $contextid = stream_context_create($options); $this->handle_ = @fopen( $this->scheme_ . '://' . $host . $this->uri_, 'r', false, $contextid ); // Connect failed? if ($this->handle_ === false) { $this->handle_ = null; $error = 'THttpClient: Could not connect to ' . $host . $this->uri_; throw new TTransportException($error, TTransportException::NOT_OPEN); } } public function addHeaders($headers) { $this->headers_ = array_merge($this->headers_, $headers); } } thrift-0.16.0/lib/php/lib/Transport/TMemoryBuffer.php000066400000000000000000000051161420101504100224230ustar00rootroot00000000000000buf_ = $buf; } protected $buf_ = ''; public function isOpen() { return true; } public function open() { } public function close() { } public function write($buf) { $this->buf_ .= $buf; } public function read($len) { $bufLength = TStringFuncFactory::create()->strlen($this->buf_); if ($bufLength === 0) { throw new TTransportException( 'TMemoryBuffer: Could not read ' . $len . ' bytes from buffer.', TTransportException::UNKNOWN ); } if ($bufLength <= $len) { $ret = $this->buf_; $this->buf_ = ''; return $ret; } $ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len); $this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len); return $ret; } public function getBuffer() { return $this->buf_; } public function available() { return TStringFuncFactory::create()->strlen($this->buf_); } public function putBack($data) { $this->buf_ = $data . $this->buf_; } } thrift-0.16.0/lib/php/lib/Transport/TNullTransport.php000066400000000000000000000026241420101504100226510ustar00rootroot00000000000000read_ = $mode & self::MODE_R; $this->write_ = $mode & self::MODE_W; } public function open() { if ($this->read_) { $this->inStream_ = @fopen(self::inStreamName(), 'r'); if (!is_resource($this->inStream_)) { throw new TException('TPhpStream: Could not open php://input'); } } if ($this->write_) { $this->outStream_ = @fopen('php://output', 'w'); if (!is_resource($this->outStream_)) { throw new TException('TPhpStream: Could not open php://output'); } } } public function close() { if ($this->read_) { @fclose($this->inStream_); $this->inStream_ = null; } if ($this->write_) { @fclose($this->outStream_); $this->outStream_ = null; } } public function isOpen() { return (!$this->read_ || is_resource($this->inStream_)) && (!$this->write_ || is_resource($this->outStream_)); } public function read($len) { $data = @fread($this->inStream_, $len); if ($data === false || $data === '') { throw new TException('TPhpStream: Could not read ' . $len . ' bytes'); } return $data; } public function write($buf) { while (TStringFuncFactory::create()->strlen($buf) > 0) { $got = @fwrite($this->outStream_, $buf); if ($got === 0 || $got === false) { throw new TException( 'TPhpStream: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes' ); } $buf = TStringFuncFactory::create()->substr($buf, $got); } } public function flush() { @fflush($this->outStream_); } private static function inStreamName() { if (php_sapi_name() == 'cli') { return 'php://stdin'; } return 'php://input'; } } thrift-0.16.0/lib/php/lib/Transport/TSSLSocket.php000066400000000000000000000067221420101504100216370ustar00rootroot00000000000000host_ = $this->getSSLHost($host); $this->port_ = $port; $this->context_ = $context; $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log'; } /** * Creates a host name with SSL transport protocol * if no transport protocol already specified in * the host name. * * @param string $host Host to listen on * @return string $host Host name with transport protocol */ private function getSSLHost($host) { $transport_protocol_loc = strpos($host, "://"); if ($transport_protocol_loc === false) { $host = 'ssl://' . $host; } return $host; } /** * Connects the socket. */ public function open() { if ($this->isOpen()) { throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN); } if (empty($this->host_)) { throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN); } if ($this->port_ <= 0) { throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN); } $this->handle_ = @stream_socket_client( $this->host_ . ':' . $this->port_, $errno, $errstr, $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000), STREAM_CLIENT_CONNECT, $this->context_ ); // Connect failed? if ($this->handle_ === false) { $error = 'TSocket: Could not connect to ' . $this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])'; if ($this->debug_) { call_user_func($this->debugHandler_, $error); } throw new TException($error); } } } thrift-0.16.0/lib/php/lib/Transport/TSocket.php000066400000000000000000000235051420101504100212530ustar00rootroot00000000000000host_ = $host; $this->port_ = $port; $this->persist_ = $persist; $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log'; } /** * @param resource $handle * @return void */ public function setHandle($handle) { $this->handle_ = $handle; stream_set_blocking($this->handle_, false); } /** * Sets the send timeout. * * @param int $timeout Timeout in milliseconds. */ public function setSendTimeout($timeout) { $this->sendTimeoutSec_ = floor($timeout / 1000); $this->sendTimeoutUsec_ = ($timeout - ($this->sendTimeoutSec_ * 1000)) * 1000; } /** * Sets the receive timeout. * * @param int $timeout Timeout in milliseconds. */ public function setRecvTimeout($timeout) { $this->recvTimeoutSec_ = floor($timeout / 1000); $this->recvTimeoutUsec_ = ($timeout - ($this->recvTimeoutSec_ * 1000)) * 1000; } /** * Sets debugging output on or off * * @param bool $debug */ public function setDebug($debug) { $this->debug_ = $debug; } /** * Get the host that this socket is connected to * * @return string host */ public function getHost() { return $this->host_; } /** * Get the remote port that this socket is connected to * * @return int port */ public function getPort() { return $this->port_; } /** * Tests whether this is open * * @return bool true if the socket is open */ public function isOpen() { return is_resource($this->handle_); } /** * Connects the socket. */ public function open() { if ($this->isOpen()) { throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN); } if (empty($this->host_)) { throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN); } if ($this->port_ <= 0) { throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN); } if ($this->persist_) { $this->handle_ = @pfsockopen( $this->host_, $this->port_, $errno, $errstr, $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000) ); } else { $this->handle_ = @fsockopen( $this->host_, $this->port_, $errno, $errstr, $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000) ); } // Connect failed? if ($this->handle_ === false) { $error = 'TSocket: Could not connect to ' . $this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])'; if ($this->debug_) { call_user_func($this->debugHandler_, $error); } throw new TException($error); } if (function_exists('socket_import_stream') && function_exists('socket_set_option')) { // warnings silenced due to bug https://bugs.php.net/bug.php?id=70939 $socket = @socket_import_stream($this->handle_); @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); } } /** * Closes the socket. */ public function close() { @fclose($this->handle_); $this->handle_ = null; } /** * Read from the socket at most $len bytes. * * This method will not wait for all the requested data, it will return as * soon as any data is received. * * @param int $len Maximum number of bytes to read. * @return string Binary data */ public function read($len) { $null = null; $read = array($this->handle_); $readable = @stream_select( $read, $null, $null, $this->recvTimeoutSec_, $this->recvTimeoutUsec_ ); if ($readable > 0) { $data = fread($this->handle_, $len); if ($data === false) { throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' . $this->host_ . ':' . $this->port_); } elseif ($data == '' && feof($this->handle_)) { throw new TTransportException('TSocket read 0 bytes'); } return $data; } elseif ($readable === 0) { throw new TTransportException('TSocket: timed out reading ' . $len . ' bytes from ' . $this->host_ . ':' . $this->port_); } else { throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' . $this->host_ . ':' . $this->port_); } } /** * Write to the socket. * * @param string $buf The data to write */ public function write($buf) { $null = null; $write = array($this->handle_); // keep writing until all the data has been written while (TStringFuncFactory::create()->strlen($buf) > 0) { // wait for stream to become available for writing $writable = @stream_select( $null, $write, $null, $this->sendTimeoutSec_, $this->sendTimeoutUsec_ ); if ($writable > 0) { // write buffer to stream $written = fwrite($this->handle_, $buf); $closed_socket = $written === 0 && feof($this->handle_); if ($written === -1 || $written === false || $closed_socket) { throw new TTransportException( 'TSocket: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes ' . $this->host_ . ':' . $this->port_ ); } // determine how much of the buffer is left to write $buf = TStringFuncFactory::create()->substr($buf, $written); } elseif ($writable === 0) { throw new TTransportException( 'TSocket: timed out writing ' . TStringFuncFactory::create()->strlen($buf) . ' bytes from ' . $this->host_ . ':' . $this->port_ ); } else { throw new TTransportException( 'TSocket: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes ' . $this->host_ . ':' . $this->port_ ); } } } /** * Flush output to the socket. * * Since read(), readAll() and write() operate on the sockets directly, * this is a no-op * * If you wish to have flushable buffering behaviour, wrap this TSocket * in a TBufferedTransport. */ public function flush() { // no-op } } thrift-0.16.0/lib/php/lib/Transport/TSocketPool.php000066400000000000000000000222761420101504100221110ustar00rootroot00000000000000 $val) { $ports[$key] = $port; } } foreach ($hosts as $key => $host) { $this->servers_ [] = array('host' => $host, 'port' => $ports[$key]); } } /** * Add a server to the pool * * This function does not prevent you from adding a duplicate server entry. * * @param string $host hostname or IP * @param int $port port */ public function addServer($host, $port) { $this->servers_[] = array('host' => $host, 'port' => $port); } /** * Sets how many time to keep retrying a host in the connect function. * * @param int $numRetries */ public function setNumRetries($numRetries) { $this->numRetries_ = $numRetries; } /** * Sets how long to wait until retrying a host if it was marked down * * @param int $numRetries */ public function setRetryInterval($retryInterval) { $this->retryInterval_ = $retryInterval; } /** * Sets how many time to keep retrying a host before marking it as down. * * @param int $numRetries */ public function setMaxConsecutiveFailures($maxConsecutiveFailures) { $this->maxConsecutiveFailures_ = $maxConsecutiveFailures; } /** * Turns randomization in connect order on or off. * * @param bool $randomize */ public function setRandomize($randomize) { $this->randomize_ = $randomize; } /** * Whether to always try the last server. * * @param bool $alwaysTryLast */ public function setAlwaysTryLast($alwaysTryLast) { $this->alwaysTryLast_ = $alwaysTryLast; } /** * Connects the socket by iterating through all the servers in the pool * and trying to find one that works. */ public function open() { // Check if we want order randomization if ($this->randomize_) { shuffle($this->servers_); } // Count servers to identify the "last" one $numServers = count($this->servers_); for ($i = 0; $i < $numServers; ++$i) { // This extracts the $host and $port variables extract($this->servers_[$i]); // Check APCu cache for a record of this server being down $failtimeKey = 'thrift_failtime:' . $host . ':' . $port . '~'; // Cache miss? Assume it's OK $lastFailtime = apcu_fetch($failtimeKey); if ($lastFailtime === false) { $lastFailtime = 0; } $retryIntervalPassed = false; // Cache hit...make sure enough the retry interval has elapsed if ($lastFailtime > 0) { $elapsed = time() - $lastFailtime; if ($elapsed > $this->retryInterval_) { $retryIntervalPassed = true; if ($this->debug_) { call_user_func( $this->debugHandler_, 'TSocketPool: retryInterval ' . '(' . $this->retryInterval_ . ') ' . 'has passed for host ' . $host . ':' . $port ); } } } // Only connect if not in the middle of a fail interval, OR if this // is the LAST server we are trying, just hammer away on it $isLastServer = false; if ($this->alwaysTryLast_) { $isLastServer = ($i == ($numServers - 1)); } if (($lastFailtime === 0) || ($isLastServer) || ($lastFailtime > 0 && $retryIntervalPassed)) { // Set underlying TSocket params to this one $this->host_ = $host; $this->port_ = $port; // Try up to numRetries_ connections per server for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) { try { // Use the underlying TSocket open function parent::open(); // Only clear the failure counts if required to do so if ($lastFailtime > 0) { apcu_store($failtimeKey, 0); } // Successful connection, return now return; } catch (TException $tx) { // Connection failed } } // Mark failure of this host in the cache $consecfailsKey = 'thrift_consecfails:' . $host . ':' . $port . '~'; // Ignore cache misses $consecfails = apcu_fetch($consecfailsKey); if ($consecfails === false) { $consecfails = 0; } // Increment by one $consecfails++; // Log and cache this failure if ($consecfails >= $this->maxConsecutiveFailures_) { if ($this->debug_) { call_user_func( $this->debugHandler_, 'TSocketPool: marking ' . $host . ':' . $port . ' as down for ' . $this->retryInterval_ . ' secs ' . 'after ' . $consecfails . ' failed attempts.' ); } // Store the failure time apcu_store($failtimeKey, time()); // Clear the count of consecutive failures apcu_store($consecfailsKey, 0); } else { apcu_store($consecfailsKey, $consecfails); } } } // Oh no; we failed them all. The system is totally ill! $error = 'TSocketPool: All hosts in pool are down. '; $hosts = array(); foreach ($this->servers_ as $server) { $hosts [] = $server['host'] . ':' . $server['port']; } $hostlist = implode(',', $hosts); $error .= '(' . $hostlist . ')'; if ($this->debug_) { call_user_func($this->debugHandler_, $error); } throw new TException($error); } } thrift-0.16.0/lib/php/lib/Transport/TTransport.php000066400000000000000000000047431420101504100220220ustar00rootroot00000000000000read($len); $data = ''; $got = 0; while (($got = TStringFuncFactory::create()->strlen($data)) < $len) { $data .= $this->read($len - $got); } return $data; } /** * Writes the given data out. * * @param string $buf The data to write * @throws TTransportException if writing fails */ abstract public function write($buf); /** * Flushes any pending data out of a buffer * * @throws TTransportException if a writing error occurs */ public function flush() { } } thrift-0.16.0/lib/php/lib/Type/000077500000000000000000000000001420101504100161065ustar00rootroot00000000000000thrift-0.16.0/lib/php/lib/Type/TConstant.php000066400000000000000000000025601420101504100205370ustar00rootroot00000000000000strlen($str) - $start; } return mb_substr($str, $start, $length, '8bit'); } public function strlen($str) { return mb_strlen($str, '8bit'); } } class TStringFuncFactory { private static $_instance; /** * Get the Singleton instance of TStringFunc implementation that is * compatible with the current system's mbstring.func_overload settings. * * @return TStringFunc */ public static function create() { if (!self::$_instance) { self::_setInstance(); } return self::$_instance; } private static function _setInstance() { /** * Cannot use str* functions for byte counting because multibyte * characters will be read a single bytes. * * See: http://us.php.net/manual/en/mbstring.overload.php */ if (ini_get('mbstring.func_overload') & 2) { self::$_instance = new TStringFunc_Mbstring(); } /** * mbstring is not installed or does not have function overloading * of the str* functions enabled so use PHP core str* functions for * byte counting. */ else { self::$_instance = new TStringFunc_Core(); } } } thrift-0.16.0/lib/php/src/Thrift.php000066400000000000000000000550211420101504100171620ustar00rootroot00000000000000 $fspec) { $var = $fspec['var']; if (isset($vals[$var])) { $this->$var = $vals[$var]; } } } else { parent::__construct($p1, $p2); } } static $tmethod = array(TType::BOOL => 'Bool', TType::BYTE => 'Byte', TType::I16 => 'I16', TType::I32 => 'I32', TType::I64 => 'I64', TType::DOUBLE => 'Double', TType::STRING => 'String'); private function _readMap(&$var, $spec, $input) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kread = $vread = null; if (isset(TBase::$tmethod[$ktype])) { $kread = 'read'.TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vread = 'read'.TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $var = array(); $_ktype = $_vtype = $size = 0; $xfer += $input->readMapBegin($_ktype, $_vtype, $size); for ($i = 0; $i < $size; ++$i) { $key = $val = null; if ($kread !== null) { $xfer += $input->$kread($key); } else { switch ($ktype) { case TType::STRUCT: $class = $kspec['class']; $key = new $class(); $xfer += $key->read($input); break; case TType::MAP: $xfer += $this->_readMap($key, $kspec, $input); break; case TType::LST: $xfer += $this->_readList($key, $kspec, $input, false); break; case TType::SET: $xfer += $this->_readList($key, $kspec, $input, true); break; } } if ($vread !== null) { $xfer += $input->$vread($val); } else { switch ($vtype) { case TType::STRUCT: $class = $vspec['class']; $val = new $class(); $xfer += $val->read($input); break; case TType::MAP: $xfer += $this->_readMap($val, $vspec, $input); break; case TType::LST: $xfer += $this->_readList($val, $vspec, $input, false); break; case TType::SET: $xfer += $this->_readList($val, $vspec, $input, true); break; } } $var[$key] = $val; } $xfer += $input->readMapEnd(); return $xfer; } private function _readList(&$var, $spec, $input, $set=false) { $xfer = 0; $etype = $spec['etype']; $eread = $vread = null; if (isset(TBase::$tmethod[$etype])) { $eread = 'read'.TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } $var = array(); $_etype = $size = 0; if ($set) { $xfer += $input->readSetBegin($_etype, $size); } else { $xfer += $input->readListBegin($_etype, $size); } for ($i = 0; $i < $size; ++$i) { $elem = null; if ($eread !== null) { $xfer += $input->$eread($elem); } else { $espec = $spec['elem']; switch ($etype) { case TType::STRUCT: $class = $espec['class']; $elem = new $class(); $xfer += $elem->read($input); break; case TType::MAP: $xfer += $this->_readMap($elem, $espec, $input); break; case TType::LST: $xfer += $this->_readList($elem, $espec, $input, false); break; case TType::SET: $xfer += $this->_readList($elem, $espec, $input, true); break; } } if ($set) { $var[$elem] = true; } else { $var []= $elem; } } if ($set) { $xfer += $input->readSetEnd(); } else { $xfer += $input->readListEnd(); } return $xfer; } protected function _read($class, $spec, $input) { $xfer = 0; $fname = null; $ftype = 0; $fid = 0; $xfer += $input->readStructBegin($fname); while (true) { $xfer += $input->readFieldBegin($fname, $ftype, $fid); if ($ftype == TType::STOP) { break; } if (isset($spec[$fid])) { $fspec = $spec[$fid]; $var = $fspec['var']; if ($ftype == $fspec['type']) { $xfer = 0; if (isset(TBase::$tmethod[$ftype])) { $func = 'read'.TBase::$tmethod[$ftype]; $xfer += $input->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $class = $fspec['class']; $this->$var = new $class(); $xfer += $this->$var->read($input); break; case TType::MAP: $xfer += $this->_readMap($this->$var, $fspec, $input); break; case TType::LST: $xfer += $this->_readList($this->$var, $fspec, $input, false); break; case TType::SET: $xfer += $this->_readList($this->$var, $fspec, $input, true); break; } } } else { $xfer += $input->skip($ftype); } } else { $xfer += $input->skip($ftype); } $xfer += $input->readFieldEnd(); } $xfer += $input->readStructEnd(); return $xfer; } private function _writeMap($var, $spec, $output) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kwrite = $vwrite = null; if (isset(TBase::$tmethod[$ktype])) { $kwrite = 'write'.TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vwrite = 'write'.TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); foreach ($var as $key => $val) { if (isset($kwrite)) { $xfer += $output->$kwrite($key); } else { switch ($ktype) { case TType::STRUCT: $xfer += $key->write($output); break; case TType::MAP: $xfer += $this->_writeMap($key, $kspec, $output); break; case TType::LST: $xfer += $this->_writeList($key, $kspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($key, $kspec, $output, true); break; } } if (isset($vwrite)) { $xfer += $output->$vwrite($val); } else { switch ($vtype) { case TType::STRUCT: $xfer += $val->write($output); break; case TType::MAP: $xfer += $this->_writeMap($val, $vspec, $output); break; case TType::LST: $xfer += $this->_writeList($val, $vspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($val, $vspec, $output, true); break; } } } $xfer += $output->writeMapEnd(); return $xfer; } private function _writeList($var, $spec, $output, $set=false) { $xfer = 0; $etype = $spec['etype']; $ewrite = null; if (isset(TBase::$tmethod[$etype])) { $ewrite = 'write'.TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } if ($set) { $xfer += $output->writeSetBegin($etype, count($var)); } else { $xfer += $output->writeListBegin($etype, count($var)); } foreach ($var as $key => $val) { $elem = $set ? $key : $val; if (isset($ewrite)) { $xfer += $output->$ewrite($elem); } else { switch ($etype) { case TType::STRUCT: $xfer += $elem->write($output); break; case TType::MAP: $xfer += $this->_writeMap($elem, $espec, $output); break; case TType::LST: $xfer += $this->_writeList($elem, $espec, $output, false); break; case TType::SET: $xfer += $this->_writeList($elem, $espec, $output, true); break; } } } if ($set) { $xfer += $output->writeSetEnd(); } else { $xfer += $output->writeListEnd(); } return $xfer; } protected function _write($class, $spec, $output) { $xfer = 0; $xfer += $output->writeStructBegin($class); foreach ($spec as $fid => $fspec) { $var = $fspec['var']; if ($this->$var !== null) { $ftype = $fspec['type']; $xfer += $output->writeFieldBegin($var, $ftype, $fid); if (isset(TBase::$tmethod[$ftype])) { $func = 'write'.TBase::$tmethod[$ftype]; $xfer += $output->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $xfer += $this->$var->write($output); break; case TType::MAP: $xfer += $this->_writeMap($this->$var, $fspec, $output); break; case TType::LST: $xfer += $this->_writeList($this->$var, $fspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($this->$var, $fspec, $output, true); break; } } $xfer += $output->writeFieldEnd(); } } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; } } /** * Base class from which other Thrift structs extend. This is so that we can * cut back on the size of the generated code which is turning out to have a * nontrivial cost just to load thanks to the wondrously abysmal implementation * of PHP. Note that code is intentionally duplicated in here to avoid making * function calls for every field or member of a container.. */ abstract class TBase { static $tmethod = array(TType::BOOL => 'Bool', TType::BYTE => 'Byte', TType::I16 => 'I16', TType::I32 => 'I32', TType::I64 => 'I64', TType::DOUBLE => 'Double', TType::STRING => 'String'); abstract public function read($input); abstract public function write($output); public function __construct($spec=null, $vals=null) { if (is_array($spec) && is_array($vals)) { foreach ($spec as $fid => $fspec) { $var = $fspec['var']; if (isset($vals[$var])) { $this->$var = $vals[$var]; } } } } private function _readMap(&$var, $spec, $input) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kread = $vread = null; if (isset(TBase::$tmethod[$ktype])) { $kread = 'read'.TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vread = 'read'.TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $var = array(); $_ktype = $_vtype = $size = 0; $xfer += $input->readMapBegin($_ktype, $_vtype, $size); for ($i = 0; $i < $size; ++$i) { $key = $val = null; if ($kread !== null) { $xfer += $input->$kread($key); } else { switch ($ktype) { case TType::STRUCT: $class = $kspec['class']; $key = new $class(); $xfer += $key->read($input); break; case TType::MAP: $xfer += $this->_readMap($key, $kspec, $input); break; case TType::LST: $xfer += $this->_readList($key, $kspec, $input, false); break; case TType::SET: $xfer += $this->_readList($key, $kspec, $input, true); break; } } if ($vread !== null) { $xfer += $input->$vread($val); } else { switch ($vtype) { case TType::STRUCT: $class = $vspec['class']; $val = new $class(); $xfer += $val->read($input); break; case TType::MAP: $xfer += $this->_readMap($val, $vspec, $input); break; case TType::LST: $xfer += $this->_readList($val, $vspec, $input, false); break; case TType::SET: $xfer += $this->_readList($val, $vspec, $input, true); break; } } $var[$key] = $val; } $xfer += $input->readMapEnd(); return $xfer; } private function _readList(&$var, $spec, $input, $set=false) { $xfer = 0; $etype = $spec['etype']; $eread = $vread = null; if (isset(TBase::$tmethod[$etype])) { $eread = 'read'.TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } $var = array(); $_etype = $size = 0; if ($set) { $xfer += $input->readSetBegin($_etype, $size); } else { $xfer += $input->readListBegin($_etype, $size); } for ($i = 0; $i < $size; ++$i) { $elem = null; if ($eread !== null) { $xfer += $input->$eread($elem); } else { $espec = $spec['elem']; switch ($etype) { case TType::STRUCT: $class = $espec['class']; $elem = new $class(); $xfer += $elem->read($input); break; case TType::MAP: $xfer += $this->_readMap($elem, $espec, $input); break; case TType::LST: $xfer += $this->_readList($elem, $espec, $input, false); break; case TType::SET: $xfer += $this->_readList($elem, $espec, $input, true); break; } } if ($set) { $var[$elem] = true; } else { $var []= $elem; } } if ($set) { $xfer += $input->readSetEnd(); } else { $xfer += $input->readListEnd(); } return $xfer; } protected function _read($class, $spec, $input) { $xfer = 0; $fname = null; $ftype = 0; $fid = 0; $xfer += $input->readStructBegin($fname); while (true) { $xfer += $input->readFieldBegin($fname, $ftype, $fid); if ($ftype == TType::STOP) { break; } if (isset($spec[$fid])) { $fspec = $spec[$fid]; $var = $fspec['var']; if ($ftype == $fspec['type']) { $xfer = 0; if (isset(TBase::$tmethod[$ftype])) { $func = 'read'.TBase::$tmethod[$ftype]; $xfer += $input->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $class = $fspec['class']; $this->$var = new $class(); $xfer += $this->$var->read($input); break; case TType::MAP: $xfer += $this->_readMap($this->$var, $fspec, $input); break; case TType::LST: $xfer += $this->_readList($this->$var, $fspec, $input, false); break; case TType::SET: $xfer += $this->_readList($this->$var, $fspec, $input, true); break; } } } else { $xfer += $input->skip($ftype); } } else { $xfer += $input->skip($ftype); } $xfer += $input->readFieldEnd(); } $xfer += $input->readStructEnd(); return $xfer; } private function _writeMap($var, $spec, $output) { $xfer = 0; $ktype = $spec['ktype']; $vtype = $spec['vtype']; $kwrite = $vwrite = null; if (isset(TBase::$tmethod[$ktype])) { $kwrite = 'write'.TBase::$tmethod[$ktype]; } else { $kspec = $spec['key']; } if (isset(TBase::$tmethod[$vtype])) { $vwrite = 'write'.TBase::$tmethod[$vtype]; } else { $vspec = $spec['val']; } $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); foreach ($var as $key => $val) { if (isset($kwrite)) { $xfer += $output->$kwrite($key); } else { switch ($ktype) { case TType::STRUCT: $xfer += $key->write($output); break; case TType::MAP: $xfer += $this->_writeMap($key, $kspec, $output); break; case TType::LST: $xfer += $this->_writeList($key, $kspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($key, $kspec, $output, true); break; } } if (isset($vwrite)) { $xfer += $output->$vwrite($val); } else { switch ($vtype) { case TType::STRUCT: $xfer += $val->write($output); break; case TType::MAP: $xfer += $this->_writeMap($val, $vspec, $output); break; case TType::LST: $xfer += $this->_writeList($val, $vspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($val, $vspec, $output, true); break; } } } $xfer += $output->writeMapEnd(); return $xfer; } private function _writeList($var, $spec, $output, $set=false) { $xfer = 0; $etype = $spec['etype']; $ewrite = null; if (isset(TBase::$tmethod[$etype])) { $ewrite = 'write'.TBase::$tmethod[$etype]; } else { $espec = $spec['elem']; } if ($set) { $xfer += $output->writeSetBegin($etype, count($var)); } else { $xfer += $output->writeListBegin($etype, count($var)); } foreach ($var as $key => $val) { $elem = $set ? $key : $val; if (isset($ewrite)) { $xfer += $output->$ewrite($elem); } else { switch ($etype) { case TType::STRUCT: $xfer += $elem->write($output); break; case TType::MAP: $xfer += $this->_writeMap($elem, $espec, $output); break; case TType::LST: $xfer += $this->_writeList($elem, $espec, $output, false); break; case TType::SET: $xfer += $this->_writeList($elem, $espec, $output, true); break; } } } if ($set) { $xfer += $output->writeSetEnd(); } else { $xfer += $output->writeListEnd(); } return $xfer; } protected function _write($class, $spec, $output) { $xfer = 0; $xfer += $output->writeStructBegin($class); foreach ($spec as $fid => $fspec) { $var = $fspec['var']; if ($this->$var !== null) { $ftype = $fspec['type']; $xfer += $output->writeFieldBegin($var, $ftype, $fid); if (isset(TBase::$tmethod[$ftype])) { $func = 'write'.TBase::$tmethod[$ftype]; $xfer += $output->$func($this->$var); } else { switch ($ftype) { case TType::STRUCT: $xfer += $this->$var->write($output); break; case TType::MAP: $xfer += $this->_writeMap($this->$var, $fspec, $output); break; case TType::LST: $xfer += $this->_writeList($this->$var, $fspec, $output, false); break; case TType::SET: $xfer += $this->_writeList($this->$var, $fspec, $output, true); break; } } $xfer += $output->writeFieldEnd(); } } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; } } class TApplicationException extends TException { static $_TSPEC = array(1 => array('var' => 'message', 'type' => TType::STRING), 2 => array('var' => 'code', 'type' => TType::I32)); const UNKNOWN = 0; const UNKNOWN_METHOD = 1; const INVALID_MESSAGE_TYPE = 2; const WRONG_METHOD_NAME = 3; const BAD_SEQUENCE_ID = 4; const MISSING_RESULT = 5; const INTERNAL_ERROR = 6; const PROTOCOL_ERROR = 7; public function __construct($message=null, $code=0) { parent::__construct($message, $code); } public function read($output) { return $this->_read('TApplicationException', self::$_TSPEC, $output); } public function write($output) { $xfer = 0; $xfer += $output->writeStructBegin('TApplicationException'); if ($message = $this->getMessage()) { $xfer += $output->writeFieldBegin('message', TType::STRING, 1); $xfer += $output->writeString($message); $xfer += $output->writeFieldEnd(); } if ($code = $this->getCode()) { $xfer += $output->writeFieldBegin('type', TType::I32, 2); $xfer += $output->writeI32($code); $xfer += $output->writeFieldEnd(); } $xfer += $output->writeFieldStop(); $xfer += $output->writeStructEnd(); return $xfer; } } /** * Set global THRIFT ROOT automatically via inclusion here */ if (!isset($GLOBALS['THRIFT_ROOT'])) { $GLOBALS['THRIFT_ROOT'] = dirname(__FILE__); } include_once $GLOBALS['THRIFT_ROOT'].'/protocol/TProtocol.php'; include_once $GLOBALS['THRIFT_ROOT'].'/transport/TTransport.php'; include_once $GLOBALS['THRIFT_ROOT'].'/TStringUtils.php'; thrift-0.16.0/lib/php/src/autoload.php000066400000000000000000000035721420101504100175360ustar00rootroot00000000000000= 70000 #include #include #include #include #include #ifndef bswap_64 #define bswap_64(x) (((uint64_t)(x) << 56) | \ (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ (((uint64_t)(x) >> 40) & 0xff00ULL) | \ ((uint64_t)(x) >> 56)) #endif #if __BYTE_ORDER == __LITTLE_ENDIAN #define htonll(x) bswap_64(x) #define ntohll(x) bswap_64(x) #elif __BYTE_ORDER == __BIG_ENDIAN #define htonll(x) x #define ntohll(x) x #else #error Unknown __BYTE_ORDER #endif enum TType { T_STOP = 0, T_VOID = 1, T_BOOL = 2, T_BYTE = 3, T_I08 = 3, T_I16 = 6, T_I32 = 8, T_U64 = 9, T_I64 = 10, T_DOUBLE = 4, T_STRING = 11, T_UTF7 = 11, T_STRUCT = 12, T_MAP = 13, T_SET = 14, T_LIST = 15, T_UTF8 = 16, T_UTF16 = 17 }; const int32_t VERSION_MASK = 0xffff0000; const int32_t VERSION_1 = 0x80010000; const int8_t T_CALL = 1; const int8_t T_REPLY = 2; const int8_t T_EXCEPTION = 3; // tprotocolexception const int INVALID_DATA = 1; const int BAD_VERSION = 4; zend_module_entry thrift_protocol_module_entry = { STANDARD_MODULE_HEADER, "thrift_protocol", ext_functions, nullptr, nullptr, nullptr, nullptr, nullptr, "1.0", STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_THRIFT_PROTOCOL ZEND_GET_MODULE(thrift_protocol) #endif class PHPExceptionWrapper : public std::exception { public: PHPExceptionWrapper(zval* _ex) throw() { ZVAL_COPY(&ex, _ex); snprintf(_what, 40, "PHP exception zval=%p", _ex); } PHPExceptionWrapper(zend_object* _exobj) throw() { ZVAL_OBJ(&ex, _exobj); snprintf(_what, 40, "PHP exception zval=%p", _exobj); } ~PHPExceptionWrapper() throw() { zval_dtor(&ex); } const char* what() const throw() { return _what; } operator zval*() const throw() { return const_cast(&ex); } // Zend API doesn't do 'const'... protected: zval ex; char _what[40]; } ; class PHPTransport { protected: PHPTransport(zval* _p, size_t _buffer_size) { assert(Z_TYPE_P(_p) == IS_OBJECT); ZVAL_UNDEF(&t); buffer = reinterpret_cast(emalloc(_buffer_size)); buffer_ptr = buffer; buffer_used = 0; buffer_size = _buffer_size; // Get the transport for the passed protocol zval gettransport; ZVAL_STRING(&gettransport, "getTransport"); call_user_function(nullptr, _p, &gettransport, &t, 0, nullptr); zval_dtor(&gettransport); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } assert(Z_TYPE(t) == IS_OBJECT); } ~PHPTransport() { efree(buffer); zval_dtor(&t); } char* buffer; char* buffer_ptr; size_t buffer_used; size_t buffer_size; zval t; }; class PHPOutputTransport : public PHPTransport { public: PHPOutputTransport(zval* _p, size_t _buffer_size = 8192) : PHPTransport(_p, _buffer_size) { } ~PHPOutputTransport() { } void write(const char* data, size_t len) { if ((len + buffer_used) > buffer_size) { internalFlush(); } if (len > buffer_size) { directWrite(data, len); } else { memcpy(buffer_ptr, data, len); buffer_used += len; buffer_ptr += len; } } void writeI64(int64_t i) { i = htonll(i); write((const char*)&i, 8); } void writeU32(uint32_t i) { i = htonl(i); write((const char*)&i, 4); } void writeI32(int32_t i) { i = htonl(i); write((const char*)&i, 4); } void writeI16(int16_t i) { i = htons(i); write((const char*)&i, 2); } void writeI8(int8_t i) { write((const char*)&i, 1); } void writeString(const char* str, size_t len) { writeU32(len); write(str, len); } void flush() { internalFlush(); directFlush(); } protected: void internalFlush() { if (buffer_used) { directWrite(buffer, buffer_used); buffer_ptr = buffer; buffer_used = 0; } } void directFlush() { zval ret, flushfn; ZVAL_NULL(&ret); ZVAL_STRING(&flushfn, "flush"); call_user_function(EG(function_table), &(this->t), &flushfn, &ret, 0, nullptr); zval_dtor(&flushfn); zval_dtor(&ret); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } } void directWrite(const char* data, size_t len) { zval args[1], ret, writefn; ZVAL_STRING(&writefn, "write"); ZVAL_STRINGL(&args[0], data, len); ZVAL_NULL(&ret); call_user_function(EG(function_table), &(this->t), &writefn, &ret, 1, args); zval_dtor(&writefn); zval_dtor(&ret); zval_dtor(&args[0]); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } } }; class PHPInputTransport : public PHPTransport { public: PHPInputTransport(zval* _p, size_t _buffer_size = 8192) : PHPTransport(_p, _buffer_size) { } ~PHPInputTransport() { put_back(); } void put_back() { if (buffer_used) { zval args[1], ret, putbackfn; ZVAL_STRINGL(&args[0], buffer_ptr, buffer_used); ZVAL_STRING(&putbackfn, "putBack"); ZVAL_NULL(&ret); call_user_function(EG(function_table), &(this->t), &putbackfn, &ret, 1, args); zval_dtor(&putbackfn); zval_dtor(&ret); zval_dtor(&args[0]); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } } buffer_used = 0; buffer_ptr = buffer; } void skip(size_t len) { while (len) { size_t chunk_size = (std::min)(len, buffer_used); if (chunk_size) { buffer_ptr = reinterpret_cast(buffer_ptr) + chunk_size; buffer_used -= chunk_size; len -= chunk_size; } if (! len) break; refill(); } } void readBytes(void* buf, size_t len) { while (len) { size_t chunk_size = (std::min)(len, buffer_used); if (chunk_size) { memcpy(buf, buffer_ptr, chunk_size); buffer_ptr = reinterpret_cast(buffer_ptr) + chunk_size; buffer_used -= chunk_size; buf = reinterpret_cast(buf) + chunk_size; len -= chunk_size; } if (! len) break; refill(); } } int8_t readI8() { int8_t c; readBytes(&c, 1); return c; } int16_t readI16() { int16_t c; readBytes(&c, 2); return (int16_t)ntohs(c); } uint32_t readU32() { uint32_t c; readBytes(&c, 4); return (uint32_t)ntohl(c); } int32_t readI32() { int32_t c; readBytes(&c, 4); return (int32_t)ntohl(c); } protected: void refill() { assert(buffer_used == 0); zval retval; zval args[1]; zval funcname; ZVAL_NULL(&retval); ZVAL_LONG(&args[0], buffer_size); ZVAL_STRING(&funcname, "read"); call_user_function(EG(function_table), &(this->t), &funcname, &retval, 1, args); zval_dtor(&args[0]); zval_dtor(&funcname); if (EG(exception)) { zval_dtor(&retval); zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } buffer_used = Z_STRLEN(retval); memcpy(buffer, Z_STRVAL(retval), buffer_used); zval_dtor(&retval); buffer_ptr = buffer; } }; static void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec); static void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec); static void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* value, HashTable* fieldspec); static inline bool ttype_is_scalar(int8_t t); // Create a PHP object given a typename and call the ctor, optionally passing up to 2 arguments static void createObject(const char* obj_typename, zval* return_value, int nargs = 0, zval* arg1 = nullptr, zval* arg2 = nullptr) { /* is there a better way to do that on the stack ? */ zend_string *obj_name = zend_string_init(obj_typename, strlen(obj_typename), 0); zend_class_entry* ce = zend_fetch_class(obj_name, ZEND_FETCH_CLASS_DEFAULT); zend_string_release(obj_name); if (! ce) { php_error_docref(nullptr, E_ERROR, "Class %s does not exist", obj_typename); RETURN_NULL(); } object_and_properties_init(return_value, ce, nullptr); zend_function* constructor = zend_std_get_constructor(Z_OBJ_P(return_value)); zval ctor_rv; zend_call_method(Z4_OBJ_P(return_value), ce, &constructor, nullptr, 0, &ctor_rv, nargs, arg1, arg2); zval_dtor(&ctor_rv); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } } static void throw_tprotocolexception(const char* what, long errorcode) { zval zwhat, zerrorcode; ZVAL_STRING(&zwhat, what); ZVAL_LONG(&zerrorcode, errorcode); zval ex; createObject("\\Thrift\\Exception\\TProtocolException", &ex, 2, &zwhat, &zerrorcode); zval_dtor(&zwhat); zval_dtor(&zerrorcode); throw PHPExceptionWrapper(&ex); } // Sets EG(exception), call this and then RETURN_NULL(); static void throw_zend_exception_from_std_exception(const std::exception& ex) { zend_throw_exception(zend_exception_get_default(), const_cast(ex.what()), 0); } static void skip_element(long thrift_typeID, PHPInputTransport& transport) { switch (thrift_typeID) { case T_STOP: case T_VOID: return; case T_STRUCT: while (true) { int8_t ttype = transport.readI8(); // get field type if (ttype == T_STOP) break; transport.skip(2); // skip field number, I16 skip_element(ttype, transport); // skip field payload } return; case T_BOOL: case T_BYTE: transport.skip(1); return; case T_I16: transport.skip(2); return; case T_I32: transport.skip(4); return; case T_U64: case T_I64: case T_DOUBLE: transport.skip(8); return; //case T_UTF7: // aliases T_STRING case T_UTF8: case T_UTF16: case T_STRING: { uint32_t len = transport.readU32(); transport.skip(len); } return; case T_MAP: { int8_t keytype = transport.readI8(); int8_t valtype = transport.readI8(); uint32_t size = transport.readU32(); for (uint32_t i = 0; i < size; ++i) { skip_element(keytype, transport); skip_element(valtype, transport); } } return; case T_LIST: case T_SET: { int8_t valtype = transport.readI8(); uint32_t size = transport.readU32(); for (uint32_t i = 0; i < size; ++i) { skip_element(valtype, transport); } } return; }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %ld", thrift_typeID); throw_tprotocolexception(errbuf, INVALID_DATA); } static inline bool zval_is_bool(zval* v) { return Z_TYPE_P(v) == IS_TRUE || Z_TYPE_P(v) == IS_FALSE; } static void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval* return_value, HashTable* fieldspec) { ZVAL_NULL(return_value); switch (thrift_typeID) { case T_STOP: case T_VOID: RETURN_NULL(); return; case T_STRUCT: { zval* val_ptr = zend_hash_str_find(fieldspec, "class", sizeof("class")-1); if (val_ptr == nullptr) { throw_tprotocolexception("no class type in spec", INVALID_DATA); skip_element(T_STRUCT, transport); RETURN_NULL(); } char* structType = Z_STRVAL_P(val_ptr); // Create an object in PHP userland based on our spec createObject(structType, return_value); if (Z_TYPE_P(return_value) == IS_NULL) { // unable to create class entry skip_element(T_STRUCT, transport); RETURN_NULL(); } zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false); ZVAL_DEREF(spec); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } if (Z_TYPE_P(spec) != IS_ARRAY) { char errbuf[128]; snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType, Z_TYPE_P(spec)); throw_tprotocolexception(errbuf, INVALID_DATA); RETURN_NULL(); } binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec)); return; } break; case T_BOOL: { uint8_t c; transport.readBytes(&c, 1); RETURN_BOOL(c != 0); } //case T_I08: // same numeric value as T_BYTE case T_BYTE: { uint8_t c; transport.readBytes(&c, 1); RETURN_LONG((int8_t)c); } case T_I16: { uint16_t c; transport.readBytes(&c, 2); RETURN_LONG((int16_t)ntohs(c)); } case T_I32: { uint32_t c; transport.readBytes(&c, 4); RETURN_LONG((int32_t)ntohl(c)); } case T_U64: case T_I64: { uint64_t c; transport.readBytes(&c, 8); RETURN_LONG((int64_t)ntohll(c)); } case T_DOUBLE: { union { uint64_t c; double d; } a; transport.readBytes(&(a.c), 8); a.c = ntohll(a.c); RETURN_DOUBLE(a.d); } //case T_UTF7: // aliases T_STRING case T_UTF8: case T_UTF16: case T_STRING: { uint32_t size = transport.readU32(); if (size) { char strbuf[size+1]; transport.readBytes(strbuf, size); strbuf[size] = '\0'; ZVAL_STRINGL(return_value, strbuf, size); } else { ZVAL_EMPTY_STRING(return_value); } return; } case T_MAP: { // array of key -> value uint8_t types[2]; transport.readBytes(types, 2); uint32_t size = transport.readU32(); array_init(return_value); zval *val_ptr; val_ptr = zend_hash_str_find(fieldspec, "key", sizeof("key")-1); HashTable* keyspec = Z_ARRVAL_P(val_ptr); val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1); HashTable* valspec = Z_ARRVAL_P(val_ptr); for (uint32_t s = 0; s < size; ++s) { zval key, value; binary_deserialize(types[0], transport, &key, keyspec); binary_deserialize(types[1], transport, &value, valspec); if (Z_TYPE(key) == IS_LONG) { zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value); } else { if (Z_TYPE(key) != IS_STRING) convert_to_string(&key); zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value); } zval_dtor(&key); } return; // return_value already populated } case T_LIST: { // array with autogenerated numeric keys int8_t type = transport.readI8(); uint32_t size = transport.readU32(); zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); HashTable* elemspec = Z_ARRVAL_P(val_ptr); array_init(return_value); for (uint32_t s = 0; s < size; ++s) { zval value; binary_deserialize(type, transport, &value, elemspec); zend_hash_next_index_insert(Z_ARR_P(return_value), &value); } return; } case T_SET: { // array of key -> TRUE uint8_t type; uint32_t size; transport.readBytes(&type, 1); transport.readBytes(&size, 4); size = ntohl(size); zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); HashTable* elemspec = Z_ARRVAL_P(val_ptr); array_init(return_value); for (uint32_t s = 0; s < size; ++s) { zval key, value; ZVAL_TRUE(&value); binary_deserialize(type, transport, &key, elemspec); if (Z_TYPE(key) == IS_LONG) { zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value); } else { if (Z_TYPE(key) != IS_STRING) convert_to_string(&key); zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value); } zval_dtor(&key); } return; } }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(errbuf, INVALID_DATA); } static void binary_serialize_hashtable_key(int8_t keytype, PHPOutputTransport& transport, HashTable* ht, HashPosition& ht_pos, HashTable* spec) { bool keytype_is_numeric = (!((keytype == T_STRING) || (keytype == T_UTF8) || (keytype == T_UTF16))); zend_string* key; uint key_len; long index = 0; zval z; int res = zend_hash_get_current_key_ex(ht, &key, (zend_ulong*)&index, &ht_pos); if (res == HASH_KEY_IS_STRING) { ZVAL_STR_COPY(&z, key); } else { ZVAL_LONG(&z, index); } binary_serialize(keytype, transport, &z, spec); zval_dtor(&z); } static void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* value, HashTable* fieldspec) { if (value) { ZVAL_DEREF(value); } // At this point the typeID (and field num, if applicable) should've already been written to the output so all we need to do is write the payload. switch (thrift_typeID) { case T_STOP: case T_VOID: return; case T_STRUCT: { if (Z_TYPE_P(value) != IS_OBJECT) { throw_tprotocolexception("Attempt to send non-object type as a T_STRUCT", INVALID_DATA); } zval* spec = zend_read_static_property(Z_OBJCE_P(value), "_TSPEC", sizeof("_TSPEC")-1, true); if (spec && Z_TYPE_P(spec) == IS_REFERENCE) { ZVAL_DEREF(spec); } if (!spec || Z_TYPE_P(spec) != IS_ARRAY) { throw_tprotocolexception("Attempt to send non-Thrift object as a T_STRUCT", INVALID_DATA); } binary_serialize_spec(value, transport, Z_ARRVAL_P(spec)); } return; case T_BOOL: if (!zval_is_bool(value)) convert_to_boolean(value); transport.writeI8(Z_TYPE_INFO_P(value) == IS_TRUE ? 1 : 0); return; case T_BYTE: if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); transport.writeI8(Z_LVAL_P(value)); return; case T_I16: if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); transport.writeI16(Z_LVAL_P(value)); return; case T_I32: if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); transport.writeI32(Z_LVAL_P(value)); return; case T_I64: case T_U64: { int64_t l_data; #if defined(_LP64) || defined(_WIN64) if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value); l_data = Z_LVAL_P(value); #else if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value); l_data = (int64_t)Z_DVAL_P(value); #endif transport.writeI64(l_data); } return; case T_DOUBLE: { union { int64_t c; double d; } a; if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value); a.d = Z_DVAL_P(value); transport.writeI64(a.c); } return; case T_UTF8: case T_UTF16: case T_STRING: if (Z_TYPE_P(value) != IS_STRING) convert_to_string(value); transport.writeString(Z_STRVAL_P(value), Z_STRLEN_P(value)); return; case T_MAP: { if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value); if (Z_TYPE_P(value) != IS_ARRAY) { throw_tprotocolexception("Attempt to send an incompatible type as an array (T_MAP)", INVALID_DATA); } HashTable* ht = Z_ARRVAL_P(value); zval* val_ptr; val_ptr = zend_hash_str_find(fieldspec, "ktype", sizeof("ktype")-1); if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); uint8_t keytype = Z_LVAL_P(val_ptr); transport.writeI8(keytype); val_ptr = zend_hash_str_find(fieldspec, "vtype", sizeof("vtype")-1); if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); uint8_t valtype = Z_LVAL_P(val_ptr); transport.writeI8(valtype); val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1); HashTable* valspec = Z_ARRVAL_P(val_ptr); HashTable* keyspec = Z_ARRVAL_P(zend_hash_str_find(fieldspec, "key", sizeof("key")-1)); transport.writeI32(zend_hash_num_elements(ht)); HashPosition key_ptr; for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; zend_hash_move_forward_ex(ht, &key_ptr)) { binary_serialize_hashtable_key(keytype, transport, ht, key_ptr, keyspec); binary_serialize(valtype, transport, val_ptr, valspec); } } return; case T_LIST: { if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value); if (Z_TYPE_P(value) != IS_ARRAY) { throw_tprotocolexception("Attempt to send an incompatible type as an array (T_LIST)", INVALID_DATA); } HashTable* ht = Z_ARRVAL_P(value); zval* val_ptr; val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1); if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); uint8_t valtype = Z_LVAL_P(val_ptr); transport.writeI8(valtype); val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); HashTable* valspec = Z_ARRVAL_P(val_ptr); transport.writeI32(zend_hash_num_elements(ht)); HashPosition key_ptr; for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; zend_hash_move_forward_ex(ht, &key_ptr)) { binary_serialize(valtype, transport, val_ptr, valspec); } } return; case T_SET: { if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value); if (Z_TYPE_P(value) != IS_ARRAY) { throw_tprotocolexception("Attempt to send an incompatible type as an array (T_SET)", INVALID_DATA); } HashTable* ht = Z_ARRVAL_P(value); zval* val_ptr; val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1); HashTable* spec = Z_ARRVAL_P(zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1)); if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); uint8_t keytype = Z_LVAL_P(val_ptr); transport.writeI8(keytype); transport.writeI32(zend_hash_num_elements(ht)); HashPosition key_ptr; if(ttype_is_scalar(keytype)){ for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; zend_hash_move_forward_ex(ht, &key_ptr)) { binary_serialize_hashtable_key(keytype, transport, ht, key_ptr, spec); } } else { for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr; zend_hash_move_forward_ex(ht, &key_ptr)) { binary_serialize(keytype, transport, val_ptr, spec); } } } return; }; char errbuf[128]; snprintf(errbuf, 128, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(errbuf, INVALID_DATA); } static void protocol_writeMessageBegin(zval* transport, zend_string* method_name, int32_t msgtype, int32_t seqID) { zval args[3]; zval ret; zval writeMessagefn; ZVAL_STR_COPY(&args[0], method_name); ZVAL_LONG(&args[1], msgtype); ZVAL_LONG(&args[2], seqID); ZVAL_NULL(&ret); ZVAL_STRING(&writeMessagefn, "writeMessageBegin"); call_user_function(EG(function_table), transport, &writeMessagefn, &ret, 3, args); zval_dtor(&writeMessagefn); zval_dtor(&args[2]); zval_dtor(&args[1]); zval_dtor(&args[0]); zval_dtor(&ret); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } } static inline bool ttype_is_int(int8_t t) { return ((t == T_BYTE) || ((t >= T_I16) && (t <= T_I64))); } static inline bool ttype_is_scalar(int8_t t) { return !((t == T_STRUCT) || ( t== T_MAP) || (t == T_SET) || (t == T_LIST)); } static inline bool ttypes_are_compatible(int8_t t1, int8_t t2) { // Integer types of different widths are considered compatible; // otherwise the typeID must match. return ((t1 == t2) || (ttype_is_int(t1) && ttype_is_int(t2))); } //is used to validate objects before serialization and after deserialization. For now, only required fields are validated. static void validate_thrift_object(zval* object) { zend_class_entry* object_class_entry = Z_OBJCE_P(object); zval* is_validate = zend_read_static_property(object_class_entry, "isValidate", sizeof("isValidate")-1, true); if (is_validate) { ZVAL_DEREF(is_validate); } zval* spec = zend_read_static_property(object_class_entry, "_TSPEC", sizeof("_TSPEC")-1, true); if (spec) { ZVAL_DEREF(spec); } HashPosition key_ptr; zval* val_ptr; if (is_validate && Z_TYPE_INFO_P(is_validate) == IS_TRUE) { for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(spec), &key_ptr); (val_ptr = zend_hash_get_current_data_ex(Z_ARRVAL_P(spec), &key_ptr)) != nullptr; zend_hash_move_forward_ex(Z_ARRVAL_P(spec), &key_ptr)) { zend_ulong fieldno; if (zend_hash_get_current_key_ex(Z_ARRVAL_P(spec), nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) { throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA); return; } HashTable* fieldspec = Z_ARRVAL_P(val_ptr); // field name zval* zvarname = zend_hash_str_find(fieldspec, "var", sizeof("var")-1); char* varname = Z_STRVAL_P(zvarname); zval* is_required = zend_hash_str_find(fieldspec, "isRequired", sizeof("isRequired")-1); zval rv; zval* prop = zend_read_property(object_class_entry, Z4_OBJ_P(object), varname, strlen(varname), false, &rv); if (Z_TYPE_INFO_P(is_required) == IS_TRUE && Z_TYPE_P(prop) == IS_NULL) { char errbuf[128]; snprintf(errbuf, 128, "Required field %s.%s is unset!", ZSTR_VAL(object_class_entry->name), varname); throw_tprotocolexception(errbuf, INVALID_DATA); } } } } static void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec) { // SET and LIST have 'elem' => array('type', [optional] 'class') // MAP has 'val' => array('type', [optiona] 'class') zend_class_entry* ce = Z_OBJCE_P(zthis); while (true) { int8_t ttype = transport.readI8(); if (ttype == T_STOP) { validate_thrift_object(zthis); return; } int16_t fieldno = transport.readI16(); zval* val_ptr = zend_hash_index_find(spec, fieldno); if (val_ptr != nullptr) { HashTable* fieldspec = Z_ARRVAL_P(val_ptr); // pull the field name val_ptr = zend_hash_str_find(fieldspec, "var", sizeof("var")-1); char* varname = Z_STRVAL_P(val_ptr); // and the type val_ptr = zend_hash_str_find(fieldspec, "type", sizeof("type")-1); if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); int8_t expected_ttype = Z_LVAL_P(val_ptr); if (ttypes_are_compatible(ttype, expected_ttype)) { zval rv; ZVAL_UNDEF(&rv); binary_deserialize(ttype, transport, &rv, fieldspec); zend_update_property(ce, Z4_OBJ_P(zthis), varname, strlen(varname), &rv); zval_ptr_dtor(&rv); } else { skip_element(ttype, transport); } } else { skip_element(ttype, transport); } } } static void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec) { validate_thrift_object(zthis); HashPosition key_ptr; zval* val_ptr; for (zend_hash_internal_pointer_reset_ex(spec, &key_ptr); (val_ptr = zend_hash_get_current_data_ex(spec, &key_ptr)) != nullptr; zend_hash_move_forward_ex(spec, &key_ptr)) { zend_ulong fieldno; if (zend_hash_get_current_key_ex(spec, nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) { throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA); return; } HashTable* fieldspec = Z_ARRVAL_P(val_ptr); // field name val_ptr = zend_hash_str_find(fieldspec, "var", sizeof("var")-1); char* varname = Z_STRVAL_P(val_ptr); // thrift type val_ptr = zend_hash_str_find(fieldspec, "type", sizeof("type")-1); if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr); int8_t ttype = Z_LVAL_P(val_ptr); zval rv; zval* prop = zend_read_property(Z_OBJCE_P(zthis), Z4_OBJ_P(zthis), varname, strlen(varname), false, &rv); if (Z_TYPE_P(prop) == IS_REFERENCE){ ZVAL_DEREF(prop); } if (Z_TYPE_P(prop) != IS_NULL) { transport.writeI8(ttype); transport.writeI16(fieldno); binary_serialize(ttype, transport, prop, fieldspec); } } transport.writeI8(T_STOP); // struct end } // 6 params: $transport $method_name $ttype $request_struct $seqID $strict_write PHP_FUNCTION(thrift_protocol_write_binary) { zval *protocol; zval *request_struct; zend_string *method_name; long msgtype, seqID; zend_bool strict_write; if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "oSlolb", &protocol, &method_name, &msgtype, &request_struct, &seqID, &strict_write) == FAILURE) { return; } try { zval* spec = zend_read_static_property(Z_OBJCE_P(request_struct), "_TSPEC", sizeof("_TSPEC")-1, true); if (spec) { ZVAL_DEREF(spec); } if (!spec || Z_TYPE_P(spec) != IS_ARRAY) { throw_tprotocolexception("Attempt serialize from non-Thrift object", INVALID_DATA); } PHPOutputTransport transport(protocol); protocol_writeMessageBegin(protocol, method_name, (int32_t) msgtype, (int32_t) seqID); binary_serialize_spec(request_struct, transport, Z_ARRVAL_P(spec)); transport.flush(); } catch (const PHPExceptionWrapper& ex) { // ex will be destructed, so copy to a zval that zend_throw_exception_object can take ownership of zval myex; ZVAL_COPY(&myex, ex); zend_throw_exception_object(&myex); RETURN_NULL(); } catch (const std::exception& ex) { throw_zend_exception_from_std_exception(ex); RETURN_NULL(); } } // 4 params: $transport $response_Typename $strict_read $buffer_size PHP_FUNCTION(thrift_protocol_read_binary) { zval *protocol; zend_string *obj_typename; zend_bool strict_read; size_t buffer_size = 8192; if (zend_parse_parameters(ZEND_NUM_ARGS(), "oSb|l", &protocol, &obj_typename, &strict_read, &buffer_size) == FAILURE) { return; } try { PHPInputTransport transport(protocol, buffer_size); int8_t messageType = 0; int32_t sz = transport.readI32(); if (sz < 0) { // Check for correct version number int32_t version = sz & VERSION_MASK; if (version != VERSION_1) { throw_tprotocolexception("Bad version identifier", BAD_VERSION); } messageType = (sz & 0x000000ff); int32_t namelen = transport.readI32(); // skip the name string and the sequence ID, we don't care about those transport.skip(namelen + 4); } else { if (strict_read) { throw_tprotocolexception("No version identifier... old protocol client in strict mode?", BAD_VERSION); } else { // Handle pre-versioned input transport.skip(sz); // skip string body messageType = transport.readI8(); transport.skip(4); // skip sequence number } } if (messageType == T_EXCEPTION) { zval ex; createObject("\\Thrift\\Exception\\TApplicationException", &ex); zval* spec = zend_read_static_property(Z_OBJCE(ex), "_TSPEC", sizeof("_TPSEC")-1, false); ZVAL_DEREF(spec); if (EG(exception)) { zend_object *ex = EG(exception); EG(exception) = nullptr; throw PHPExceptionWrapper(ex); } binary_deserialize_spec(&ex, transport, Z_ARRVAL_P(spec)); throw PHPExceptionWrapper(&ex); } createObject(ZSTR_VAL(obj_typename), return_value); zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, true); if (spec) { ZVAL_DEREF(spec); } if (!spec || Z_TYPE_P(spec) != IS_ARRAY) { throw_tprotocolexception("Attempt deserialize to non-Thrift object", INVALID_DATA); } binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec)); } catch (const PHPExceptionWrapper& ex) { // ex will be destructed, so copy to a zval that zend_throw_exception_object can ownership of zval myex; ZVAL_COPY(&myex, ex); zval_dtor(return_value); zend_throw_exception_object(&myex); RETURN_NULL(); } catch (const std::exception& ex) { throw_zend_exception_from_std_exception(ex); RETURN_NULL(); } } // 4 params: $transport $response_Typename $strict_read $buffer_size PHP_FUNCTION(thrift_protocol_read_binary_after_message_begin) { zval *protocol; zend_string *obj_typename; zend_bool strict_read; size_t buffer_size = 8192; if (zend_parse_parameters(ZEND_NUM_ARGS(), "oSb|l", &protocol, &obj_typename, &strict_read, &buffer_size) == FAILURE) { return; } try { PHPInputTransport transport(protocol, buffer_size); createObject(ZSTR_VAL(obj_typename), return_value); zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false); ZVAL_DEREF(spec); binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec)); } catch (const PHPExceptionWrapper& ex) { // ex will be destructed, so copy to a zval that zend_throw_exception_object can take ownership of zval myex; ZVAL_COPY(&myex, ex); zend_throw_exception_object(&myex); RETURN_NULL(); } catch (const std::exception& ex) { throw_zend_exception_from_std_exception(ex); RETURN_NULL(); } } #endif /* PHP_VERSION_ID >= 70000 */ thrift-0.16.0/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h000066400000000000000000000054371420101504100255010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #pragma once /* backward compat macros */ #if PHP_VERSION_ID >= 80000 # define Z4_OBJ_P(zval) (Z_OBJ_P(zval)) #else # define Z4_OBJ_P(zval) (zval) #endif #ifndef IS_MIXED # define IS_MIXED 0 #endif #ifndef ZEND_PARSE_PARAMETERS_NONE #define ZEND_PARSE_PARAMETERS_NONE() \ ZEND_PARSE_PARAMETERS_START(0, 0) \ ZEND_PARSE_PARAMETERS_END() #endif #ifndef ZEND_ARG_INFO_WITH_DEFAULT_VALUE #define ZEND_ARG_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, default_value) \ ZEND_ARG_INFO(pass_by_ref, name) #endif #if PHP_VERSION_ID < 70200 #undef ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ static const zend_internal_arg_info name[] = { \ { (const char*)(zend_uintptr_t)(required_num_args), ( #class_name ), 0, return_reference, allow_null, 0 }, #endif #ifndef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX # define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) #endif #ifndef ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX # define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(name, return_reference, num_args, type) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, num_args) #endif #ifndef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX # define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(name, return_reference, required_num_args, class_name, type) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args) #endif #ifndef ZEND_ARG_TYPE_MASK # define ZEND_ARG_TYPE_MASK(pass_by_ref, name, type_mask, default_value) \ ZEND_ARG_TYPE_INFO(pass_by_ref, name, 0, 0) #endif #ifndef ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE # define ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, type_hint, allow_null, default_value) \ ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) #endif #include "php_thrift_protocol_arginfo.h" thrift-0.16.0/lib/php/src/ext/thrift_protocol/php_thrift_protocol.stub.php000066400000000000000000000011101420101504100267750ustar00rootroot00000000000000<><"; self::$testArgs['testString3'] = "string that ends in double-backslash \\\\"; self::$testArgs['testUnicodeStringWithNonBMP'] = "สวัสดี/𝒯"; self::$testArgs['testDouble'] = 3.1415926535898; // TODO: add testBinary() call self::$testArgs['testByte'] = 0x01; self::$testArgs['testI32'] = pow(2, 30); if (PHP_INT_SIZE == 8) { self::$testArgs['testI64'] = pow(2, 60); } else { self::$testArgs['testI64'] = "1152921504606847000"; } self::$testArgs['testStruct'] = new Xtruct( array( 'string_thing' => 'worked', 'byte_thing' => 0x01, 'i32_thing' => pow(2, 30), 'i64_thing' => self::$testArgs['testI64'] ) ); self::$testArgs['testNestNested'] = new Xtruct( array( 'string_thing' => 'worked', 'byte_thing' => 0x01, 'i32_thing' => pow(2, 30), 'i64_thing' => self::$testArgs['testI64'] ) ); self::$testArgs['testNest'] = new Xtruct2( array( 'byte_thing' => 0x01, 'struct_thing' => self::$testArgs['testNestNested'], 'i32_thing' => pow(2, 15) ) ); self::$testArgs['testMap'] = array( 7 => 77, 8 => 88, 9 => 99 ); self::$testArgs['testStringMap'] = array( "a" => "123", "a b" => "with spaces ", "same" => "same", "0" => "numeric key", "longValue" => self::$testArgs['testString1'], self::$testArgs['testString1'] => "long key" ); self::$testArgs['testSet'] = array(1 => true, 5 => true, 6 => true); self::$testArgs['testList'] = array(1, 2, 3); self::$testArgs['testEnum'] = Numberz::ONE; self::$testArgs['testTypedef'] = 69; self::$testArgs['testMapMapExpectedResult'] = array( 4 => array( 1 => 1, 2 => 2, 3 => 3, 4 => 4, ), -4 => array( -4 => -4, -3 => -3, -2 => -2, -1 => -1 ) ); // testInsanity ... takes a few steps to set up! $xtruct1 = new Xtruct( array( 'string_thing' => 'Goodbye4', 'byte_thing' => 4, 'i32_thing' => 4, 'i64_thing' => 4 ) ); $xtruct2 = new Xtruct( array( 'string_thing' => 'Hello2', 'byte_thing' => 2, 'i32_thing' => 2, 'i64_thing' => 2 ) ); $userMap = array( Numberz::FIVE => 5, Numberz::EIGHT => 8 ); $insanity2 = new Insanity( array( 'userMap' => $userMap, 'xtructs' => array($xtruct1, $xtruct2) ) ); $insanity3 = $insanity2; $insanity6 = new Insanity( array( 'userMap' => null, 'xtructs' => null ) ); self::$testArgs['testInsanityExpectedResult'] = array( "1" => array( Numberz::TWO => $insanity2, Numberz::THREE => $insanity3 ), "2" => array( Numberz::SIX => $insanity6 ) ); } } thrift-0.16.0/lib/php/test/JsonSerialize/000077500000000000000000000000001420101504100201575ustar00rootroot00000000000000thrift-0.16.0/lib/php/test/JsonSerialize/JsonSerializeTest.php000066400000000000000000000102011420101504100243030ustar00rootroot00000000000000markTestSkipped('Requires PHP 5.4 or newer!'); } /** @var \Composer\Autoload\ClassLoader $loader */ $loader = require __DIR__ . '/../../../../vendor/autoload.php'; $loader->addPsr4('', __DIR__ . '/../packages/phpjs'); } public function testEmptyStruct() { $empty = new \ThriftTest\EmptyStruct(array('non_existing_key' => 'bar')); $this->assertEquals(new stdClass(), json_decode(json_encode($empty))); } public function testStringsAndInts() { $input = array( 'string_thing' => 'foo', 'i64_thing' => 1234567890, ); $xtruct = new \ThriftTest\Xtruct($input); // Xtruct's 'i32_thing' and 'byte_thing' fields should not be present here! $expected = new stdClass(); $expected->string_thing = $input['string_thing']; $expected->i64_thing = $input['i64_thing']; $this->assertEquals($expected, json_decode(json_encode($xtruct))); } public function testNestedStructs() { $xtruct2 = new \ThriftTest\Xtruct2(array( 'byte_thing' => 42, 'struct_thing' => new \ThriftTest\Xtruct(array( 'i32_thing' => 123456, )), )); $expected = new stdClass(); $expected->byte_thing = $xtruct2->byte_thing; $expected->struct_thing = new stdClass(); $expected->struct_thing->i32_thing = $xtruct2->struct_thing->i32_thing; $this->assertEquals($expected, json_decode(json_encode($xtruct2))); } public function testInsanity() { $xinput = array('string_thing' => 'foo'); $xtruct = new \ThriftTest\Xtruct($xinput); $insanity = new \ThriftTest\Insanity(array( 'xtructs' => array($xtruct, $xtruct, $xtruct) )); $expected = new stdClass(); $expected->xtructs = array((object)$xinput, (object)$xinput, (object)$xinput); $this->assertEquals($expected, json_decode(json_encode($insanity))); } public function testNestedLists() { $bonk = new \ThriftTest\Bonk(array('message' => 'foo')); $nested = new \ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk))))); $expected = new stdClass(); $expected->bonk = array(array(array((object)array('message' => 'foo')))); $this->assertEquals($expected, json_decode(json_encode($nested))); } public function testMaps() { $intmap = new \ThriftTest\ThriftTest_testMap_args(['thing' => [0 => 'zero']]); $emptymap = new \ThriftTest\ThriftTest_testMap_args([]); $this->assertEquals('{"thing":{"0":"zero"}}', json_encode($intmap)); $this->assertEquals('{}', json_encode($emptymap)); } public function testScalarTypes() { $b = new \ThriftTest\Bools(['im_true' => '1', 'im_false' => '0']); $this->assertEquals('{"im_true":true,"im_false":false}', json_encode($b)); $s = new \ThriftTest\StructA(['s' => 42]); $this->assertEquals('{"s":"42"}', json_encode($s)); } } thrift-0.16.0/lib/php/test/Makefile.am000077500000000000000000000034741420101504100174450ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # PHPUNIT=php $(top_srcdir)/vendor/bin/phpunit stubs: ../../../test/ThriftTest.thrift TestValidators.thrift mkdir -p ./packages/php $(THRIFT) --gen php -r --out ./packages/php ../../../test/ThriftTest.thrift mkdir -p ./packages/phpv mkdir -p ./packages/phpvo mkdir -p ./packages/phpjs $(THRIFT) --gen php:validate -r --out ./packages/phpv TestValidators.thrift $(THRIFT) --gen php:validate,oop -r --out ./packages/phpvo TestValidators.thrift $(THRIFT) --gen php:json -r --out ./packages/phpjs TestValidators.thrift deps: $(top_srcdir)/composer.json composer install --working-dir=$(top_srcdir) all-local: deps check-json-serializer: deps stubs $(PHPUNIT) --log-junit=TEST-log-json-serializer.xml JsonSerialize/ check-validator: deps stubs $(PHPUNIT) --log-junit=TEST-log-validator.xml Validator/ check-protocol: deps stubs $(PHPUNIT) --log-junit=TEST-log-protocol.xml Protocol/ check: deps stubs \ check-protocol \ check-validator \ check-json-serializer distclean-local: clean-local: $(RM) -r ./packages $(RM) TEST-*.xml thrift-0.16.0/lib/php/test/Protocol/000077500000000000000000000000001420101504100171775ustar00rootroot00000000000000thrift-0.16.0/lib/php/test/Protocol/BinarySerializerTest.php000066400000000000000000000037641420101504100240400ustar00rootroot00000000000000addPsr4('', __DIR__ . '/../packages/php'); } /** * We try to serialize and deserialize a random object to make sure no exceptions are thrown. * @see THRIFT-1579 */ public function testBinarySerializer() { $struct = new \ThriftTest\Xtruct(array('string_thing' => 'abc')); $serialized = TBinarySerializer::serialize($struct, 'ThriftTest\\Xtruct'); $deserialized = TBinarySerializer::deserialize($serialized, 'ThriftTest\\Xtruct'); $this->assertEquals($struct, $deserialized); } } thrift-0.16.0/lib/php/test/Protocol/TJSONProtocolFixtures.php000066400000000000000000000311241420101504100240620ustar00rootroot00000000000000<><"}}'; self::$testArgsJSON['testString3'] = '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}'; self::$testArgsJSON['testUnicodeStringWithNonBMP'] = '{"1":{"str":"สวัสดี\/𝒯"}}'; self::$testArgsJSON['testDouble'] = '{"1":{"dbl":3.1415926535898}}'; self::$testArgsJSON['testByte'] = '{"1":{"i8":1}}'; self::$testArgsJSON['testI32'] = '{"1":{"i32":1073741824}}'; if (PHP_INT_SIZE == 8) { self::$testArgsJSON['testI64'] = '{"1":{"i64":' . pow(2, 60) . '}}'; self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}}}'; self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}},"3":{"i32":32768}}}}'; } else { self::$testArgsJSON['testI64'] = '{"1":{"i64":1152921504606847000}}'; self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}'; self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}'; } self::$testArgsJSON['testMap'] = '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}'; self::$testArgsJSON['testStringMap'] = '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}]}}'; self::$testArgsJSON['testSet'] = '{"1":{"set":["i32",3,1,5,6]}}'; self::$testArgsJSON['testList'] = '{"1":{"lst":["i32",3,1,2,3]}}'; self::$testArgsJSON['testEnum'] = '{"1":{"i32":1}}'; self::$testArgsJSON['testTypedef'] = '{"1":{"i64":69}}'; self::$testArgsJSON['testMapMap'] = '{"0":{"map":["i32","map",2,{"4":["i32","i32",4,{"1":1,"2":2,"3":3,"4":4}],"-4":["i32","i32",4,{"-4":-4,"-3":-3,"-2":-2,"-1":-1}]}]}}'; self::$testArgsJSON['testInsanity'] = '{"0":{"map":["i64","map",2,{"1":["i32","rec",2,{"2":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}},"3":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}}}],"2":["i32","rec",1,{"6":{}}]}]}}'; } } thrift-0.16.0/lib/php/test/Protocol/TJSONProtocolTest.php000066400000000000000000000360771420101504100232040ustar00rootroot00000000000000addPsr4('', __DIR__ . '/../packages/php'); Fixtures::populateTestArgs(); TJSONProtocolFixtures::populateTestArgsJSON(); } public function setUp() { $this->transport = new TMemoryBuffer(); $this->protocol = new TJSONProtocol($this->transport); $this->transport->open(); } /** * WRITE TESTS */ public function testVoidWrite() { $args = new \ThriftTest\ThriftTest_testVoid_args(); $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testVoid']; $this->assertEquals($expected, $actual); } public function testString1Write() { $args = new \ThriftTest\ThriftTest_testString_args(); $args->thing = Fixtures::$testArgs['testString1']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testString1']; $this->assertEquals($expected, $actual); } public function testString2Write() { $args = new \ThriftTest\ThriftTest_testString_args(); $args->thing = Fixtures::$testArgs['testString2']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testString2']; $this->assertEquals($expected, $actual); } public function testDoubleWrite() { $args = new \ThriftTest\ThriftTest_testDouble_args(); $args->thing = Fixtures::$testArgs['testDouble']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testDouble']; $this->assertEquals($expected, $actual); } public function testByteWrite() { $args = new \ThriftTest\ThriftTest_testByte_args(); $args->thing = Fixtures::$testArgs['testByte']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testByte']; $this->assertEquals($expected, $actual); } public function testI32Write() { $args = new \ThriftTest\ThriftTest_testI32_args(); $args->thing = Fixtures::$testArgs['testI32']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testI32']; $this->assertEquals($expected, $actual); } public function testI64Write() { $args = new \ThriftTest\ThriftTest_testI64_args(); $args->thing = Fixtures::$testArgs['testI64']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testI64']; $this->assertEquals($expected, $actual); } public function testStructWrite() { $args = new \ThriftTest\ThriftTest_testStruct_args(); $args->thing = Fixtures::$testArgs['testStruct']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testStruct']; $this->assertEquals($expected, $actual); } public function testNestWrite() { $args = new \ThriftTest\ThriftTest_testNest_args(); $args->thing = Fixtures::$testArgs['testNest']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testNest']; $this->assertEquals($expected, $actual); } public function testMapWrite() { $args = new \ThriftTest\ThriftTest_testMap_args(); $args->thing = Fixtures::$testArgs['testMap']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testMap']; $this->assertEquals($expected, $actual); } public function testStringMapWrite() { $args = new \ThriftTest\ThriftTest_testStringMap_args(); $args->thing = Fixtures::$testArgs['testStringMap']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testStringMap']; /* * The $actual returns unescaped string. * It is required to to decode then encode it again * to get the expected escaped unicode. */ $this->assertEquals($expected, json_encode(json_decode($actual))); } public function testSetWrite() { $args = new \ThriftTest\ThriftTest_testSet_args(); $args->thing = Fixtures::$testArgs['testSet']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testSet']; $this->assertEquals($expected, $actual); } public function testListWrite() { $args = new \ThriftTest\ThriftTest_testList_args(); $args->thing = Fixtures::$testArgs['testList']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testList']; $this->assertEquals($expected, $actual); } public function testEnumWrite() { $args = new \ThriftTest\ThriftTest_testEnum_args(); $args->thing = Fixtures::$testArgs['testEnum']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testEnum']; $this->assertEquals($expected, $actual); } public function testTypedefWrite() { $args = new \ThriftTest\ThriftTest_testTypedef_args(); $args->thing = Fixtures::$testArgs['testTypedef']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testTypedef']; $this->assertEquals($expected, $actual); } /** * READ TESTS */ public function testVoidRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testVoid'] ); $args = new \ThriftTest\ThriftTest_testVoid_args(); $args->read($this->protocol); } public function testString1Read() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testString1'] ); $args = new \ThriftTest\ThriftTest_testString_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testString1']; $this->assertEquals($expected, $actual); } public function testString2Read() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testString2'] ); $args = new \ThriftTest\ThriftTest_testString_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testString2']; $this->assertEquals($expected, $actual); } public function testString3Write() { $args = new \ThriftTest\ThriftTest_testString_args(); $args->thing = Fixtures::$testArgs['testString3']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testString3']; $this->assertEquals($expected, $actual); } public function testString4Write() { $args = new \ThriftTest\ThriftTest_testString_args(); $args->thing = Fixtures::$testArgs['testUnicodeStringWithNonBMP']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TJSONProtocolFixtures::$testArgsJSON['testUnicodeStringWithNonBMP']; $this->assertEquals($expected, $actual); } public function testDoubleRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testDouble'] ); $args = new \ThriftTest\ThriftTest_testDouble_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testDouble']; $this->assertEquals($expected, $actual); } public function testByteRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testByte'] ); $args = new \ThriftTest\ThriftTest_testByte_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testByte']; $this->assertEquals($expected, $actual); } public function testI32Read() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testI32'] ); $args = new \ThriftTest\ThriftTest_testI32_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testI32']; $this->assertEquals($expected, $actual); } public function testI64Read() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testI64'] ); $args = new \ThriftTest\ThriftTest_testI64_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testI64']; $this->assertEquals($expected, $actual); } public function testStructRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testStruct'] ); $args = new \ThriftTest\ThriftTest_testStruct_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testStruct']; $this->assertEquals($expected, $actual); } public function testNestRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testNest'] ); $args = new \ThriftTest\ThriftTest_testNest_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testNest']; $this->assertEquals($expected, $actual); } public function testMapRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testMap'] ); $args = new \ThriftTest\ThriftTest_testMap_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testMap']; $this->assertEquals($expected, $actual); } public function testStringMapRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testStringMap'] ); $args = new \ThriftTest\ThriftTest_testStringMap_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testStringMap']; $this->assertEquals($expected, $actual); } public function testSetRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testSet'] ); $args = new \ThriftTest\ThriftTest_testSet_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testSet']; $this->assertEquals($expected, $actual); } public function testListRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testList'] ); $args = new \ThriftTest\ThriftTest_testList_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testList']; $this->assertEquals($expected, $actual); } public function testEnumRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testEnum'] ); $args = new \ThriftTest\ThriftTest_testEnum_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testEnum']; $this->assertEquals($expected, $actual); } public function testTypedefRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testTypedef'] ); $args = new \ThriftTest\ThriftTest_testTypedef_args(); $args->read($this->protocol); $actual = $args->thing; $expected = Fixtures::$testArgs['testTypedef']; $this->assertEquals($expected, $actual); } public function testMapMapRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testMapMap'] ); $result = new \ThriftTest\ThriftTest_testMapMap_result(); $result->read($this->protocol); $actual = $result->success; $expected = Fixtures::$testArgs['testMapMapExpectedResult']; $this->assertEquals($expected, $actual); } public function testInsanityRead() { $this->transport->write( TJSONProtocolFixtures::$testArgsJSON['testInsanity'] ); $result = new \ThriftTest\ThriftTest_testInsanity_result(); $result->read($this->protocol); $actual = $result->success; $expected = Fixtures::$testArgs['testInsanityExpectedResult']; $this->assertEquals($expected, $actual); } } thrift-0.16.0/lib/php/test/Protocol/TSimpleJSONProtocolFixtures.php000066400000000000000000000317631420101504100252450ustar00rootroot00000000000000<><"}'; self::$testArgsJSON['testDouble'] = '{"thing":3.1415926535898}'; self::$testArgsJSON['testByte'] = '{"thing":1}'; self::$testArgsJSON['testI32'] = '{"thing":1073741824}'; if (PHP_INT_SIZE == 8) { self::$testArgsJSON['testI64'] = '{"thing":' . pow(2, 60) . '}'; self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '}}'; self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '},"i32_thing":32768}}'; } else { self::$testArgsJSON['testI64'] = '{"thing":1152921504606847000}'; self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000}}'; self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000},"i32_thing":32768}}'; } self::$testArgsJSON['testMap'] = '{"thing":{"7":77,"8":88,"9":99}}'; self::$testArgsJSON['testStringMap'] = '{"thing":{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}}'; self::$testArgsJSON['testSet'] = '{"thing":[1,5,6]}'; self::$testArgsJSON['testList'] = '{"thing":[1,2,3]}'; self::$testArgsJSON['testEnum'] = '{"thing":1}'; self::$testArgsJSON['testTypedef'] = '{"thing":69}'; } } thrift-0.16.0/lib/php/test/Protocol/TSimpleJSONProtocolTest.php000066400000000000000000000173431420101504100243510ustar00rootroot00000000000000addPsr4('', __DIR__ . '/../packages/php'); Fixtures::populateTestArgs(); TSimpleJSONProtocolFixtures::populateTestArgsSimpleJSON(); } public function setUp() { $this->transport = new TMemoryBuffer(); $this->protocol = new TSimpleJSONProtocol($this->transport); $this->transport->open(); } /** * WRITE TESTS */ public function testVoidWrite() { $args = new \ThriftTest\ThriftTest_testVoid_args(); $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testVoid']; $this->assertEquals($expected, $actual); } public function testString1Write() { $args = new \ThriftTest\ThriftTest_testString_args(); $args->thing = Fixtures::$testArgs['testString1']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString1']; $this->assertEquals($expected, $actual); } public function testString2Write() { $args = new \ThriftTest\ThriftTest_testString_args(); $args->thing = Fixtures::$testArgs['testString2']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString2']; $this->assertEquals($expected, $actual); } public function testDoubleWrite() { $args = new \ThriftTest\ThriftTest_testDouble_args(); $args->thing = Fixtures::$testArgs['testDouble']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testDouble']; $this->assertEquals($expected, $actual); } public function testByteWrite() { $args = new \ThriftTest\ThriftTest_testByte_args(); $args->thing = Fixtures::$testArgs['testByte']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testByte']; $this->assertEquals($expected, $actual); } public function testI32Write() { $args = new \ThriftTest\ThriftTest_testI32_args(); $args->thing = Fixtures::$testArgs['testI32']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI32']; $this->assertEquals($expected, $actual); } public function testI64Write() { $args = new \ThriftTest\ThriftTest_testI64_args(); $args->thing = Fixtures::$testArgs['testI64']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI64']; $this->assertEquals($expected, $actual); } public function testStructWrite() { $args = new \ThriftTest\ThriftTest_testStruct_args(); $args->thing = Fixtures::$testArgs['testStruct']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStruct']; $this->assertEquals($expected, $actual); } public function testNestWrite() { $args = new \ThriftTest\ThriftTest_testNest_args(); $args->thing = Fixtures::$testArgs['testNest']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testNest']; $this->assertEquals($expected, $actual); } public function testMapWrite() { $args = new \ThriftTest\ThriftTest_testMap_args(); $args->thing = Fixtures::$testArgs['testMap']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testMap']; $this->assertEquals($expected, $actual); } public function testStringMapWrite() { $args = new \ThriftTest\ThriftTest_testStringMap_args(); $args->thing = Fixtures::$testArgs['testStringMap']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStringMap']; $this->assertEquals($expected, $actual); } public function testSetWrite() { $args = new \ThriftTest\ThriftTest_testSet_args(); $args->thing = Fixtures::$testArgs['testSet']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testSet']; $this->assertEquals($expected, $actual); } public function testListWrite() { $args = new \ThriftTest\ThriftTest_testList_args(); $args->thing = Fixtures::$testArgs['testList']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testList']; $this->assertEquals($expected, $actual); } public function testEnumWrite() { $args = new \ThriftTest\ThriftTest_testEnum_args(); $args->thing = Fixtures::$testArgs['testEnum']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testEnum']; $this->assertEquals($expected, $actual); } public function testTypedefWrite() { $args = new \ThriftTest\ThriftTest_testTypedef_args(); $args->thing = Fixtures::$testArgs['testTypedef']; $args->write($this->protocol); $actual = $this->transport->read(Fixtures::$bufsize); $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testTypedef']; $this->assertEquals($expected, $actual); } } thrift-0.16.0/lib/php/test/TestValidators.thrift000066400000000000000000000017711420101504100215760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace php TestValidators include "../../../test/ThriftTest.thrift" union UnionOfStrings { 1: string aa; 2: string bb; } service TestService { void test() throws(1: ThriftTest.Xception xception); } thrift-0.16.0/lib/php/test/Validator/000077500000000000000000000000001420101504100173235ustar00rootroot00000000000000thrift-0.16.0/lib/php/test/Validator/BaseValidatorTest.php000066400000000000000000000113401420101504100234130ustar00rootroot00000000000000assertNoReadValidator('ThriftTest\EmptyStruct'); $this->assertNoWriteValidator('ThriftTest\EmptyStruct'); } public function testBonkValidator() { $this->assertNoReadValidator('ThriftTest\Bonk'); $this->assertHasWriteValidator('ThriftTest\Bonk'); } public function testStructAValidator() { $this->assertHasReadValidator('ThriftTest\StructA'); $this->assertHasWriteValidator('ThriftTest\StructA'); } public function testUnionOfStringsValidator() { $this->assertNoWriteValidator('TestValidators\UnionOfStrings'); } public function testServiceResultValidator() { $this->assertNoReadValidator('TestValidators\TestService_test_result'); $this->assertNoWriteValidator('TestValidators\TestService_test_result'); } public function testReadEmpty() { $bonk = new \ThriftTest\Bonk(); $transport = new TMemoryBuffer("\000"); $protocol = new TBinaryProtocol($transport); $bonk->read($protocol); } public function testWriteEmpty() { $bonk = new \ThriftTest\Bonk(); $transport = new TMemoryBuffer(); $protocol = new TBinaryProtocol($transport); try { $bonk->write($protocol); $this->fail('Bonk was able to write an empty object'); } catch (TProtocolException $e) { } } public function testWriteWithMissingRequired() { // Check that we are not able to write StructA with a missing required field $structa = new \ThriftTest\StructA(); $transport = new TMemoryBuffer(); $protocol = new TBinaryProtocol($transport); try { $structa->write($protocol); $this->fail('StructA was able to write an empty object'); } catch (TProtocolException $e) { } } public function testReadStructA() { $transport = new TMemoryBuffer(base64_decode('CwABAAAAA2FiYwA=')); $protocol = new TBinaryProtocol($transport); $structa = new \ThriftTest\StructA(); $structa->read($protocol); $this->assertEquals("abc", $structa->s); } public function testWriteStructA() { $transport = new TMemoryBuffer(); $protocol = new TBinaryProtocol($transport); $structa = new \ThriftTest\StructA(); $structa->s = "abc"; $structa->write($protocol); $writeResult = base64_encode($transport->getBuffer()); $this->assertEquals('CwABAAAAA2FiYwA=', $writeResult); } protected static function assertHasReadValidator($class) { if (!static::hasReadValidator($class)) { static::fail($class . ' class should have a read validator'); } } protected static function assertNoReadValidator($class) { if (static::hasReadValidator($class)) { static::fail($class . ' class should not have a write validator'); } } protected static function assertHasWriteValidator($class) { if (!static::hasWriteValidator($class)) { static::fail($class . ' class should have a write validator'); } } protected static function assertNoWriteValidator($class) { if (static::hasWriteValidator($class)) { static::fail($class . ' class should not have a write validator'); } } private static function hasReadValidator($class) { $rc = new \ReflectionClass($class); return $rc->hasMethod('_validateForRead'); } private static function hasWriteValidator($class) { $rc = new \ReflectionClass($class); return $rc->hasMethod('_validateForWrite'); } } thrift-0.16.0/lib/php/test/Validator/ValidatorTest.php000066400000000000000000000024321420101504100226220ustar00rootroot00000000000000addPsr4('', __DIR__ . '/../packages/phpv'); } } thrift-0.16.0/lib/php/test/Validator/ValidatorTestOop.php000066400000000000000000000024461420101504100233050ustar00rootroot00000000000000addPsr4('', __DIR__ . '/../packages/phpvo'); } } thrift-0.16.0/lib/php/thrift_protocol.ini000066400000000000000000000000351420101504100203370ustar00rootroot00000000000000extension=thrift_protocol.so thrift-0.16.0/lib/py/000077500000000000000000000000001420101504100142605ustar00rootroot00000000000000thrift-0.16.0/lib/py/CMakeLists.txt000066400000000000000000000035711420101504100170260ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # include_directories(${PYTHON_INCLUDE_DIRS}) add_custom_target(python_build ALL COMMAND ${THRIFT_COMPILER} --gen py test/test_thrift_file/TestServer.thrift COMMAND ${PYTHON_EXECUTABLE} setup.py build WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Building Python library" ) if(BUILD_TESTING) add_test(PythonTestSSLSocket ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/test_sslsocket.py) add_test(PythonThriftJson ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_json.py) add_test(PythonThriftTransport ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_transport.py) add_test(PythonThriftTBinaryProtocol ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_TBinaryProtocol.py) add_test(PythonThriftTZlibTransport ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_TZlibTransport.py) add_test(PythonThriftProtocol ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_TCompactProtocol.py) add_test(PythonThriftTNonblockingServer ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_TNonblockingServer.py) endif() thrift-0.16.0/lib/py/MANIFEST.in000066400000000000000000000000221420101504100160100ustar00rootroot00000000000000include src/ext/* thrift-0.16.0/lib/py/Makefile.am000066400000000000000000000050271420101504100163200ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # AUTOMAKE_OPTIONS = serial-tests DESTDIR ?= / if WITH_PY3 py3-build: $(PYTHON3) setup.py build py3-test: py3-build $(PYTHON3) test/thrift_json.py $(PYTHON3) test/thrift_transport.py $(PYTHON3) test/test_sslsocket.py $(PYTHON3) test/thrift_TBinaryProtocol.py $(PYTHON3) test/thrift_TZlibTransport.py $(PYTHON3) test/thrift_TCompactProtocol.py $(PYTHON3) test/thrift_TNonblockingServer.py $(PYTHON3) test/thrift_TSerializer.py else py3-build: py3-test: endif all-local: py3-build $(PYTHON) setup.py build ${THRIFT} --gen py test/test_thrift_file/TestServer.thrift # We're ignoring prefix here because site-packages seems to be # the equivalent of /usr/local/lib in Python land. # Old version (can't put inline because it's not portable). #$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS) install-exec-hook: $(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS) check-local: all py3-test $(PYTHON) test/thrift_json.py $(PYTHON) test/thrift_transport.py $(PYTHON) test/test_sslsocket.py $(PYTHON) test/test_socket.py $(PYTHON) test/thrift_TBinaryProtocol.py $(PYTHON) test/thrift_TZlibTransport.py $(PYTHON) test/thrift_TCompactProtocol.py $(PYTHON) test/thrift_TNonblockingServer.py $(PYTHON) test/thrift_TSerializer.py clean-local: $(RM) -r build $(RM) -r gen-py find . -type f \( -iname "*.pyc" \) | xargs rm -f find . -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf dist-hook: find $(distdir) -type f \( -iname "*.pyc" \) | xargs rm -f find $(distdir) -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf EXTRA_DIST = \ CMakeLists.txt \ MANIFEST.in \ coding_standards.md \ compat \ setup.py \ setup.cfg \ src \ test \ README.md thrift-0.16.0/lib/py/README.md000066400000000000000000000027121420101504100155410ustar00rootroot00000000000000Thrift Python Software Library License ======= Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Using Thrift with Python ======================== Thrift is provided as a set of Python packages. The top level package is thrift, and there are subpackages for the protocol, transport, and server code. Each package contains modules using standard Thrift naming conventions (i.e. TProtocol, TTransport) and implementations in corresponding modules (i.e. TSocket). There is also a subpackage reflection, which contains the generated code for the reflection structures. The Python libraries can be installed manually using the provided setup.py file, or automatically using the install hook provided via autoconf/automake. To use the latter, become superuser and do make install. thrift-0.16.0/lib/py/coding_standards.md000066400000000000000000000004311420101504100201060ustar00rootroot00000000000000## Python Coding Standards Please follow: * [Thrift General Coding Standards](/doc/coding_standards.md) * Code Style for Python Code [PEP8](http://legacy.python.org/dev/peps/pep-0008/) When in doubt - check with or online with . thrift-0.16.0/lib/py/compat/000077500000000000000000000000001420101504100155435ustar00rootroot00000000000000thrift-0.16.0/lib/py/compat/win32/000077500000000000000000000000001420101504100165055ustar00rootroot00000000000000thrift-0.16.0/lib/py/compat/win32/stdint.h000066400000000000000000000170601420101504100201670ustar00rootroot00000000000000// ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2008 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. 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. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we should wrap include with 'extern "C++" {}' // or compiler give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #ifdef __cplusplus extern "C" { #endif # include #ifdef __cplusplus } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants #define INTMAX_C INT64_C #define UINTMAX_C UINT64_C #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_STDINT_H_ ] thrift-0.16.0/lib/py/setup.cfg000066400000000000000000000001361420101504100161010ustar00rootroot00000000000000[install] optimize = 1 [metadata] description_file = README.md [flake8] max-line-length = 100 thrift-0.16.0/lib/py/setup.py000066400000000000000000000111461420101504100157750ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import sys try: from setuptools import setup, Extension except Exception: from distutils.core import setup, Extension from distutils.command.build_ext import build_ext from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError # Fix to build sdist under vagrant import os if 'vagrant' in str(os.environ): try: del os.link except AttributeError: pass include_dirs = ['src'] if sys.platform == 'win32': include_dirs.append('compat/win32') ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOError) else: ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError) class BuildFailed(Exception): pass class ve_build_ext(build_ext): def run(self): try: build_ext.run(self) except DistutilsPlatformError: raise BuildFailed() def build_extension(self, ext): try: build_ext.build_extension(self, ext) except ext_errors: raise BuildFailed() def read_file(path): """ Return the contents of a file Arguments: - path: path to the file Returns: - contents of the file """ with open(path, "r") as desc_file: return desc_file.read().rstrip() def run_setup(with_binary): if with_binary: extensions = dict( ext_modules=[ Extension('thrift.protocol.fastbinary', extra_compile_args=['-std=c++11'], sources=[ 'src/ext/module.cpp', 'src/ext/types.cpp', 'src/ext/binary.cpp', 'src/ext/compact.cpp', ], include_dirs=include_dirs, ) ], cmdclass=dict(build_ext=ve_build_ext) ) else: extensions = dict() ssl_deps = [] if sys.version_info[0] == 2: ssl_deps.append('ipaddress') if sys.hexversion < 0x03050000: ssl_deps.append('backports.ssl_match_hostname>=3.5') tornado_deps = ['tornado>=4.0'] twisted_deps = ['twisted'] setup(name='thrift', version='0.16.0', description='Python bindings for the Apache Thrift RPC system', long_description=read_file("README.md"), long_description_content_type="text/markdown", author='Apache Thrift Developers', author_email='dev@thrift.apache.org', url='http://thrift.apache.org', license='Apache License 2.0', install_requires=['six>=1.7.2'], extras_require={ 'ssl': ssl_deps, 'tornado': tornado_deps, 'twisted': twisted_deps, 'all': ssl_deps + tornado_deps + twisted_deps, }, packages=[ 'thrift', 'thrift.protocol', 'thrift.transport', 'thrift.server', ], package_dir={'thrift': 'src'}, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Libraries', 'Topic :: System :: Networking' ], zip_safe=False, **extensions ) try: with_binary = True run_setup(with_binary) except BuildFailed: print() print('*' * 80) print("An error occurred while trying to compile with the C extension enabled") print("Attempting to build without the extension now") print('*' * 80) print() run_setup(False) thrift-0.16.0/lib/py/src/000077500000000000000000000000001420101504100150475ustar00rootroot00000000000000thrift-0.16.0/lib/py/src/TMultiplexedProcessor.py000066400000000000000000000064111420101504100217430ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from thrift.Thrift import TProcessor, TMessageType from thrift.protocol import TProtocolDecorator, TMultiplexedProtocol from thrift.protocol.TProtocol import TProtocolException class TMultiplexedProcessor(TProcessor): def __init__(self): self.defaultProcessor = None self.services = {} def registerDefault(self, processor): """ If a non-multiplexed processor connects to the server and wants to communicate, use the given processor to handle it. This mechanism allows servers to upgrade from non-multiplexed to multiplexed in a backwards-compatible way and still handle old clients. """ self.defaultProcessor = processor def registerProcessor(self, serviceName, processor): self.services[serviceName] = processor def on_message_begin(self, func): for key in self.services.keys(): self.services[key].on_message_begin(func) def process(self, iprot, oprot): (name, type, seqid) = iprot.readMessageBegin() if type != TMessageType.CALL and type != TMessageType.ONEWAY: raise TProtocolException( TProtocolException.NOT_IMPLEMENTED, "TMultiplexedProtocol only supports CALL & ONEWAY") index = name.find(TMultiplexedProtocol.SEPARATOR) if index < 0: if self.defaultProcessor: return self.defaultProcessor.process( StoredMessageProtocol(iprot, (name, type, seqid)), oprot) else: raise TProtocolException( TProtocolException.NOT_IMPLEMENTED, "Service name not found in message name: " + name + ". " + "Did you forget to use TMultiplexedProtocol in your client?") serviceName = name[0:index] call = name[index + len(TMultiplexedProtocol.SEPARATOR):] if serviceName not in self.services: raise TProtocolException( TProtocolException.NOT_IMPLEMENTED, "Service name not found: " + serviceName + ". " + "Did you forget to call registerProcessor()?") standardMessage = (call, type, seqid) return self.services[serviceName].process( StoredMessageProtocol(iprot, standardMessage), oprot) class StoredMessageProtocol(TProtocolDecorator.TProtocolDecorator): def __init__(self, protocol, messageBegin): self.messageBegin = messageBegin def readMessageBegin(self): return self.messageBegin thrift-0.16.0/lib/py/src/TRecursive.py000066400000000000000000000064051420101504100175210ustar00rootroot00000000000000# 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. from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals from thrift.Thrift import TType TYPE_IDX = 1 SPEC_ARGS_IDX = 3 SPEC_ARGS_CLASS_REF_IDX = 0 SPEC_ARGS_THRIFT_SPEC_IDX = 1 def fix_spec(all_structs): """Wire up recursive references for all TStruct definitions inside of each thrift_spec.""" for struc in all_structs: spec = struc.thrift_spec for thrift_spec in spec: if thrift_spec is None: continue elif thrift_spec[TYPE_IDX] == TType.STRUCT: other = thrift_spec[SPEC_ARGS_IDX][SPEC_ARGS_CLASS_REF_IDX].thrift_spec thrift_spec[SPEC_ARGS_IDX][SPEC_ARGS_THRIFT_SPEC_IDX] = other elif thrift_spec[TYPE_IDX] in (TType.LIST, TType.SET): _fix_list_or_set(thrift_spec[SPEC_ARGS_IDX]) elif thrift_spec[TYPE_IDX] == TType.MAP: _fix_map(thrift_spec[SPEC_ARGS_IDX]) def _fix_list_or_set(element_type): # For a list or set, the thrift_spec entry looks like, # (1, TType.LIST, 'lister', (TType.STRUCT, [RecList, None], False), None, ), # 1 # so ``element_type`` will be, # (TType.STRUCT, [RecList, None], False) if element_type[0] == TType.STRUCT: element_type[1][1] = element_type[1][0].thrift_spec elif element_type[0] in (TType.LIST, TType.SET): _fix_list_or_set(element_type[1]) elif element_type[0] == TType.MAP: _fix_map(element_type[1]) def _fix_map(element_type): # For a map of key -> value type, ``element_type`` will be, # (TType.I16, None, TType.STRUCT, [RecMapBasic, None], False), None, ) # which is just a normal struct definition. # # For a map of key -> list / set, ``element_type`` will be, # (TType.I16, None, TType.LIST, (TType.STRUCT, [RecMapList, None], False), False) # and we need to process the 3rd element as a list. # # For a map of key -> map, ``element_type`` will be, # (TType.I16, None, TType.MAP, (TType.I16, None, TType.STRUCT, # [RecMapMap, None], False), False) # and need to process 3rd element as a map. # Is the map key a struct? if element_type[0] == TType.STRUCT: element_type[1][1] = element_type[1][0].thrift_spec elif element_type[0] in (TType.LIST, TType.SET): _fix_list_or_set(element_type[1]) elif element_type[0] == TType.MAP: _fix_map(element_type[1]) # Is the map value a struct? if element_type[2] == TType.STRUCT: element_type[3][1] = element_type[3][0].thrift_spec elif element_type[2] in (TType.LIST, TType.SET): _fix_list_or_set(element_type[3]) elif element_type[2] == TType.MAP: _fix_map(element_type[3]) thrift-0.16.0/lib/py/src/TSCons.py000066400000000000000000000024351420101504100165760ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from os import path from SCons.Builder import Builder from six.moves import map def scons_env(env, add=''): opath = path.dirname(path.abspath('$TARGET')) lstr = 'thrift --gen cpp -o ' + opath + ' ' + add + ' $SOURCE' cppbuild = Builder(action=lstr) env.Append(BUILDERS={'ThriftCpp': cppbuild}) def gen_cpp(env, dir, file): scons_env(env) suffixes = ['_types.h', '_types.cpp'] targets = map(lambda s: 'gen-cpp/' + file + s, suffixes) return env.ThriftCpp(targets, dir + file + '.thrift') thrift-0.16.0/lib/py/src/TSerialization.py000066400000000000000000000025551420101504100203710ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from .protocol import TBinaryProtocol from .transport import TTransport def serialize(thrift_object, protocol_factory=TBinaryProtocol.TBinaryProtocolFactory()): transport = TTransport.TMemoryBuffer() protocol = protocol_factory.getProtocol(transport) thrift_object.write(protocol) return transport.getvalue() def deserialize(base, buf, protocol_factory=TBinaryProtocol.TBinaryProtocolFactory()): transport = TTransport.TMemoryBuffer(buf) protocol = protocol_factory.getProtocol(transport) base.read(protocol) return base thrift-0.16.0/lib/py/src/TTornado.py000066400000000000000000000144071420101504100171610ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from __future__ import absolute_import import logging import socket import struct from .transport.TTransport import TTransportException, TTransportBase, TMemoryBuffer from io import BytesIO from collections import deque from contextlib import contextmanager from tornado import gen, iostream, ioloop, tcpserver, concurrent __all__ = ['TTornadoServer', 'TTornadoStreamTransport'] logger = logging.getLogger(__name__) class _Lock(object): def __init__(self): self._waiters = deque() def acquired(self): return len(self._waiters) > 0 @gen.coroutine def acquire(self): blocker = self._waiters[-1] if self.acquired() else None future = concurrent.Future() self._waiters.append(future) if blocker: yield blocker raise gen.Return(self._lock_context()) def release(self): assert self.acquired(), 'Lock not aquired' future = self._waiters.popleft() future.set_result(None) @contextmanager def _lock_context(self): try: yield finally: self.release() class TTornadoStreamTransport(TTransportBase): """a framed, buffered transport over a Tornado stream""" def __init__(self, host, port, stream=None, io_loop=None): self.host = host self.port = port self.io_loop = io_loop or ioloop.IOLoop.current() self.__wbuf = BytesIO() self._read_lock = _Lock() # servers provide a ready-to-go stream self.stream = stream def with_timeout(self, timeout, future): return gen.with_timeout(timeout, future, self.io_loop) @gen.coroutine def open(self, timeout=None): logger.debug('socket connecting') sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) self.stream = iostream.IOStream(sock) try: connect = self.stream.connect((self.host, self.port)) if timeout is not None: yield self.with_timeout(timeout, connect) else: yield connect except (socket.error, IOError, ioloop.TimeoutError) as e: message = 'could not connect to {}:{} ({})'.format(self.host, self.port, e) raise TTransportException( type=TTransportException.NOT_OPEN, message=message) raise gen.Return(self) def set_close_callback(self, callback): """ Should be called only after open() returns """ self.stream.set_close_callback(callback) def close(self): # don't raise if we intend to close self.stream.set_close_callback(None) self.stream.close() def read(self, _): # The generated code for Tornado shouldn't do individual reads -- only # frames at a time assert False, "you're doing it wrong" @contextmanager def io_exception_context(self): try: yield except (socket.error, IOError) as e: raise TTransportException( type=TTransportException.END_OF_FILE, message=str(e)) except iostream.StreamBufferFullError as e: raise TTransportException( type=TTransportException.UNKNOWN, message=str(e)) @gen.coroutine def readFrame(self): # IOStream processes reads one at a time with (yield self._read_lock.acquire()): with self.io_exception_context(): frame_header = yield self.stream.read_bytes(4) if len(frame_header) == 0: raise iostream.StreamClosedError('Read zero bytes from stream') frame_length, = struct.unpack('!i', frame_header) frame = yield self.stream.read_bytes(frame_length) raise gen.Return(frame) def write(self, buf): self.__wbuf.write(buf) def flush(self): frame = self.__wbuf.getvalue() # reset wbuf before write/flush to preserve state on underlying failure frame_length = struct.pack('!i', len(frame)) self.__wbuf = BytesIO() with self.io_exception_context(): return self.stream.write(frame_length + frame) class TTornadoServer(tcpserver.TCPServer): def __init__(self, processor, iprot_factory, oprot_factory=None, *args, **kwargs): super(TTornadoServer, self).__init__(*args, **kwargs) self._processor = processor self._iprot_factory = iprot_factory self._oprot_factory = (oprot_factory if oprot_factory is not None else iprot_factory) @gen.coroutine def handle_stream(self, stream, address): host, port = address[:2] trans = TTornadoStreamTransport(host=host, port=port, stream=stream, io_loop=self.io_loop) oprot = self._oprot_factory.getProtocol(trans) try: while not trans.stream.closed(): try: frame = yield trans.readFrame() except TTransportException as e: if e.type == TTransportException.END_OF_FILE: break else: raise tr = TMemoryBuffer(frame) iprot = self._iprot_factory.getProtocol(tr) yield self._processor.process(iprot, oprot) except Exception: logger.exception('thrift exception in handle_stream') trans.close() logger.info('client disconnected %s:%d', host, port) thrift-0.16.0/lib/py/src/Thrift.py000066400000000000000000000126631420101504100166710ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # class TType(object): STOP = 0 VOID = 1 BOOL = 2 BYTE = 3 I08 = 3 DOUBLE = 4 I16 = 6 I32 = 8 I64 = 10 STRING = 11 UTF7 = 11 STRUCT = 12 MAP = 13 SET = 14 LIST = 15 UTF8 = 16 UTF16 = 17 _VALUES_TO_NAMES = ( 'STOP', 'VOID', 'BOOL', 'BYTE', 'DOUBLE', None, 'I16', None, 'I32', None, 'I64', 'STRING', 'STRUCT', 'MAP', 'SET', 'LIST', 'UTF8', 'UTF16', ) class TMessageType(object): CALL = 1 REPLY = 2 EXCEPTION = 3 ONEWAY = 4 class TProcessor(object): """Base class for processor, which works on two streams.""" def process(self, iprot, oprot): """ Process a request. The normal behvaior is to have the processor invoke the correct handler and then it is the server's responsibility to write the response to oprot. """ pass def on_message_begin(self, func): """ Install a callback that receives (name, type, seqid) after the message header is read. """ pass class TException(Exception): """Base class for all thrift exceptions.""" def __init__(self, message=None): Exception.__init__(self, message) super(TException, self).__setattr__("message", message) class TApplicationException(TException): """Application level thrift exceptions.""" UNKNOWN = 0 UNKNOWN_METHOD = 1 INVALID_MESSAGE_TYPE = 2 WRONG_METHOD_NAME = 3 BAD_SEQUENCE_ID = 4 MISSING_RESULT = 5 INTERNAL_ERROR = 6 PROTOCOL_ERROR = 7 INVALID_TRANSFORM = 8 INVALID_PROTOCOL = 9 UNSUPPORTED_CLIENT_TYPE = 10 def __init__(self, type=UNKNOWN, message=None): TException.__init__(self, message) self.type = type def __str__(self): if self.message: return self.message elif self.type == self.UNKNOWN_METHOD: return 'Unknown method' elif self.type == self.INVALID_MESSAGE_TYPE: return 'Invalid message type' elif self.type == self.WRONG_METHOD_NAME: return 'Wrong method name' elif self.type == self.BAD_SEQUENCE_ID: return 'Bad sequence ID' elif self.type == self.MISSING_RESULT: return 'Missing result' elif self.type == self.INTERNAL_ERROR: return 'Internal error' elif self.type == self.PROTOCOL_ERROR: return 'Protocol error' elif self.type == self.INVALID_TRANSFORM: return 'Invalid transform' elif self.type == self.INVALID_PROTOCOL: return 'Invalid protocol' elif self.type == self.UNSUPPORTED_CLIENT_TYPE: return 'Unsupported client type' else: return 'Default (unknown) TApplicationException' def read(self, iprot): iprot.readStructBegin() while True: (fname, ftype, fid) = iprot.readFieldBegin() if ftype == TType.STOP: break if fid == 1: if ftype == TType.STRING: self.message = iprot.readString() else: iprot.skip(ftype) elif fid == 2: if ftype == TType.I32: self.type = iprot.readI32() else: iprot.skip(ftype) else: iprot.skip(ftype) iprot.readFieldEnd() iprot.readStructEnd() def write(self, oprot): oprot.writeStructBegin('TApplicationException') if self.message is not None: oprot.writeFieldBegin('message', TType.STRING, 1) oprot.writeString(self.message) oprot.writeFieldEnd() if self.type is not None: oprot.writeFieldBegin('type', TType.I32, 2) oprot.writeI32(self.type) oprot.writeFieldEnd() oprot.writeFieldStop() oprot.writeStructEnd() class TFrozenDict(dict): """A dictionary that is "frozen" like a frozenset""" def __init__(self, *args, **kwargs): super(TFrozenDict, self).__init__(*args, **kwargs) # Sort the items so they will be in a consistent order. # XOR in the hash of the class so we don't collide with # the hash of a list of tuples. self.__hashval = hash(TFrozenDict) ^ hash(tuple(sorted(self.items()))) def __setitem__(self, *args): raise TypeError("Can't modify frozen TFreezableDict") def __delitem__(self, *args): raise TypeError("Can't modify frozen TFreezableDict") def __hash__(self): return self.__hashval thrift-0.16.0/lib/py/src/__init__.py000066400000000000000000000014611420101504100171620ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # __all__ = ['Thrift', 'TSCons'] thrift-0.16.0/lib/py/src/compat.py000066400000000000000000000024431420101504100167070ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import sys if sys.version_info[0] == 2: from cStringIO import StringIO as BufferIO def binary_to_str(bin_val): return bin_val def str_to_binary(str_val): return str_val def byte_index(bytes_val, i): return ord(bytes_val[i]) else: from io import BytesIO as BufferIO # noqa def binary_to_str(bin_val): return bin_val.decode('utf8') def str_to_binary(str_val): return bytes(str_val, 'utf8') def byte_index(bytes_val, i): return bytes_val[i] thrift-0.16.0/lib/py/src/ext/000077500000000000000000000000001420101504100156475ustar00rootroot00000000000000thrift-0.16.0/lib/py/src/ext/binary.cpp000066400000000000000000000021661420101504100176440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #define PY_SSIZE_T_CLEAN #include "ext/binary.h" namespace apache { namespace thrift { namespace py { bool BinaryProtocol::readFieldBegin(TType& type, int16_t& tag) { uint8_t b = 0; if (!readByte(b)) { return false; } type = static_cast(b); if (type == T_STOP) { return true; } return readI16(tag); } } } } thrift-0.16.0/lib/py/src/ext/binary.h000066400000000000000000000132331420101504100173060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_PY_BINARY_H #define THRIFT_PY_BINARY_H #include #include "ext/protocol.h" #include "ext/endian.h" #include namespace apache { namespace thrift { namespace py { class BinaryProtocol : public ProtocolBase { public: virtual ~BinaryProtocol() {} void writeI8(int8_t val) { writeBuffer(reinterpret_cast(&val), sizeof(int8_t)); } void writeI16(int16_t val) { int16_t net = static_cast(htons(val)); writeBuffer(reinterpret_cast(&net), sizeof(int16_t)); } void writeI32(int32_t val) { int32_t net = static_cast(htonl(val)); writeBuffer(reinterpret_cast(&net), sizeof(int32_t)); } void writeI64(int64_t val) { int64_t net = static_cast(htonll(val)); writeBuffer(reinterpret_cast(&net), sizeof(int64_t)); } void writeDouble(double dub) { // Unfortunately, bitwise_cast doesn't work in C. Bad C! union { double f; int64_t t; } transfer; transfer.f = dub; writeI64(transfer.t); } void writeBool(int v) { writeByte(static_cast(v)); } void writeString(PyObject* value, int32_t len) { writeI32(len); writeBuffer(PyBytes_AS_STRING(value), len); } bool writeListBegin(PyObject* value, const SetListTypeArgs& parsedargs, int32_t len) { writeByte(parsedargs.element_type); writeI32(len); return true; } bool writeMapBegin(PyObject* value, const MapTypeArgs& parsedargs, int32_t len) { writeByte(parsedargs.ktag); writeByte(parsedargs.vtag); writeI32(len); return true; } bool writeStructBegin() { return true; } bool writeStructEnd() { return true; } bool writeField(PyObject* value, const StructItemSpec& parsedspec) { writeByte(static_cast(parsedspec.type)); writeI16(parsedspec.tag); return encodeValue(value, parsedspec.type, parsedspec.typeargs); } void writeFieldStop() { writeByte(static_cast(T_STOP)); } bool readBool(bool& val) { char* buf; if (!readBytes(&buf, 1)) { return false; } val = buf[0] == 1; return true; } bool readI8(int8_t& val) { char* buf; if (!readBytes(&buf, 1)) { return false; } val = buf[0]; return true; } bool readI16(int16_t& val) { char* buf; if (!readBytes(&buf, sizeof(int16_t))) { return false; } memcpy(&val, buf, sizeof(int16_t)); val = ntohs(val); return true; } bool readI32(int32_t& val) { char* buf; if (!readBytes(&buf, sizeof(int32_t))) { return false; } memcpy(&val, buf, sizeof(int32_t)); val = ntohl(val); return true; } bool readI64(int64_t& val) { char* buf; if (!readBytes(&buf, sizeof(int64_t))) { return false; } memcpy(&val, buf, sizeof(int64_t)); val = ntohll(val); return true; } bool readDouble(double& val) { union { int64_t f; double t; } transfer; if (!readI64(transfer.f)) { return false; } val = transfer.t; return true; } int32_t readString(char** buf) { int32_t len = 0; if (!readI32(len) || !checkLengthLimit(len, stringLimit()) || !readBytes(buf, len)) { return -1; } return len; } int32_t readListBegin(TType& etype) { int32_t len; uint8_t b = 0; if (!readByte(b) || !readI32(len) || !checkLengthLimit(len, containerLimit())) { return -1; } etype = static_cast(b); return len; } int32_t readMapBegin(TType& ktype, TType& vtype) { int32_t len; uint8_t k, v; if (!readByte(k) || !readByte(v) || !readI32(len) || !checkLengthLimit(len, containerLimit())) { return -1; } ktype = static_cast(k); vtype = static_cast(v); return len; } bool readStructBegin() { return true; } bool readStructEnd() { return true; } bool readFieldBegin(TType& type, int16_t& tag); #define SKIPBYTES(n) \ do { \ if (!readBytes(&dummy_buf_, (n))) { \ return false; \ } \ return true; \ } while (0) bool skipBool() { SKIPBYTES(1); } bool skipByte() { SKIPBYTES(1); } bool skipI16() { SKIPBYTES(2); } bool skipI32() { SKIPBYTES(4); } bool skipI64() { SKIPBYTES(8); } bool skipDouble() { SKIPBYTES(8); } bool skipString() { int32_t len; if (!readI32(len)) { return false; } SKIPBYTES(len); } #undef SKIPBYTES private: char* dummy_buf_; }; } } } #endif // THRIFT_PY_BINARY_H thrift-0.16.0/lib/py/src/ext/compact.cpp000066400000000000000000000052561420101504100200110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #define PY_SSIZE_T_CLEAN #include "ext/compact.h" namespace apache { namespace thrift { namespace py { const uint8_t CompactProtocol::TTypeToCType[] = { CT_STOP, // T_STOP 0, // unused CT_BOOLEAN_TRUE, // T_BOOL CT_BYTE, // T_BYTE CT_DOUBLE, // T_DOUBLE 0, // unused CT_I16, // T_I16 0, // unused CT_I32, // T_I32 0, // unused CT_I64, // T_I64 CT_BINARY, // T_STRING CT_STRUCT, // T_STRUCT CT_MAP, // T_MAP CT_SET, // T_SET CT_LIST, // T_LIST }; bool CompactProtocol::readFieldBegin(TType& type, int16_t& tag) { uint8_t b; if (!readByte(b)) { return false; } uint8_t ctype = b & 0xf; type = getTType(ctype); if (type == -1) { return false; } else if (type == T_STOP) { tag = 0; return true; } uint8_t diff = (b & 0xf0) >> 4; if (diff) { tag = readTags_.top() + diff; } else if (!readI16(tag)) { readTags_.top() = -1; return false; } if (ctype == CT_BOOLEAN_FALSE || ctype == CT_BOOLEAN_TRUE) { readBool_.exists = true; readBool_.value = ctype == CT_BOOLEAN_TRUE; } readTags_.top() = tag; return true; } TType CompactProtocol::getTType(uint8_t type) { switch (type) { case T_STOP: return T_STOP; case CT_BOOLEAN_FALSE: case CT_BOOLEAN_TRUE: return T_BOOL; case CT_BYTE: return T_BYTE; case CT_I16: return T_I16; case CT_I32: return T_I32; case CT_I64: return T_I64; case CT_DOUBLE: return T_DOUBLE; case CT_BINARY: return T_STRING; case CT_LIST: return T_LIST; case CT_SET: return T_SET; case CT_MAP: return T_MAP; case CT_STRUCT: return T_STRUCT; default: PyErr_Format(PyExc_TypeError, "don't know what type: %d", type); return static_cast(-1); } } } } } thrift-0.16.0/lib/py/src/ext/compact.h000066400000000000000000000213571420101504100174560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_PY_COMPACT_H #define THRIFT_PY_COMPACT_H #include #include "ext/protocol.h" #include "ext/endian.h" #include #include namespace apache { namespace thrift { namespace py { class CompactProtocol : public ProtocolBase { public: CompactProtocol() { readBool_.exists = false; } virtual ~CompactProtocol() {} void writeI8(int8_t val) { writeBuffer(reinterpret_cast(&val), 1); } void writeI16(int16_t val) { writeVarint(toZigZag(val)); } int writeI32(int32_t val) { return writeVarint(toZigZag(val)); } void writeI64(int64_t val) { writeVarint64(toZigZag64(val)); } void writeDouble(double dub) { union { double f; int64_t t; } transfer; transfer.f = htolell(dub); writeBuffer(reinterpret_cast(&transfer.t), sizeof(int64_t)); } void writeBool(int v) { writeByte(static_cast(v ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE)); } void writeString(PyObject* value, int32_t len) { writeVarint(len); writeBuffer(PyBytes_AS_STRING(value), len); } bool writeListBegin(PyObject* value, const SetListTypeArgs& args, int32_t len) { int ctype = toCompactType(args.element_type); if (len <= 14) { writeByte(static_cast(len << 4 | ctype)); } else { writeByte(0xf0 | ctype); writeVarint(len); } return true; } bool writeMapBegin(PyObject* value, const MapTypeArgs& args, int32_t len) { if (len == 0) { writeByte(0); return true; } int ctype = toCompactType(args.ktag) << 4 | toCompactType(args.vtag); writeVarint(len); writeByte(ctype); return true; } bool writeStructBegin() { writeTags_.push(0); return true; } bool writeStructEnd() { writeTags_.pop(); return true; } bool writeField(PyObject* value, const StructItemSpec& spec) { if (spec.type == T_BOOL) { doWriteFieldBegin(spec, PyObject_IsTrue(value) ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE); return true; } else { doWriteFieldBegin(spec, toCompactType(spec.type)); return encodeValue(value, spec.type, spec.typeargs); } } void writeFieldStop() { writeByte(0); } bool readBool(bool& val) { if (readBool_.exists) { readBool_.exists = false; val = readBool_.value; return true; } char* buf; if (!readBytes(&buf, 1)) { return false; } val = buf[0] == CT_BOOLEAN_TRUE; return true; } bool readI8(int8_t& val) { char* buf; if (!readBytes(&buf, 1)) { return false; } val = buf[0]; return true; } bool readI16(int16_t& val) { uint16_t uval; if (readVarint(uval)) { val = fromZigZag(uval); return true; } return false; } bool readI32(int32_t& val) { uint32_t uval; if (readVarint(uval)) { val = fromZigZag(uval); return true; } return false; } bool readI64(int64_t& val) { uint64_t uval; if (readVarint(uval)) { val = fromZigZag(uval); return true; } return false; } bool readDouble(double& val) { union { int64_t f; double t; } transfer; char* buf; if (!readBytes(&buf, 8)) { return false; } memcpy(&transfer.f, buf, sizeof(int64_t)); transfer.f = letohll(transfer.f); val = transfer.t; return true; } int32_t readString(char** buf) { uint32_t len; if (!readVarint(len) || !checkLengthLimit(len, stringLimit())) { return -1; } if (len == 0) { return 0; } if (!readBytes(buf, len)) { return -1; } return len; } int32_t readListBegin(TType& etype) { uint8_t b; if (!readByte(b)) { return -1; } etype = getTType(b & 0xf); if (etype == -1) { return -1; } uint32_t len = (b >> 4) & 0xf; if (len == 15 && !readVarint(len)) { return -1; } if (!checkLengthLimit(len, containerLimit())) { return -1; } return len; } int32_t readMapBegin(TType& ktype, TType& vtype) { uint32_t len; if (!readVarint(len) || !checkLengthLimit(len, containerLimit())) { return -1; } if (len != 0) { uint8_t kvType; if (!readByte(kvType)) { return -1; } ktype = getTType(kvType >> 4); vtype = getTType(kvType & 0xf); if (ktype == -1 || vtype == -1) { return -1; } } return len; } bool readStructBegin() { readTags_.push(0); return true; } bool readStructEnd() { readTags_.pop(); return true; } bool readFieldBegin(TType& type, int16_t& tag); bool skipBool() { bool val; return readBool(val); } #define SKIPBYTES(n) \ do { \ if (!readBytes(&dummy_buf_, (n))) { \ return false; \ } \ return true; \ } while (0) bool skipByte() { SKIPBYTES(1); } bool skipDouble() { SKIPBYTES(8); } bool skipI16() { int16_t val; return readI16(val); } bool skipI32() { int32_t val; return readI32(val); } bool skipI64() { int64_t val; return readI64(val); } bool skipString() { uint32_t len; if (!readVarint(len)) { return false; } SKIPBYTES(len); } #undef SKIPBYTES private: enum Types { CT_STOP = 0x00, CT_BOOLEAN_TRUE = 0x01, CT_BOOLEAN_FALSE = 0x02, CT_BYTE = 0x03, CT_I16 = 0x04, CT_I32 = 0x05, CT_I64 = 0x06, CT_DOUBLE = 0x07, CT_BINARY = 0x08, CT_LIST = 0x09, CT_SET = 0x0A, CT_MAP = 0x0B, CT_STRUCT = 0x0C }; static const uint8_t TTypeToCType[]; TType getTType(uint8_t type); int toCompactType(TType type) { int i = static_cast(type); return i < 16 ? TTypeToCType[i] : -1; } uint32_t toZigZag(int32_t val) { return (val >> 31) ^ (val << 1); } uint64_t toZigZag64(int64_t val) { return (val >> 63) ^ (val << 1); } int writeVarint(uint32_t val) { int cnt = 1; while (val & ~0x7fU) { writeByte(static_cast((val & 0x7fU) | 0x80U)); val >>= 7; ++cnt; } writeByte(static_cast(val)); return cnt; } int writeVarint64(uint64_t val) { int cnt = 1; while (val & ~0x7fULL) { writeByte(static_cast((val & 0x7fULL) | 0x80ULL)); val >>= 7; ++cnt; } writeByte(static_cast(val)); return cnt; } template bool readVarint(T& result) { uint8_t b; T val = 0; int shift = 0; for (int i = 0; i < Max; ++i) { if (!readByte(b)) { return false; } if (b & 0x80) { val |= static_cast(b & 0x7f) << shift; } else { val |= static_cast(b) << shift; result = val; return true; } shift += 7; } PyErr_Format(PyExc_OverflowError, "varint exceeded %d bytes", Max); return false; } template S fromZigZag(U val) { return (val >> 1) ^ static_cast(-static_cast(val & 1)); } void doWriteFieldBegin(const StructItemSpec& spec, int ctype) { int diff = spec.tag - writeTags_.top(); if (diff > 0 && diff <= 15) { writeByte(static_cast(diff << 4 | ctype)); } else { writeByte(static_cast(ctype)); writeI16(spec.tag); } writeTags_.top() = spec.tag; } std::stack writeTags_; std::stack readTags_; struct { bool exists; bool value; } readBool_; char* dummy_buf_; }; } } } #endif // THRIFT_PY_COMPACT_H thrift-0.16.0/lib/py/src/ext/endian.h000066400000000000000000000053631420101504100172650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_PY_ENDIAN_H #define THRIFT_PY_ENDIAN_H #include #ifndef _WIN32 #include #else #include #pragma comment(lib, "ws2_32.lib") #define BIG_ENDIAN (4321) #define LITTLE_ENDIAN (1234) #define BYTE_ORDER LITTLE_ENDIAN #define inline __inline #endif /* Fix endianness issues on Solaris */ #if defined(__SVR4) && defined(__sun) #if defined(__i386) && !defined(__i386__) #define __i386__ #endif #ifndef BIG_ENDIAN #define BIG_ENDIAN (4321) #endif #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN (1234) #endif /* I386 is LE, even on Solaris */ #if !defined(BYTE_ORDER) && defined(__i386__) #define BYTE_ORDER LITTLE_ENDIAN #endif #endif #ifndef __BYTE_ORDER #if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) #define __BYTE_ORDER BYTE_ORDER #define __LITTLE_ENDIAN LITTLE_ENDIAN #define __BIG_ENDIAN BIG_ENDIAN #else #error "Cannot determine endianness" #endif #endif // Same comment as the enum. Sorry. #if __BYTE_ORDER == __BIG_ENDIAN #define ntohll(n) (n) #define htonll(n) (n) #if defined(__GNUC__) && defined(__GLIBC__) #include #define letohll(n) bswap_64(n) #define htolell(n) bswap_64(n) #else /* GNUC & GLIBC */ #define letohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32)) #define htolell(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32)) #endif #elif __BYTE_ORDER == __LITTLE_ENDIAN #if defined(__GNUC__) && defined(__GLIBC__) #include #define ntohll(n) bswap_64(n) #define htonll(n) bswap_64(n) #elif defined(_MSC_VER) #include #define ntohll(n) _byteswap_uint64(n) #define htonll(n) _byteswap_uint64(n) #else /* GNUC & GLIBC */ #define ntohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32)) #define htonll(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32)) #endif /* GNUC & GLIBC */ #define letohll(n) (n) #define htolell(n) (n) #else /* __BYTE_ORDER */ #error "Can't define htonll or ntohll!" #endif #endif // THRIFT_PY_ENDIAN_H thrift-0.16.0/lib/py/src/ext/module.cpp000066400000000000000000000142451420101504100176460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include "types.h" #include "binary.h" #include "compact.h" #include #include // TODO(dreiss): defval appears to be unused. Look into removing it. // TODO(dreiss): Make parse_spec_args recursive, and cache the output // permanently in the object. (Malloc and orphan.) // TODO(dreiss): Why do we need cStringIO for reading, why not just char*? // Can cStringIO let us work with a BufferedTransport? // TODO(dreiss): Don't ignore the rv from cwrite (maybe). // Doing a benchmark shows that interning actually makes a difference, amazingly. /** Pointer to interned string to speed up attribute lookup. */ PyObject* INTERN_STRING(TFrozenDict); PyObject* INTERN_STRING(cstringio_buf); PyObject* INTERN_STRING(cstringio_refill); static PyObject* INTERN_STRING(string_length_limit); static PyObject* INTERN_STRING(container_length_limit); static PyObject* INTERN_STRING(trans); namespace apache { namespace thrift { namespace py { template static PyObject* encode_impl(PyObject* args) { if (!args) return nullptr; PyObject* enc_obj = nullptr; PyObject* type_args = nullptr; if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) { return nullptr; } if (!enc_obj || !type_args) { return nullptr; } T protocol; if (!protocol.prepareEncodeBuffer() || !protocol.encodeValue(enc_obj, T_STRUCT, type_args)) { return nullptr; } return protocol.getEncodedValue(); } static inline long as_long_then_delete(PyObject* value, long default_value) { ScopedPyObject scope(value); long v = PyInt_AsLong(value); if (INT_CONV_ERROR_OCCURRED(v)) { PyErr_Clear(); return default_value; } return v; } template static PyObject* decode_impl(PyObject* args) { PyObject* output_obj = nullptr; PyObject* oprot = nullptr; PyObject* typeargs = nullptr; if (!PyArg_ParseTuple(args, "OOO", &output_obj, &oprot, &typeargs)) { return nullptr; } T protocol; int32_t default_limit = (std::numeric_limits::max)(); protocol.setStringLengthLimit( as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(string_length_limit)), default_limit)); protocol.setContainerLengthLimit( as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(container_length_limit)), default_limit)); ScopedPyObject transport(PyObject_GetAttr(oprot, INTERN_STRING(trans))); if (!transport) { return nullptr; } StructTypeArgs parsedargs; if (!parse_struct_args(&parsedargs, typeargs)) { return nullptr; } if (!protocol.prepareDecodeBufferFromTransport(transport.get())) { return nullptr; } return protocol.readStruct(output_obj, parsedargs.klass, parsedargs.spec); } } } } using namespace apache::thrift::py; /* -- PYTHON MODULE SETUP STUFF --- */ extern "C" { static PyObject* encode_binary(PyObject*, PyObject* args) { return encode_impl(args); } static PyObject* decode_binary(PyObject*, PyObject* args) { return decode_impl(args); } static PyObject* encode_compact(PyObject*, PyObject* args) { return encode_impl(args); } static PyObject* decode_compact(PyObject*, PyObject* args) { return decode_impl(args); } static PyMethodDef ThriftFastBinaryMethods[] = { {"encode_binary", encode_binary, METH_VARARGS, ""}, {"decode_binary", decode_binary, METH_VARARGS, ""}, {"encode_compact", encode_compact, METH_VARARGS, ""}, {"decode_compact", decode_compact, METH_VARARGS, ""}, {nullptr, nullptr, 0, nullptr} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef ThriftFastBinaryDef = {PyModuleDef_HEAD_INIT, "thrift.protocol.fastbinary", nullptr, 0, ThriftFastBinaryMethods, nullptr, nullptr, nullptr, nullptr}; #define INITERROR return nullptr; PyObject* PyInit_fastbinary() { #else #define INITERROR return; void initfastbinary() { PycString_IMPORT; if (PycStringIO == nullptr) INITERROR #endif #define INIT_INTERN_STRING(value) \ do { \ INTERN_STRING(value) = PyString_InternFromString(#value); \ if (!INTERN_STRING(value)) \ INITERROR \ } while (0) INIT_INTERN_STRING(TFrozenDict); INIT_INTERN_STRING(cstringio_buf); INIT_INTERN_STRING(cstringio_refill); INIT_INTERN_STRING(string_length_limit); INIT_INTERN_STRING(container_length_limit); INIT_INTERN_STRING(trans); #undef INIT_INTERN_STRING PyObject* module = #if PY_MAJOR_VERSION >= 3 PyModule_Create(&ThriftFastBinaryDef); #else Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods); #endif if (module == nullptr) INITERROR; #if PY_MAJOR_VERSION >= 3 return module; #endif } } thrift-0.16.0/lib/py/src/ext/protocol.h000066400000000000000000000050051420101504100176610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_PY_PROTOCOL_H #define THRIFT_PY_PROTOCOL_H #include "ext/types.h" #include #include namespace apache { namespace thrift { namespace py { template class ProtocolBase { public: ProtocolBase() : stringLimit_((std::numeric_limits::max)()), containerLimit_((std::numeric_limits::max)()), output_(nullptr) {} inline virtual ~ProtocolBase(); bool prepareDecodeBufferFromTransport(PyObject* trans); PyObject* readStruct(PyObject* output, PyObject* klass, PyObject* spec_seq); bool prepareEncodeBuffer(); bool encodeValue(PyObject* value, TType type, PyObject* typeargs); PyObject* getEncodedValue(); long stringLimit() const { return stringLimit_; } void setStringLengthLimit(long limit) { stringLimit_ = limit; } long containerLimit() const { return containerLimit_; } void setContainerLengthLimit(long limit) { containerLimit_ = limit; } protected: bool readBytes(char** output, int len); bool readByte(uint8_t& val) { char* buf; if (!readBytes(&buf, 1)) { return false; } val = static_cast(buf[0]); return true; } bool writeBuffer(char* data, size_t len); void writeByte(uint8_t val) { writeBuffer(reinterpret_cast(&val), 1); } PyObject* decodeValue(TType type, PyObject* typeargs); bool skip(TType type); inline bool checkType(TType got, TType expected); inline bool checkLengthLimit(int32_t len, long limit); inline bool isUtf8(PyObject* typeargs); private: Impl* impl() { return static_cast(this); } long stringLimit_; long containerLimit_; EncodeBuffer* output_; DecodeBuffer input_; }; } } } #include "ext/protocol.tcc" #endif // THRIFT_PY_PROTOCOL_H thrift-0.16.0/lib/py/src/ext/protocol.tcc000066400000000000000000000557331420101504100202200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_PY_PROTOCOL_TCC #define THRIFT_PY_PROTOCOL_TCC #include #define CHECK_RANGE(v, min, max) (((v) <= (max)) && ((v) >= (min))) #define INIT_OUTBUF_SIZE 128 #if PY_MAJOR_VERSION < 3 #include #else #include #endif namespace apache { namespace thrift { namespace py { #if PY_MAJOR_VERSION < 3 namespace detail { inline bool input_check(PyObject* input) { return PycStringIO_InputCheck(input); } inline EncodeBuffer* new_encode_buffer(size_t size) { if (!PycStringIO) { PycString_IMPORT; } if (!PycStringIO) { return nullptr; } return PycStringIO->NewOutput(size); } inline int read_buffer(PyObject* buf, char** output, int len) { if (!PycStringIO) { PycString_IMPORT; } if (!PycStringIO) { PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO"); return -1; } return PycStringIO->cread(buf, output, len); } } template inline ProtocolBase::~ProtocolBase() { if (output_) { Py_CLEAR(output_); } } template inline bool ProtocolBase::isUtf8(PyObject* typeargs) { return PyString_Check(typeargs) && !strncmp(PyString_AS_STRING(typeargs), "UTF8", 4); } template PyObject* ProtocolBase::getEncodedValue() { if (!PycStringIO) { PycString_IMPORT; } if (!PycStringIO) { return nullptr; } return PycStringIO->cgetvalue(output_); } template inline bool ProtocolBase::writeBuffer(char* data, size_t size) { if (!PycStringIO) { PycString_IMPORT; } if (!PycStringIO) { PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO"); return false; } int len = PycStringIO->cwrite(output_, data, size); if (len < 0) { PyErr_SetString(PyExc_IOError, "failed to write to cStringIO object"); return false; } if (static_cast(len) != size) { PyErr_Format(PyExc_EOFError, "write length mismatch: expected %lu got %d", size, len); return false; } return true; } #else namespace detail { inline bool input_check(PyObject* input) { // TODO: Check for BytesIO type return true; } inline EncodeBuffer* new_encode_buffer(size_t size) { EncodeBuffer* buffer = new EncodeBuffer; buffer->buf.reserve(size); buffer->pos = 0; return buffer; } struct bytesio { PyObject_HEAD #if PY_MINOR_VERSION < 5 char* buf; #else PyObject* buf; #endif Py_ssize_t pos; Py_ssize_t string_size; }; inline int read_buffer(PyObject* buf, char** output, int len) { bytesio* buf2 = reinterpret_cast(buf); #if PY_MINOR_VERSION < 5 *output = buf2->buf + buf2->pos; #else *output = PyBytes_AS_STRING(buf2->buf) + buf2->pos; #endif Py_ssize_t pos0 = buf2->pos; buf2->pos = (std::min)(buf2->pos + static_cast(len), buf2->string_size); return static_cast(buf2->pos - pos0); } } template inline ProtocolBase::~ProtocolBase() { if (output_) { delete output_; } } template inline bool ProtocolBase::isUtf8(PyObject* typeargs) { // while condition for py2 is "arg == 'UTF8'", it should be "arg != 'BINARY'" for py3. // HACK: check the length and don't bother reading the value return !PyUnicode_Check(typeargs) || PyUnicode_GET_LENGTH(typeargs) != 6; } template PyObject* ProtocolBase::getEncodedValue() { return PyBytes_FromStringAndSize(output_->buf.data(), output_->buf.size()); } template inline bool ProtocolBase::writeBuffer(char* data, size_t size) { size_t need = size + output_->pos; if (output_->buf.capacity() < need) { try { output_->buf.reserve(need); } catch (std::bad_alloc&) { PyErr_SetString(PyExc_MemoryError, "Failed to allocate write buffer"); return false; } } std::copy(data, data + size, std::back_inserter(output_->buf)); return true; } #endif namespace detail { #define DECLARE_OP_SCOPE(name, op) \ template \ struct name##Scope { \ Impl* impl; \ bool valid; \ name##Scope(Impl* thiz) : impl(thiz), valid(impl->op##Begin()) {} \ ~name##Scope() { \ if (valid) \ impl->op##End(); \ } \ operator bool() { return valid; } \ }; \ template class T> \ name##Scope op##Scope(T* thiz) { \ return name##Scope(static_cast(thiz)); \ } DECLARE_OP_SCOPE(WriteStruct, writeStruct) DECLARE_OP_SCOPE(ReadStruct, readStruct) #undef DECLARE_OP_SCOPE inline bool check_ssize_t_32(Py_ssize_t len) { // error from getting the int if (INT_CONV_ERROR_OCCURRED(len)) { return false; } if (!CHECK_RANGE(len, 0, (std::numeric_limits::max)())) { PyErr_SetString(PyExc_OverflowError, "size out of range: exceeded INT32_MAX"); return false; } return true; } } template bool parse_pyint(PyObject* o, T* ret, int32_t min, int32_t max) { long val = PyInt_AsLong(o); if (INT_CONV_ERROR_OCCURRED(val)) { return false; } if (!CHECK_RANGE(val, min, max)) { PyErr_SetString(PyExc_OverflowError, "int out of range"); return false; } *ret = static_cast(val); return true; } template inline bool ProtocolBase::checkType(TType got, TType expected) { if (expected != got) { PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field"); return false; } return true; } template bool ProtocolBase::checkLengthLimit(int32_t len, long limit) { if (len < 0) { PyErr_Format(PyExc_OverflowError, "negative length: %ld", limit); return false; } if (len > limit) { PyErr_Format(PyExc_OverflowError, "size exceeded specified limit: %ld", limit); return false; } return true; } template bool ProtocolBase::readBytes(char** output, int len) { if (len < 0) { PyErr_Format(PyExc_ValueError, "attempted to read negative length: %d", len); return false; } // TODO(dreiss): Don't fear the malloc. Think about taking a copy of // the partial read instead of forcing the transport // to prepend it to its buffer. int rlen = detail::read_buffer(input_.stringiobuf.get(), output, len); if (rlen == len) { return true; } else if (rlen == -1) { return false; } else { // using building functions as this is a rare codepath ScopedPyObject newiobuf(PyObject_CallFunction(input_.refill_callable.get(), refill_signature, *output, rlen, len, nullptr)); if (!newiobuf) { return false; } // must do this *AFTER* the call so that we don't deref the io buffer input_.stringiobuf.reset(newiobuf.release()); rlen = detail::read_buffer(input_.stringiobuf.get(), output, len); if (rlen == len) { return true; } else if (rlen == -1) { return false; } else { // TODO(dreiss): This could be a valid code path for big binary blobs. PyErr_SetString(PyExc_TypeError, "refill claimed to have refilled the buffer, but didn't!!"); return false; } } } template bool ProtocolBase::prepareDecodeBufferFromTransport(PyObject* trans) { if (input_.stringiobuf) { PyErr_SetString(PyExc_ValueError, "decode buffer is already initialized"); return false; } ScopedPyObject stringiobuf(PyObject_GetAttr(trans, INTERN_STRING(cstringio_buf))); if (!stringiobuf) { return false; } if (!detail::input_check(stringiobuf.get())) { PyErr_SetString(PyExc_TypeError, "expecting stringio input_"); return false; } ScopedPyObject refill_callable(PyObject_GetAttr(trans, INTERN_STRING(cstringio_refill))); if (!refill_callable) { return false; } if (!PyCallable_Check(refill_callable.get())) { PyErr_SetString(PyExc_TypeError, "expecting callable"); return false; } input_.stringiobuf.swap(stringiobuf); input_.refill_callable.swap(refill_callable); return true; } template bool ProtocolBase::prepareEncodeBuffer() { output_ = detail::new_encode_buffer(INIT_OUTBUF_SIZE); return output_ != nullptr; } template bool ProtocolBase::encodeValue(PyObject* value, TType type, PyObject* typeargs) { /* * Refcounting Strategy: * * We assume that elements of the thrift_spec tuple are not going to be * mutated, so we don't ref count those at all. Other than that, we try to * keep a reference to all the user-created objects while we work with them. * encodeValue assumes that a reference is already held. The *caller* is * responsible for handling references */ switch (type) { case T_BOOL: { int v = PyObject_IsTrue(value); if (v == -1) { return false; } impl()->writeBool(v); return true; } case T_I08: { int8_t val; if (!parse_pyint(value, &val, (std::numeric_limits::min)(), (std::numeric_limits::max)())) { return false; } impl()->writeI8(val); return true; } case T_I16: { int16_t val; if (!parse_pyint(value, &val, (std::numeric_limits::min)(), (std::numeric_limits::max)())) { return false; } impl()->writeI16(val); return true; } case T_I32: { int32_t val; if (!parse_pyint(value, &val, (std::numeric_limits::min)(), (std::numeric_limits::max)())) { return false; } impl()->writeI32(val); return true; } case T_I64: { int64_t nval = PyLong_AsLongLong(value); if (INT_CONV_ERROR_OCCURRED(nval)) { return false; } if (!CHECK_RANGE(nval, (std::numeric_limits::min)(), (std::numeric_limits::max)())) { PyErr_SetString(PyExc_OverflowError, "int out of range"); return false; } impl()->writeI64(nval); return true; } case T_DOUBLE: { double nval = PyFloat_AsDouble(value); if (nval == -1.0 && PyErr_Occurred()) { return false; } impl()->writeDouble(nval); return true; } case T_STRING: { ScopedPyObject nval; if (PyUnicode_Check(value)) { nval.reset(PyUnicode_AsUTF8String(value)); if (!nval) { return false; } } else { Py_INCREF(value); nval.reset(value); } Py_ssize_t len = PyBytes_Size(nval.get()); if (!detail::check_ssize_t_32(len)) { return false; } impl()->writeString(nval.get(), static_cast(len)); return true; } case T_LIST: case T_SET: { SetListTypeArgs parsedargs; if (!parse_set_list_args(&parsedargs, typeargs)) { return false; } Py_ssize_t len = PyObject_Length(value); if (!detail::check_ssize_t_32(len)) { return false; } if (!impl()->writeListBegin(value, parsedargs, static_cast(len)) || PyErr_Occurred()) { return false; } ScopedPyObject iterator(PyObject_GetIter(value)); if (!iterator) { return false; } while (PyObject* rawItem = PyIter_Next(iterator.get())) { ScopedPyObject item(rawItem); if (!encodeValue(item.get(), parsedargs.element_type, parsedargs.typeargs)) { return false; } } return true; } case T_MAP: { Py_ssize_t len = PyDict_Size(value); if (!detail::check_ssize_t_32(len)) { return false; } MapTypeArgs parsedargs; if (!parse_map_args(&parsedargs, typeargs)) { return false; } if (!impl()->writeMapBegin(value, parsedargs, static_cast(len)) || PyErr_Occurred()) { return false; } Py_ssize_t pos = 0; PyObject* k = nullptr; PyObject* v = nullptr; // TODO(bmaurer): should support any mapping, not just dicts while (PyDict_Next(value, &pos, &k, &v)) { if (!encodeValue(k, parsedargs.ktag, parsedargs.ktypeargs) || !encodeValue(v, parsedargs.vtag, parsedargs.vtypeargs)) { return false; } } return true; } case T_STRUCT: { StructTypeArgs parsedargs; if (!parse_struct_args(&parsedargs, typeargs)) { return false; } Py_ssize_t nspec = PyTuple_Size(parsedargs.spec); if (nspec == -1) { PyErr_SetString(PyExc_TypeError, "spec is not a tuple"); return false; } detail::WriteStructScope scope = detail::writeStructScope(this); if (!scope) { return false; } for (Py_ssize_t i = 0; i < nspec; i++) { PyObject* spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i); if (spec_tuple == Py_None) { continue; } StructItemSpec parsedspec; if (!parse_struct_item_spec(&parsedspec, spec_tuple)) { return false; } ScopedPyObject instval(PyObject_GetAttr(value, parsedspec.attrname)); if (!instval) { return false; } if (instval.get() == Py_None) { continue; } bool res = impl()->writeField(instval.get(), parsedspec); if (!res) { return false; } } impl()->writeFieldStop(); return true; } case T_STOP: case T_VOID: case T_UTF16: case T_UTF8: case T_U64: default: PyErr_Format(PyExc_TypeError, "Unexpected TType for encodeValue: %d", type); return false; } return true; } template bool ProtocolBase::skip(TType type) { switch (type) { case T_BOOL: return impl()->skipBool(); case T_I08: return impl()->skipByte(); case T_I16: return impl()->skipI16(); case T_I32: return impl()->skipI32(); case T_I64: return impl()->skipI64(); case T_DOUBLE: return impl()->skipDouble(); case T_STRING: { return impl()->skipString(); } case T_LIST: case T_SET: { TType etype = T_STOP; int32_t len = impl()->readListBegin(etype); if (len < 0) { return false; } for (int32_t i = 0; i < len; i++) { if (!skip(etype)) { return false; } } return true; } case T_MAP: { TType ktype = T_STOP; TType vtype = T_STOP; int32_t len = impl()->readMapBegin(ktype, vtype); if (len < 0) { return false; } for (int32_t i = 0; i < len; i++) { if (!skip(ktype) || !skip(vtype)) { return false; } } return true; } case T_STRUCT: { detail::ReadStructScope scope = detail::readStructScope(this); if (!scope) { return false; } while (true) { TType type = T_STOP; int16_t tag; if (!impl()->readFieldBegin(type, tag)) { return false; } if (type == T_STOP) { return true; } if (!skip(type)) { return false; } } return true; } case T_STOP: case T_VOID: case T_UTF16: case T_UTF8: case T_U64: default: PyErr_Format(PyExc_TypeError, "Unexpected TType for skip: %d", type); return false; } return true; } // Returns a new reference. template PyObject* ProtocolBase::decodeValue(TType type, PyObject* typeargs) { switch (type) { case T_BOOL: { bool v = 0; if (!impl()->readBool(v)) { return nullptr; } if (v) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } case T_I08: { int8_t v = 0; if (!impl()->readI8(v)) { return nullptr; } return PyInt_FromLong(v); } case T_I16: { int16_t v = 0; if (!impl()->readI16(v)) { return nullptr; } return PyInt_FromLong(v); } case T_I32: { int32_t v = 0; if (!impl()->readI32(v)) { return nullptr; } return PyInt_FromLong(v); } case T_I64: { int64_t v = 0; if (!impl()->readI64(v)) { return nullptr; } // TODO(dreiss): Find out if we can take this fastpath always when // sizeof(long) == sizeof(long long). if (CHECK_RANGE(v, LONG_MIN, LONG_MAX)) { return PyInt_FromLong((long)v); } return PyLong_FromLongLong(v); } case T_DOUBLE: { double v = 0.0; if (!impl()->readDouble(v)) { return nullptr; } return PyFloat_FromDouble(v); } case T_STRING: { char* buf = nullptr; int len = impl()->readString(&buf); if (len < 0) { return nullptr; } if (isUtf8(typeargs)) { return PyUnicode_DecodeUTF8(buf, len, "replace"); } else { return PyBytes_FromStringAndSize(buf, len); } } case T_LIST: case T_SET: { SetListTypeArgs parsedargs; if (!parse_set_list_args(&parsedargs, typeargs)) { return nullptr; } TType etype = T_STOP; int32_t len = impl()->readListBegin(etype); if (len < 0) { return nullptr; } if (len > 0 && !checkType(etype, parsedargs.element_type)) { return nullptr; } bool use_tuple = type == T_LIST && parsedargs.immutable; ScopedPyObject ret(use_tuple ? PyTuple_New(len) : PyList_New(len)); if (!ret) { return nullptr; } for (int i = 0; i < len; i++) { PyObject* item = decodeValue(etype, parsedargs.typeargs); if (!item) { return nullptr; } if (use_tuple) { PyTuple_SET_ITEM(ret.get(), i, item); } else { PyList_SET_ITEM(ret.get(), i, item); } } // TODO(dreiss): Consider biting the bullet and making two separate cases // for list and set, avoiding this post facto conversion. if (type == T_SET) { PyObject* setret; setret = parsedargs.immutable ? PyFrozenSet_New(ret.get()) : PySet_New(ret.get()); return setret; } return ret.release(); } case T_MAP: { MapTypeArgs parsedargs; if (!parse_map_args(&parsedargs, typeargs)) { return nullptr; } TType ktype = T_STOP; TType vtype = T_STOP; uint32_t len = impl()->readMapBegin(ktype, vtype); if (len > 0 && (!checkType(ktype, parsedargs.ktag) || !checkType(vtype, parsedargs.vtag))) { return nullptr; } ScopedPyObject ret(PyDict_New()); if (!ret) { return nullptr; } for (uint32_t i = 0; i < len; i++) { ScopedPyObject k(decodeValue(ktype, parsedargs.ktypeargs)); if (!k) { return nullptr; } ScopedPyObject v(decodeValue(vtype, parsedargs.vtypeargs)); if (!v) { return nullptr; } if (PyDict_SetItem(ret.get(), k.get(), v.get()) == -1) { return nullptr; } } if (parsedargs.immutable) { if (!ThriftModule) { ThriftModule = PyImport_ImportModule("thrift.Thrift"); } if (!ThriftModule) { return nullptr; } ScopedPyObject cls(PyObject_GetAttr(ThriftModule, INTERN_STRING(TFrozenDict))); if (!cls) { return nullptr; } ScopedPyObject arg(PyTuple_New(1)); PyTuple_SET_ITEM(arg.get(), 0, ret.release()); ret.reset(PyObject_CallObject(cls.get(), arg.get())); } return ret.release(); } case T_STRUCT: { StructTypeArgs parsedargs; if (!parse_struct_args(&parsedargs, typeargs)) { return nullptr; } return readStruct(Py_None, parsedargs.klass, parsedargs.spec); } case T_STOP: case T_VOID: case T_UTF16: case T_UTF8: case T_U64: default: PyErr_Format(PyExc_TypeError, "Unexpected TType for decodeValue: %d", type); return nullptr; } } template PyObject* ProtocolBase::readStruct(PyObject* output, PyObject* klass, PyObject* spec_seq) { int spec_seq_len = PyTuple_Size(spec_seq); bool immutable = output == Py_None; ScopedPyObject kwargs; if (spec_seq_len == -1) { return nullptr; } if (immutable) { kwargs.reset(PyDict_New()); if (!kwargs) { PyErr_SetString(PyExc_TypeError, "failed to prepare kwargument storage"); return nullptr; } } detail::ReadStructScope scope = detail::readStructScope(this); if (!scope) { return nullptr; } while (true) { TType type = T_STOP; int16_t tag; if (!impl()->readFieldBegin(type, tag)) { return nullptr; } if (type == T_STOP) { break; } if (tag < 0 || tag >= spec_seq_len) { if (!skip(type)) { PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field"); return nullptr; } continue; } PyObject* item_spec = PyTuple_GET_ITEM(spec_seq, tag); if (item_spec == Py_None) { if (!skip(type)) { PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field"); return nullptr; } continue; } StructItemSpec parsedspec; if (!parse_struct_item_spec(&parsedspec, item_spec)) { return nullptr; } if (parsedspec.type != type) { if (!skip(type)) { PyErr_Format(PyExc_TypeError, "struct field had wrong type: expected %d but got %d", parsedspec.type, type); return nullptr; } continue; } ScopedPyObject fieldval(decodeValue(parsedspec.type, parsedspec.typeargs)); if (!fieldval) { return nullptr; } if ((immutable && PyDict_SetItem(kwargs.get(), parsedspec.attrname, fieldval.get()) == -1) || (!immutable && PyObject_SetAttr(output, parsedspec.attrname, fieldval.get()) == -1)) { return nullptr; } } if (immutable) { ScopedPyObject args(PyTuple_New(0)); if (!args) { PyErr_SetString(PyExc_TypeError, "failed to prepare argument storage"); return nullptr; } return PyObject_Call(klass, args.get(), kwargs.get()); } Py_INCREF(output); return output; } } } } #endif // THRIFT_PY_PROTOCOL_H thrift-0.16.0/lib/py/src/ext/types.cpp000066400000000000000000000065211420101504100175230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "ext/types.h" #include "ext/protocol.h" namespace apache { namespace thrift { namespace py { PyObject* ThriftModule = nullptr; #if PY_MAJOR_VERSION < 3 char refill_signature[] = {'s', '#', 'i'}; #else const char* refill_signature = "y#i"; #endif bool parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple) { // i'd like to use ParseArgs here, but it seems to be a bottleneck. if (PyTuple_Size(spec_tuple) != 5) { PyErr_Format(PyExc_TypeError, "expecting 5 arguments for spec tuple but got %d", static_cast(PyTuple_Size(spec_tuple))); return false; } dest->tag = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 0))); if (INT_CONV_ERROR_OCCURRED(dest->tag)) { return false; } dest->type = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 1))); if (INT_CONV_ERROR_OCCURRED(dest->type)) { return false; } dest->attrname = PyTuple_GET_ITEM(spec_tuple, 2); dest->typeargs = PyTuple_GET_ITEM(spec_tuple, 3); dest->defval = PyTuple_GET_ITEM(spec_tuple, 4); return true; } bool parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs) { if (PyTuple_Size(typeargs) != 3) { PyErr_SetString(PyExc_TypeError, "expecting tuple of size 3 for list/set type args"); return false; } dest->element_type = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0))); if (INT_CONV_ERROR_OCCURRED(dest->element_type)) { return false; } dest->typeargs = PyTuple_GET_ITEM(typeargs, 1); dest->immutable = Py_True == PyTuple_GET_ITEM(typeargs, 2); return true; } bool parse_map_args(MapTypeArgs* dest, PyObject* typeargs) { if (PyTuple_Size(typeargs) != 5) { PyErr_SetString(PyExc_TypeError, "expecting 5 arguments for typeargs to map"); return false; } dest->ktag = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0))); if (INT_CONV_ERROR_OCCURRED(dest->ktag)) { return false; } dest->vtag = static_cast(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 2))); if (INT_CONV_ERROR_OCCURRED(dest->vtag)) { return false; } dest->ktypeargs = PyTuple_GET_ITEM(typeargs, 1); dest->vtypeargs = PyTuple_GET_ITEM(typeargs, 3); dest->immutable = Py_True == PyTuple_GET_ITEM(typeargs, 4); return true; } bool parse_struct_args(StructTypeArgs* dest, PyObject* typeargs) { if (PyList_Size(typeargs) != 2) { PyErr_SetString(PyExc_TypeError, "expecting list of size 2 for struct args"); return false; } dest->klass = PyList_GET_ITEM(typeargs, 0); dest->spec = PyList_GET_ITEM(typeargs, 1); return true; } } } } thrift-0.16.0/lib/py/src/ext/types.h000066400000000000000000000103771420101504100171740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef THRIFT_PY_TYPES_H #define THRIFT_PY_TYPES_H #include #ifdef _MSC_VER #define __STDC_FORMAT_MACROS #define __STDC_LIMIT_MACROS #endif #include #if PY_MAJOR_VERSION >= 3 #include // TODO: better macros #define PyInt_AsLong(v) PyLong_AsLong(v) #define PyInt_FromLong(v) PyLong_FromLong(v) #define PyString_InternFromString(v) PyUnicode_InternFromString(v) #endif #define INTERN_STRING(value) _intern_##value #define INT_CONV_ERROR_OCCURRED(v) (((v) == -1) && PyErr_Occurred()) extern "C" { extern PyObject* INTERN_STRING(TFrozenDict); extern PyObject* INTERN_STRING(cstringio_buf); extern PyObject* INTERN_STRING(cstringio_refill); } namespace apache { namespace thrift { namespace py { extern PyObject* ThriftModule; // Stolen out of TProtocol.h. // It would be a huge pain to have both get this from one place. enum TType { T_INVALID = -1, T_STOP = 0, T_VOID = 1, T_BOOL = 2, T_BYTE = 3, T_I08 = 3, T_I16 = 6, T_I32 = 8, T_U64 = 9, T_I64 = 10, T_DOUBLE = 4, T_STRING = 11, T_UTF7 = 11, T_STRUCT = 12, T_MAP = 13, T_SET = 14, T_LIST = 15, T_UTF8 = 16, T_UTF16 = 17 }; // replace with unique_ptr when we're OK with C++11 class ScopedPyObject { public: ScopedPyObject() : obj_(nullptr) {} explicit ScopedPyObject(PyObject* py_object) : obj_(py_object) {} ~ScopedPyObject() { if (obj_) Py_DECREF(obj_); } PyObject* get() throw() { return obj_; } operator bool() { return obj_; } void reset(PyObject* py_object) throw() { if (obj_) Py_DECREF(obj_); obj_ = py_object; } PyObject* release() throw() { PyObject* tmp = obj_; obj_ = nullptr; return tmp; } void swap(ScopedPyObject& other) throw() { ScopedPyObject tmp(other.release()); other.reset(release()); reset(tmp.release()); } private: ScopedPyObject(const ScopedPyObject&) {} ScopedPyObject& operator=(const ScopedPyObject&) { return *this; } PyObject* obj_; }; /** * A cache of the two key attributes of a CReadableTransport, * so we don't have to keep calling PyObject_GetAttr. */ struct DecodeBuffer { ScopedPyObject stringiobuf; ScopedPyObject refill_callable; }; #if PY_MAJOR_VERSION < 3 extern char refill_signature[3]; typedef PyObject EncodeBuffer; #else extern const char* refill_signature; struct EncodeBuffer { std::vector buf; size_t pos; }; #endif /** * A cache of the spec_args for a set or list, * so we don't have to keep calling PyTuple_GET_ITEM. */ struct SetListTypeArgs { TType element_type; PyObject* typeargs; bool immutable; }; /** * A cache of the spec_args for a map, * so we don't have to keep calling PyTuple_GET_ITEM. */ struct MapTypeArgs { TType ktag; TType vtag; PyObject* ktypeargs; PyObject* vtypeargs; bool immutable; }; /** * A cache of the spec_args for a struct, * so we don't have to keep calling PyTuple_GET_ITEM. */ struct StructTypeArgs { PyObject* klass; PyObject* spec; bool immutable; }; /** * A cache of the item spec from a struct specification, * so we don't have to keep calling PyTuple_GET_ITEM. */ struct StructItemSpec { int tag; TType type; PyObject* attrname; PyObject* typeargs; PyObject* defval; }; bool parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs); bool parse_map_args(MapTypeArgs* dest, PyObject* typeargs); bool parse_struct_args(StructTypeArgs* dest, PyObject* typeargs); bool parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple); } } } #endif // THRIFT_PY_TYPES_H thrift-0.16.0/lib/py/src/protocol/000077500000000000000000000000001420101504100167105ustar00rootroot00000000000000thrift-0.16.0/lib/py/src/protocol/TBase.py000066400000000000000000000055171420101504100202700ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from thrift.transport import TTransport class TBase(object): __slots__ = () def __repr__(self): L = ['%s=%r' % (key, getattr(self, key)) for key in self.__slots__] return '%s(%s)' % (self.__class__.__name__, ', '.join(L)) def __eq__(self, other): if not isinstance(other, self.__class__): return False for attr in self.__slots__: my_val = getattr(self, attr) other_val = getattr(other, attr) if my_val != other_val: return False return True def __ne__(self, other): return not (self == other) def read(self, iprot): if (iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None): iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec]) else: iprot.readStruct(self, self.thrift_spec) def write(self, oprot): if (oprot._fast_encode is not None and self.thrift_spec is not None): oprot.trans.write( oprot._fast_encode(self, [self.__class__, self.thrift_spec])) else: oprot.writeStruct(self, self.thrift_spec) class TExceptionBase(TBase, Exception): pass class TFrozenBase(TBase): def __setitem__(self, *args): raise TypeError("Can't modify frozen struct") def __delitem__(self, *args): raise TypeError("Can't modify frozen struct") def __hash__(self, *args): return hash(self.__class__) ^ hash(self.__slots__) @classmethod def read(cls, iprot): if (iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and cls.thrift_spec is not None): self = cls() return iprot._fast_decode(None, iprot, [self.__class__, self.thrift_spec]) else: return iprot.readStruct(cls, cls.thrift_spec, True) class TFrozenExceptionBase(TFrozenBase, TExceptionBase): pass thrift-0.16.0/lib/py/src/protocol/TBinaryProtocol.py000066400000000000000000000216641420101504100223650ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from .TProtocol import TType, TProtocolBase, TProtocolException, TProtocolFactory from struct import pack, unpack class TBinaryProtocol(TProtocolBase): """Binary implementation of the Thrift protocol driver.""" # NastyHaxx. Python 2.4+ on 32-bit machines forces hex constants to be # positive, converting this into a long. If we hardcode the int value # instead it'll stay in 32 bit-land. # VERSION_MASK = 0xffff0000 VERSION_MASK = -65536 # VERSION_1 = 0x80010000 VERSION_1 = -2147418112 TYPE_MASK = 0x000000ff def __init__(self, trans, strictRead=False, strictWrite=True, **kwargs): TProtocolBase.__init__(self, trans) self.strictRead = strictRead self.strictWrite = strictWrite self.string_length_limit = kwargs.get('string_length_limit', None) self.container_length_limit = kwargs.get('container_length_limit', None) def _check_string_length(self, length): self._check_length(self.string_length_limit, length) def _check_container_length(self, length): self._check_length(self.container_length_limit, length) def writeMessageBegin(self, name, type, seqid): if self.strictWrite: self.writeI32(TBinaryProtocol.VERSION_1 | type) self.writeString(name) self.writeI32(seqid) else: self.writeString(name) self.writeByte(type) self.writeI32(seqid) def writeMessageEnd(self): pass def writeStructBegin(self, name): pass def writeStructEnd(self): pass def writeFieldBegin(self, name, type, id): self.writeByte(type) self.writeI16(id) def writeFieldEnd(self): pass def writeFieldStop(self): self.writeByte(TType.STOP) def writeMapBegin(self, ktype, vtype, size): self.writeByte(ktype) self.writeByte(vtype) self.writeI32(size) def writeMapEnd(self): pass def writeListBegin(self, etype, size): self.writeByte(etype) self.writeI32(size) def writeListEnd(self): pass def writeSetBegin(self, etype, size): self.writeByte(etype) self.writeI32(size) def writeSetEnd(self): pass def writeBool(self, bool): if bool: self.writeByte(1) else: self.writeByte(0) def writeByte(self, byte): buff = pack("!b", byte) self.trans.write(buff) def writeI16(self, i16): buff = pack("!h", i16) self.trans.write(buff) def writeI32(self, i32): buff = pack("!i", i32) self.trans.write(buff) def writeI64(self, i64): buff = pack("!q", i64) self.trans.write(buff) def writeDouble(self, dub): buff = pack("!d", dub) self.trans.write(buff) def writeBinary(self, str): self.writeI32(len(str)) self.trans.write(str) def readMessageBegin(self): sz = self.readI32() if sz < 0: version = sz & TBinaryProtocol.VERSION_MASK if version != TBinaryProtocol.VERSION_1: raise TProtocolException( type=TProtocolException.BAD_VERSION, message='Bad version in readMessageBegin: %d' % (sz)) type = sz & TBinaryProtocol.TYPE_MASK name = self.readString() seqid = self.readI32() else: if self.strictRead: raise TProtocolException(type=TProtocolException.BAD_VERSION, message='No protocol version header') name = self.trans.readAll(sz) type = self.readByte() seqid = self.readI32() return (name, type, seqid) def readMessageEnd(self): pass def readStructBegin(self): pass def readStructEnd(self): pass def readFieldBegin(self): type = self.readByte() if type == TType.STOP: return (None, type, 0) id = self.readI16() return (None, type, id) def readFieldEnd(self): pass def readMapBegin(self): ktype = self.readByte() vtype = self.readByte() size = self.readI32() self._check_container_length(size) return (ktype, vtype, size) def readMapEnd(self): pass def readListBegin(self): etype = self.readByte() size = self.readI32() self._check_container_length(size) return (etype, size) def readListEnd(self): pass def readSetBegin(self): etype = self.readByte() size = self.readI32() self._check_container_length(size) return (etype, size) def readSetEnd(self): pass def readBool(self): byte = self.readByte() if byte == 0: return False return True def readByte(self): buff = self.trans.readAll(1) val, = unpack('!b', buff) return val def readI16(self): buff = self.trans.readAll(2) val, = unpack('!h', buff) return val def readI32(self): buff = self.trans.readAll(4) val, = unpack('!i', buff) return val def readI64(self): buff = self.trans.readAll(8) val, = unpack('!q', buff) return val def readDouble(self): buff = self.trans.readAll(8) val, = unpack('!d', buff) return val def readBinary(self): size = self.readI32() self._check_string_length(size) s = self.trans.readAll(size) return s class TBinaryProtocolFactory(TProtocolFactory): def __init__(self, strictRead=False, strictWrite=True, **kwargs): self.strictRead = strictRead self.strictWrite = strictWrite self.string_length_limit = kwargs.get('string_length_limit', None) self.container_length_limit = kwargs.get('container_length_limit', None) def getProtocol(self, trans): prot = TBinaryProtocol(trans, self.strictRead, self.strictWrite, string_length_limit=self.string_length_limit, container_length_limit=self.container_length_limit) return prot class TBinaryProtocolAccelerated(TBinaryProtocol): """C-Accelerated version of TBinaryProtocol. This class does not override any of TBinaryProtocol's methods, but the generated code recognizes it directly and will call into our C module to do the encoding, bypassing this object entirely. We inherit from TBinaryProtocol so that the normal TBinaryProtocol encoding can happen if the fastbinary module doesn't work for some reason. (TODO(dreiss): Make this happen sanely in more cases.) To disable this behavior, pass fallback=False constructor argument. In order to take advantage of the C module, just use TBinaryProtocolAccelerated instead of TBinaryProtocol. NOTE: This code was contributed by an external developer. The internal Thrift team has reviewed and tested it, but we cannot guarantee that it is production-ready. Please feel free to report bugs and/or success stories to the public mailing list. """ pass def __init__(self, *args, **kwargs): fallback = kwargs.pop('fallback', True) super(TBinaryProtocolAccelerated, self).__init__(*args, **kwargs) try: from thrift.protocol import fastbinary except ImportError: if not fallback: raise else: self._fast_decode = fastbinary.decode_binary self._fast_encode = fastbinary.encode_binary class TBinaryProtocolAcceleratedFactory(TProtocolFactory): def __init__(self, string_length_limit=None, container_length_limit=None, fallback=True): self.string_length_limit = string_length_limit self.container_length_limit = container_length_limit self._fallback = fallback def getProtocol(self, trans): return TBinaryProtocolAccelerated( trans, string_length_limit=self.string_length_limit, container_length_limit=self.container_length_limit, fallback=self._fallback) thrift-0.16.0/lib/py/src/protocol/TCompactProtocol.py000066400000000000000000000361511420101504100225240ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from .TProtocol import TType, TProtocolBase, TProtocolException, TProtocolFactory, checkIntegerLimits from struct import pack, unpack from ..compat import binary_to_str, str_to_binary __all__ = ['TCompactProtocol', 'TCompactProtocolFactory'] CLEAR = 0 FIELD_WRITE = 1 VALUE_WRITE = 2 CONTAINER_WRITE = 3 BOOL_WRITE = 4 FIELD_READ = 5 CONTAINER_READ = 6 VALUE_READ = 7 BOOL_READ = 8 def make_helper(v_from, container): def helper(func): def nested(self, *args, **kwargs): assert self.state in (v_from, container), (self.state, v_from, container) return func(self, *args, **kwargs) return nested return helper writer = make_helper(VALUE_WRITE, CONTAINER_WRITE) reader = make_helper(VALUE_READ, CONTAINER_READ) def makeZigZag(n, bits): checkIntegerLimits(n, bits) return (n << 1) ^ (n >> (bits - 1)) def fromZigZag(n): return (n >> 1) ^ -(n & 1) def writeVarint(trans, n): assert n >= 0, "Input to TCompactProtocol writeVarint cannot be negative!" out = bytearray() while True: if n & ~0x7f == 0: out.append(n) break else: out.append((n & 0xff) | 0x80) n = n >> 7 trans.write(bytes(out)) def readVarint(trans): result = 0 shift = 0 while True: x = trans.readAll(1) byte = ord(x) result |= (byte & 0x7f) << shift if byte >> 7 == 0: return result shift += 7 class CompactType(object): STOP = 0x00 TRUE = 0x01 FALSE = 0x02 BYTE = 0x03 I16 = 0x04 I32 = 0x05 I64 = 0x06 DOUBLE = 0x07 BINARY = 0x08 LIST = 0x09 SET = 0x0A MAP = 0x0B STRUCT = 0x0C CTYPES = { TType.STOP: CompactType.STOP, TType.BOOL: CompactType.TRUE, # used for collection TType.BYTE: CompactType.BYTE, TType.I16: CompactType.I16, TType.I32: CompactType.I32, TType.I64: CompactType.I64, TType.DOUBLE: CompactType.DOUBLE, TType.STRING: CompactType.BINARY, TType.STRUCT: CompactType.STRUCT, TType.LIST: CompactType.LIST, TType.SET: CompactType.SET, TType.MAP: CompactType.MAP, } TTYPES = {} for k, v in CTYPES.items(): TTYPES[v] = k TTYPES[CompactType.FALSE] = TType.BOOL del k del v class TCompactProtocol(TProtocolBase): """Compact implementation of the Thrift protocol driver.""" PROTOCOL_ID = 0x82 VERSION = 1 VERSION_MASK = 0x1f TYPE_MASK = 0xe0 TYPE_BITS = 0x07 TYPE_SHIFT_AMOUNT = 5 def __init__(self, trans, string_length_limit=None, container_length_limit=None): TProtocolBase.__init__(self, trans) self.state = CLEAR self.__last_fid = 0 self.__bool_fid = None self.__bool_value = None self.__structs = [] self.__containers = [] self.string_length_limit = string_length_limit self.container_length_limit = container_length_limit def _check_string_length(self, length): self._check_length(self.string_length_limit, length) def _check_container_length(self, length): self._check_length(self.container_length_limit, length) def __writeVarint(self, n): writeVarint(self.trans, n) def writeMessageBegin(self, name, type, seqid): assert self.state == CLEAR self.__writeUByte(self.PROTOCOL_ID) self.__writeUByte(self.VERSION | (type << self.TYPE_SHIFT_AMOUNT)) # The sequence id is a signed 32-bit integer but the compact protocol # writes this out as a "var int" which is always positive, and attempting # to write a negative number results in an infinite loop, so we may # need to do some conversion here... tseqid = seqid if tseqid < 0: tseqid = 2147483648 + (2147483648 + tseqid) self.__writeVarint(tseqid) self.__writeBinary(str_to_binary(name)) self.state = VALUE_WRITE def writeMessageEnd(self): assert self.state == VALUE_WRITE self.state = CLEAR def writeStructBegin(self, name): assert self.state in (CLEAR, CONTAINER_WRITE, VALUE_WRITE), self.state self.__structs.append((self.state, self.__last_fid)) self.state = FIELD_WRITE self.__last_fid = 0 def writeStructEnd(self): assert self.state == FIELD_WRITE self.state, self.__last_fid = self.__structs.pop() def writeFieldStop(self): self.__writeByte(0) def __writeFieldHeader(self, type, fid): delta = fid - self.__last_fid if 0 < delta <= 15: self.__writeUByte(delta << 4 | type) else: self.__writeByte(type) self.__writeI16(fid) self.__last_fid = fid def writeFieldBegin(self, name, type, fid): assert self.state == FIELD_WRITE, self.state if type == TType.BOOL: self.state = BOOL_WRITE self.__bool_fid = fid else: self.state = VALUE_WRITE self.__writeFieldHeader(CTYPES[type], fid) def writeFieldEnd(self): assert self.state in (VALUE_WRITE, BOOL_WRITE), self.state self.state = FIELD_WRITE def __writeUByte(self, byte): self.trans.write(pack('!B', byte)) def __writeByte(self, byte): self.trans.write(pack('!b', byte)) def __writeI16(self, i16): self.__writeVarint(makeZigZag(i16, 16)) def __writeSize(self, i32): self.__writeVarint(i32) def writeCollectionBegin(self, etype, size): assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state if size <= 14: self.__writeUByte(size << 4 | CTYPES[etype]) else: self.__writeUByte(0xf0 | CTYPES[etype]) self.__writeSize(size) self.__containers.append(self.state) self.state = CONTAINER_WRITE writeSetBegin = writeCollectionBegin writeListBegin = writeCollectionBegin def writeMapBegin(self, ktype, vtype, size): assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state if size == 0: self.__writeByte(0) else: self.__writeSize(size) self.__writeUByte(CTYPES[ktype] << 4 | CTYPES[vtype]) self.__containers.append(self.state) self.state = CONTAINER_WRITE def writeCollectionEnd(self): assert self.state == CONTAINER_WRITE, self.state self.state = self.__containers.pop() writeMapEnd = writeCollectionEnd writeSetEnd = writeCollectionEnd writeListEnd = writeCollectionEnd def writeBool(self, bool): if self.state == BOOL_WRITE: if bool: ctype = CompactType.TRUE else: ctype = CompactType.FALSE self.__writeFieldHeader(ctype, self.__bool_fid) elif self.state == CONTAINER_WRITE: if bool: self.__writeByte(CompactType.TRUE) else: self.__writeByte(CompactType.FALSE) else: raise AssertionError("Invalid state in compact protocol") writeByte = writer(__writeByte) writeI16 = writer(__writeI16) @writer def writeI32(self, i32): self.__writeVarint(makeZigZag(i32, 32)) @writer def writeI64(self, i64): self.__writeVarint(makeZigZag(i64, 64)) @writer def writeDouble(self, dub): self.trans.write(pack('> 4 if delta == 0: fid = self.__readI16() else: fid = self.__last_fid + delta self.__last_fid = fid type = type & 0x0f if type == CompactType.TRUE: self.state = BOOL_READ self.__bool_value = True elif type == CompactType.FALSE: self.state = BOOL_READ self.__bool_value = False else: self.state = VALUE_READ return (None, self.__getTType(type), fid) def readFieldEnd(self): assert self.state in (VALUE_READ, BOOL_READ), self.state self.state = FIELD_READ def __readUByte(self): result, = unpack('!B', self.trans.readAll(1)) return result def __readByte(self): result, = unpack('!b', self.trans.readAll(1)) return result def __readVarint(self): return readVarint(self.trans) def __readZigZag(self): return fromZigZag(self.__readVarint()) def __readSize(self): result = self.__readVarint() if result < 0: raise TProtocolException("Length < 0") return result def readMessageBegin(self): assert self.state == CLEAR proto_id = self.__readUByte() if proto_id != self.PROTOCOL_ID: raise TProtocolException(TProtocolException.BAD_VERSION, 'Bad protocol id in the message: %d' % proto_id) ver_type = self.__readUByte() type = (ver_type >> self.TYPE_SHIFT_AMOUNT) & self.TYPE_BITS version = ver_type & self.VERSION_MASK if version != self.VERSION: raise TProtocolException(TProtocolException.BAD_VERSION, 'Bad version: %d (expect %d)' % (version, self.VERSION)) seqid = self.__readVarint() # the sequence is a compact "var int" which is treaded as unsigned, # however the sequence is actually signed... if seqid > 2147483647: seqid = -2147483648 - (2147483648 - seqid) name = binary_to_str(self.__readBinary()) return (name, type, seqid) def readMessageEnd(self): assert self.state == CLEAR assert len(self.__structs) == 0 def readStructBegin(self): assert self.state in (CLEAR, CONTAINER_READ, VALUE_READ), self.state self.__structs.append((self.state, self.__last_fid)) self.state = FIELD_READ self.__last_fid = 0 def readStructEnd(self): assert self.state == FIELD_READ self.state, self.__last_fid = self.__structs.pop() def readCollectionBegin(self): assert self.state in (VALUE_READ, CONTAINER_READ), self.state size_type = self.__readUByte() size = size_type >> 4 type = self.__getTType(size_type) if size == 15: size = self.__readSize() self._check_container_length(size) self.__containers.append(self.state) self.state = CONTAINER_READ return type, size readSetBegin = readCollectionBegin readListBegin = readCollectionBegin def readMapBegin(self): assert self.state in (VALUE_READ, CONTAINER_READ), self.state size = self.__readSize() self._check_container_length(size) types = 0 if size > 0: types = self.__readUByte() vtype = self.__getTType(types) ktype = self.__getTType(types >> 4) self.__containers.append(self.state) self.state = CONTAINER_READ return (ktype, vtype, size) def readCollectionEnd(self): assert self.state == CONTAINER_READ, self.state self.state = self.__containers.pop() readSetEnd = readCollectionEnd readListEnd = readCollectionEnd readMapEnd = readCollectionEnd def readBool(self): if self.state == BOOL_READ: return self.__bool_value == CompactType.TRUE elif self.state == CONTAINER_READ: return self.__readByte() == CompactType.TRUE else: raise AssertionError("Invalid state in compact protocol: %d" % self.state) readByte = reader(__readByte) __readI16 = __readZigZag readI16 = reader(__readZigZag) readI32 = reader(__readZigZag) readI64 = reader(__readZigZag) @reader def readDouble(self): buff = self.trans.readAll(8) val, = unpack('= 0xd800 and codeunit <= 0xdbff def _isLowSurrogate(self, codeunit): return codeunit >= 0xdc00 and codeunit <= 0xdfff def _toChar(self, high, low=None): if not low: if sys.version_info[0] == 2: return ("\\u%04x" % high).decode('unicode-escape') \ .encode('utf-8') else: return chr(high) else: codepoint = (1 << 16) + ((high & 0x3ff) << 10) codepoint += low & 0x3ff if sys.version_info[0] == 2: s = "\\U%08x" % codepoint return s.decode('unicode-escape').encode('utf-8') else: return chr(codepoint) def readJSONString(self, skipContext): highSurrogate = None string = [] if skipContext is False: self.context.read() self.readJSONSyntaxChar(QUOTE) while True: character = self.reader.read() if character == QUOTE: break if ord(character) == ESCSEQ0: character = self.reader.read() if ord(character) == ESCSEQ1: character = self.trans.read(4).decode('ascii') codeunit = int(character, 16) if self._isHighSurrogate(codeunit): if highSurrogate: raise TProtocolException( TProtocolException.INVALID_DATA, "Expected low surrogate char") highSurrogate = codeunit continue elif self._isLowSurrogate(codeunit): if not highSurrogate: raise TProtocolException( TProtocolException.INVALID_DATA, "Expected high surrogate char") character = self._toChar(highSurrogate, codeunit) highSurrogate = None else: character = self._toChar(codeunit) else: if character not in ESCAPE_CHARS: raise TProtocolException( TProtocolException.INVALID_DATA, "Expected control char") character = ESCAPE_CHARS[character] elif character in ESCAPE_CHAR_VALS: raise TProtocolException(TProtocolException.INVALID_DATA, "Unescaped control char") elif sys.version_info[0] > 2: utf8_bytes = bytearray([ord(character)]) while ord(self.reader.peek()) >= 0x80: utf8_bytes.append(ord(self.reader.read())) character = utf8_bytes.decode('utf8') string.append(character) if highSurrogate: raise TProtocolException(TProtocolException.INVALID_DATA, "Expected low surrogate char") return ''.join(string) def isJSONNumeric(self, character): return (True if NUMERIC_CHAR.find(character) != - 1 else False) def readJSONQuotes(self): if (self.context.escapeNum()): self.readJSONSyntaxChar(QUOTE) def readJSONNumericChars(self): numeric = [] while True: character = self.reader.peek() if self.isJSONNumeric(character) is False: break numeric.append(self.reader.read()) return b''.join(numeric).decode('ascii') def readJSONInteger(self): self.context.read() self.readJSONQuotes() numeric = self.readJSONNumericChars() self.readJSONQuotes() try: return int(numeric) except ValueError: raise TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data") def readJSONDouble(self): self.context.read() if self.reader.peek() == QUOTE: string = self.readJSONString(True) try: double = float(string) if (self.context.escapeNum is False and not math.isinf(double) and not math.isnan(double)): raise TProtocolException( TProtocolException.INVALID_DATA, "Numeric data unexpectedly quoted") return double except ValueError: raise TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data") else: if self.context.escapeNum() is True: self.readJSONSyntaxChar(QUOTE) try: return float(self.readJSONNumericChars()) except ValueError: raise TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data") def readJSONBase64(self): string = self.readJSONString(False) size = len(string) m = size % 4 # Force padding since b64encode method does not allow it if m != 0: for i in range(4 - m): string += '=' return base64.b64decode(string) def readJSONObjectStart(self): self.context.read() self.readJSONSyntaxChar(LBRACE) self.pushContext(JSONPairContext(self)) def readJSONObjectEnd(self): self.readJSONSyntaxChar(RBRACE) self.popContext() def readJSONArrayStart(self): self.context.read() self.readJSONSyntaxChar(LBRACKET) self.pushContext(JSONListContext(self)) def readJSONArrayEnd(self): self.readJSONSyntaxChar(RBRACKET) self.popContext() class TJSONProtocol(TJSONProtocolBase): def readMessageBegin(self): self.resetReadContext() self.readJSONArrayStart() if self.readJSONInteger() != VERSION: raise TProtocolException(TProtocolException.BAD_VERSION, "Message contained bad version.") name = self.readJSONString(False) typen = self.readJSONInteger() seqid = self.readJSONInteger() return (name, typen, seqid) def readMessageEnd(self): self.readJSONArrayEnd() def readStructBegin(self): self.readJSONObjectStart() def readStructEnd(self): self.readJSONObjectEnd() def readFieldBegin(self): character = self.reader.peek() ttype = 0 id = 0 if character == RBRACE: ttype = TType.STOP else: id = self.readJSONInteger() self.readJSONObjectStart() ttype = JTYPES[self.readJSONString(False)] return (None, ttype, id) def readFieldEnd(self): self.readJSONObjectEnd() def readMapBegin(self): self.readJSONArrayStart() keyType = JTYPES[self.readJSONString(False)] valueType = JTYPES[self.readJSONString(False)] size = self.readJSONInteger() self.readJSONObjectStart() return (keyType, valueType, size) def readMapEnd(self): self.readJSONObjectEnd() self.readJSONArrayEnd() def readCollectionBegin(self): self.readJSONArrayStart() elemType = JTYPES[self.readJSONString(False)] size = self.readJSONInteger() return (elemType, size) readListBegin = readCollectionBegin readSetBegin = readCollectionBegin def readCollectionEnd(self): self.readJSONArrayEnd() readSetEnd = readCollectionEnd readListEnd = readCollectionEnd def readBool(self): return (False if self.readJSONInteger() == 0 else True) def readNumber(self): return self.readJSONInteger() readByte = readNumber readI16 = readNumber readI32 = readNumber readI64 = readNumber def readDouble(self): return self.readJSONDouble() def readString(self): return self.readJSONString(False) def readBinary(self): return self.readJSONBase64() def writeMessageBegin(self, name, request_type, seqid): self.resetWriteContext() self.writeJSONArrayStart() self.writeJSONNumber(VERSION) self.writeJSONString(name) self.writeJSONNumber(request_type) self.writeJSONNumber(seqid) def writeMessageEnd(self): self.writeJSONArrayEnd() def writeStructBegin(self, name): self.writeJSONObjectStart() def writeStructEnd(self): self.writeJSONObjectEnd() def writeFieldBegin(self, name, ttype, id): self.writeJSONNumber(id) self.writeJSONObjectStart() self.writeJSONString(CTYPES[ttype]) def writeFieldEnd(self): self.writeJSONObjectEnd() def writeFieldStop(self): pass def writeMapBegin(self, ktype, vtype, size): self.writeJSONArrayStart() self.writeJSONString(CTYPES[ktype]) self.writeJSONString(CTYPES[vtype]) self.writeJSONNumber(size) self.writeJSONObjectStart() def writeMapEnd(self): self.writeJSONObjectEnd() self.writeJSONArrayEnd() def writeListBegin(self, etype, size): self.writeJSONArrayStart() self.writeJSONString(CTYPES[etype]) self.writeJSONNumber(size) def writeListEnd(self): self.writeJSONArrayEnd() def writeSetBegin(self, etype, size): self.writeJSONArrayStart() self.writeJSONString(CTYPES[etype]) self.writeJSONNumber(size) def writeSetEnd(self): self.writeJSONArrayEnd() def writeBool(self, boolean): self.writeJSONNumber(1 if boolean is True else 0) def writeByte(self, byte): checkIntegerLimits(byte, 8) self.writeJSONNumber(byte) def writeI16(self, i16): checkIntegerLimits(i16, 16) self.writeJSONNumber(i16) def writeI32(self, i32): checkIntegerLimits(i32, 32) self.writeJSONNumber(i32) def writeI64(self, i64): checkIntegerLimits(i64, 64) self.writeJSONNumber(i64) def writeDouble(self, dbl): # 17 significant digits should be just enough for any double precision # value. self.writeJSONNumber(dbl, '{0:.17g}') def writeString(self, string): self.writeJSONString(string) def writeBinary(self, binary): self.writeJSONBase64(binary) class TJSONProtocolFactory(TProtocolFactory): def getProtocol(self, trans): return TJSONProtocol(trans) @property def string_length_limit(senf): return None @property def container_length_limit(senf): return None class TSimpleJSONProtocol(TJSONProtocolBase): """Simple, readable, write-only JSON protocol. Useful for interacting with scripting languages. """ def readMessageBegin(self): raise NotImplementedError() def readMessageEnd(self): raise NotImplementedError() def readStructBegin(self): raise NotImplementedError() def readStructEnd(self): raise NotImplementedError() def writeMessageBegin(self, name, request_type, seqid): self.resetWriteContext() def writeMessageEnd(self): pass def writeStructBegin(self, name): self.writeJSONObjectStart() def writeStructEnd(self): self.writeJSONObjectEnd() def writeFieldBegin(self, name, ttype, fid): self.writeJSONString(name) def writeFieldEnd(self): pass def writeMapBegin(self, ktype, vtype, size): self.writeJSONObjectStart() def writeMapEnd(self): self.writeJSONObjectEnd() def _writeCollectionBegin(self, etype, size): self.writeJSONArrayStart() def _writeCollectionEnd(self): self.writeJSONArrayEnd() writeListBegin = _writeCollectionBegin writeListEnd = _writeCollectionEnd writeSetBegin = _writeCollectionBegin writeSetEnd = _writeCollectionEnd def writeByte(self, byte): checkIntegerLimits(byte, 8) self.writeJSONNumber(byte) def writeI16(self, i16): checkIntegerLimits(i16, 16) self.writeJSONNumber(i16) def writeI32(self, i32): checkIntegerLimits(i32, 32) self.writeJSONNumber(i32) def writeI64(self, i64): checkIntegerLimits(i64, 64) self.writeJSONNumber(i64) def writeBool(self, boolean): self.writeJSONNumber(1 if boolean is True else 0) def writeDouble(self, dbl): self.writeJSONNumber(dbl) def writeString(self, string): self.writeJSONString(string) def writeBinary(self, binary): self.writeJSONBase64(binary) class TSimpleJSONProtocolFactory(TProtocolFactory): def getProtocol(self, trans): return TSimpleJSONProtocol(trans) thrift-0.16.0/lib/py/src/protocol/TMultiplexedProtocol.py000066400000000000000000000026611420101504100234310ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from thrift.Thrift import TMessageType from thrift.protocol import TProtocolDecorator SEPARATOR = ":" class TMultiplexedProtocol(TProtocolDecorator.TProtocolDecorator): def __init__(self, protocol, serviceName): self.serviceName = serviceName def writeMessageBegin(self, name, type, seqid): if (type == TMessageType.CALL or type == TMessageType.ONEWAY): super(TMultiplexedProtocol, self).writeMessageBegin( self.serviceName + SEPARATOR + name, type, seqid ) else: super(TMultiplexedProtocol, self).writeMessageBegin(name, type, seqid) thrift-0.16.0/lib/py/src/protocol/TProtocol.py000066400000000000000000000325771420101504100212250ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from thrift.Thrift import TException, TType, TFrozenDict from thrift.transport.TTransport import TTransportException from ..compat import binary_to_str, str_to_binary import six import sys from itertools import islice from six.moves import zip class TProtocolException(TException): """Custom Protocol Exception class""" UNKNOWN = 0 INVALID_DATA = 1 NEGATIVE_SIZE = 2 SIZE_LIMIT = 3 BAD_VERSION = 4 NOT_IMPLEMENTED = 5 DEPTH_LIMIT = 6 INVALID_PROTOCOL = 7 def __init__(self, type=UNKNOWN, message=None): TException.__init__(self, message) self.type = type class TProtocolBase(object): """Base class for Thrift protocol driver.""" def __init__(self, trans): self.trans = trans self._fast_decode = None self._fast_encode = None @staticmethod def _check_length(limit, length): if length < 0: raise TTransportException(TTransportException.NEGATIVE_SIZE, 'Negative length: %d' % length) if limit is not None and length > limit: raise TTransportException(TTransportException.SIZE_LIMIT, 'Length exceeded max allowed: %d' % limit) def writeMessageBegin(self, name, ttype, seqid): pass def writeMessageEnd(self): pass def writeStructBegin(self, name): pass def writeStructEnd(self): pass def writeFieldBegin(self, name, ttype, fid): pass def writeFieldEnd(self): pass def writeFieldStop(self): pass def writeMapBegin(self, ktype, vtype, size): pass def writeMapEnd(self): pass def writeListBegin(self, etype, size): pass def writeListEnd(self): pass def writeSetBegin(self, etype, size): pass def writeSetEnd(self): pass def writeBool(self, bool_val): pass def writeByte(self, byte): pass def writeI16(self, i16): pass def writeI32(self, i32): pass def writeI64(self, i64): pass def writeDouble(self, dub): pass def writeString(self, str_val): self.writeBinary(str_to_binary(str_val)) def writeBinary(self, str_val): pass def writeUtf8(self, str_val): self.writeString(str_val.encode('utf8')) def readMessageBegin(self): pass def readMessageEnd(self): pass def readStructBegin(self): pass def readStructEnd(self): pass def readFieldBegin(self): pass def readFieldEnd(self): pass def readMapBegin(self): pass def readMapEnd(self): pass def readListBegin(self): pass def readListEnd(self): pass def readSetBegin(self): pass def readSetEnd(self): pass def readBool(self): pass def readByte(self): pass def readI16(self): pass def readI32(self): pass def readI64(self): pass def readDouble(self): pass def readString(self): return binary_to_str(self.readBinary()) def readBinary(self): pass def readUtf8(self): return self.readString().decode('utf8') def skip(self, ttype): if ttype == TType.BOOL: self.readBool() elif ttype == TType.BYTE: self.readByte() elif ttype == TType.I16: self.readI16() elif ttype == TType.I32: self.readI32() elif ttype == TType.I64: self.readI64() elif ttype == TType.DOUBLE: self.readDouble() elif ttype == TType.STRING: self.readString() elif ttype == TType.STRUCT: name = self.readStructBegin() while True: (name, ttype, id) = self.readFieldBegin() if ttype == TType.STOP: break self.skip(ttype) self.readFieldEnd() self.readStructEnd() elif ttype == TType.MAP: (ktype, vtype, size) = self.readMapBegin() for i in range(size): self.skip(ktype) self.skip(vtype) self.readMapEnd() elif ttype == TType.SET: (etype, size) = self.readSetBegin() for i in range(size): self.skip(etype) self.readSetEnd() elif ttype == TType.LIST: (etype, size) = self.readListBegin() for i in range(size): self.skip(etype) self.readListEnd() else: raise TProtocolException( TProtocolException.INVALID_DATA, "invalid TType") # tuple of: ( 'reader method' name, is_container bool, 'writer_method' name ) _TTYPE_HANDLERS = ( (None, None, False), # 0 TType.STOP (None, None, False), # 1 TType.VOID # TODO: handle void? ('readBool', 'writeBool', False), # 2 TType.BOOL ('readByte', 'writeByte', False), # 3 TType.BYTE and I08 ('readDouble', 'writeDouble', False), # 4 TType.DOUBLE (None, None, False), # 5 undefined ('readI16', 'writeI16', False), # 6 TType.I16 (None, None, False), # 7 undefined ('readI32', 'writeI32', False), # 8 TType.I32 (None, None, False), # 9 undefined ('readI64', 'writeI64', False), # 10 TType.I64 ('readString', 'writeString', False), # 11 TType.STRING and UTF7 ('readContainerStruct', 'writeContainerStruct', True), # 12 *.STRUCT ('readContainerMap', 'writeContainerMap', True), # 13 TType.MAP ('readContainerSet', 'writeContainerSet', True), # 14 TType.SET ('readContainerList', 'writeContainerList', True), # 15 TType.LIST (None, None, False), # 16 TType.UTF8 # TODO: handle utf8 types? (None, None, False) # 17 TType.UTF16 # TODO: handle utf16 types? ) def _ttype_handlers(self, ttype, spec): if spec == 'BINARY': if ttype != TType.STRING: raise TProtocolException(type=TProtocolException.INVALID_DATA, message='Invalid binary field type %d' % ttype) return ('readBinary', 'writeBinary', False) if sys.version_info[0] == 2 and spec == 'UTF8': if ttype != TType.STRING: raise TProtocolException(type=TProtocolException.INVALID_DATA, message='Invalid string field type %d' % ttype) return ('readUtf8', 'writeUtf8', False) return self._TTYPE_HANDLERS[ttype] if ttype < len(self._TTYPE_HANDLERS) else (None, None, False) def _read_by_ttype(self, ttype, spec, espec): reader_name, _, is_container = self._ttype_handlers(ttype, espec) if reader_name is None: raise TProtocolException(type=TProtocolException.INVALID_DATA, message='Invalid type %d' % (ttype)) reader_func = getattr(self, reader_name) read = (lambda: reader_func(espec)) if is_container else reader_func while True: yield read() def readFieldByTType(self, ttype, spec): return next(self._read_by_ttype(ttype, spec, spec)) def readContainerList(self, spec): ttype, tspec, is_immutable = spec (list_type, list_len) = self.readListBegin() # TODO: compare types we just decoded with thrift_spec elems = islice(self._read_by_ttype(ttype, spec, tspec), list_len) results = (tuple if is_immutable else list)(elems) self.readListEnd() return results def readContainerSet(self, spec): ttype, tspec, is_immutable = spec (set_type, set_len) = self.readSetBegin() # TODO: compare types we just decoded with thrift_spec elems = islice(self._read_by_ttype(ttype, spec, tspec), set_len) results = (frozenset if is_immutable else set)(elems) self.readSetEnd() return results def readContainerStruct(self, spec): (obj_class, obj_spec) = spec # If obj_class.read is a classmethod (e.g. in frozen structs), # call it as such. if getattr(obj_class.read, '__self__', None) is obj_class: obj = obj_class.read(self) else: obj = obj_class() obj.read(self) return obj def readContainerMap(self, spec): ktype, kspec, vtype, vspec, is_immutable = spec (map_ktype, map_vtype, map_len) = self.readMapBegin() # TODO: compare types we just decoded with thrift_spec and # abort/skip if types disagree keys = self._read_by_ttype(ktype, spec, kspec) vals = self._read_by_ttype(vtype, spec, vspec) keyvals = islice(zip(keys, vals), map_len) results = (TFrozenDict if is_immutable else dict)(keyvals) self.readMapEnd() return results def readStruct(self, obj, thrift_spec, is_immutable=False): if is_immutable: fields = {} self.readStructBegin() while True: (fname, ftype, fid) = self.readFieldBegin() if ftype == TType.STOP: break try: field = thrift_spec[fid] except IndexError: self.skip(ftype) else: if field is not None and ftype == field[1]: fname = field[2] fspec = field[3] val = self.readFieldByTType(ftype, fspec) if is_immutable: fields[fname] = val else: setattr(obj, fname, val) else: self.skip(ftype) self.readFieldEnd() self.readStructEnd() if is_immutable: return obj(**fields) def writeContainerStruct(self, val, spec): val.write(self) def writeContainerList(self, val, spec): ttype, tspec, _ = spec self.writeListBegin(ttype, len(val)) for _ in self._write_by_ttype(ttype, val, spec, tspec): pass self.writeListEnd() def writeContainerSet(self, val, spec): ttype, tspec, _ = spec self.writeSetBegin(ttype, len(val)) for _ in self._write_by_ttype(ttype, val, spec, tspec): pass self.writeSetEnd() def writeContainerMap(self, val, spec): ktype, kspec, vtype, vspec, _ = spec self.writeMapBegin(ktype, vtype, len(val)) for _ in zip(self._write_by_ttype(ktype, six.iterkeys(val), spec, kspec), self._write_by_ttype(vtype, six.itervalues(val), spec, vspec)): pass self.writeMapEnd() def writeStruct(self, obj, thrift_spec): self.writeStructBegin(obj.__class__.__name__) for field in thrift_spec: if field is None: continue fname = field[2] val = getattr(obj, fname) if val is None: # skip writing out unset fields continue fid = field[0] ftype = field[1] fspec = field[3] self.writeFieldBegin(fname, ftype, fid) self.writeFieldByTType(ftype, val, fspec) self.writeFieldEnd() self.writeFieldStop() self.writeStructEnd() def _write_by_ttype(self, ttype, vals, spec, espec): _, writer_name, is_container = self._ttype_handlers(ttype, espec) writer_func = getattr(self, writer_name) write = (lambda v: writer_func(v, espec)) if is_container else writer_func for v in vals: yield write(v) def writeFieldByTType(self, ttype, val, spec): next(self._write_by_ttype(ttype, [val], spec, spec)) def checkIntegerLimits(i, bits): if bits == 8 and (i < -128 or i > 127): raise TProtocolException(TProtocolException.INVALID_DATA, "i8 requires -128 <= number <= 127") elif bits == 16 and (i < -32768 or i > 32767): raise TProtocolException(TProtocolException.INVALID_DATA, "i16 requires -32768 <= number <= 32767") elif bits == 32 and (i < -2147483648 or i > 2147483647): raise TProtocolException(TProtocolException.INVALID_DATA, "i32 requires -2147483648 <= number <= 2147483647") elif bits == 64 and (i < -9223372036854775808 or i > 9223372036854775807): raise TProtocolException(TProtocolException.INVALID_DATA, "i64 requires -9223372036854775808 <= number <= 9223372036854775807") class TProtocolFactory(object): def getProtocol(self, trans): pass thrift-0.16.0/lib/py/src/protocol/TProtocolDecorator.py000066400000000000000000000021151420101504100230510ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # class TProtocolDecorator(object): def __new__(cls, protocol, *args, **kwargs): decorated_cls = type(''.join(['Decorated', protocol.__class__.__name__]), (cls, protocol.__class__), protocol.__dict__) return object.__new__(decorated_cls) thrift-0.16.0/lib/py/src/protocol/__init__.py000066400000000000000000000016321420101504100210230ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # __all__ = ['fastbinary', 'TBase', 'TBinaryProtocol', 'TCompactProtocol', 'TJSONProtocol', 'TProtocol', 'TProtocolDecorator'] thrift-0.16.0/lib/py/src/server/000077500000000000000000000000001420101504100163555ustar00rootroot00000000000000thrift-0.16.0/lib/py/src/server/THttpServer.py000066400000000000000000000126571420101504100211740ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import ssl from six.moves import BaseHTTPServer from thrift.Thrift import TMessageType from thrift.server import TServer from thrift.transport import TTransport class ResponseException(Exception): """Allows handlers to override the HTTP response Normally, THttpServer always sends a 200 response. If a handler wants to override this behavior (e.g., to simulate a misconfigured or overloaded web server during testing), it can raise a ResponseException. The function passed to the constructor will be called with the RequestHandler as its only argument. Note that this is irrelevant for ONEWAY requests, as the HTTP response must be sent before the RPC is processed. """ def __init__(self, handler): self.handler = handler class THttpServer(TServer.TServer): """A simple HTTP-based Thrift server This class is not very performant, but it is useful (for example) for acting as a mock version of an Apache-based PHP Thrift endpoint. Also important to note the HTTP implementation pretty much violates the transport/protocol/processor/server layering, by performing the transport functions here. This means things like oneway handling are oddly exposed. """ def __init__(self, processor, server_address, inputProtocolFactory, outputProtocolFactory=None, server_class=BaseHTTPServer.HTTPServer, **kwargs): """Set up protocol factories and HTTP (or HTTPS) server. See BaseHTTPServer for server_address. See TServer for protocol factories. To make a secure server, provide the named arguments: * cafile - to validate clients [optional] * cert_file - the server cert * key_file - the server's key """ if outputProtocolFactory is None: outputProtocolFactory = inputProtocolFactory TServer.TServer.__init__(self, processor, None, None, None, inputProtocolFactory, outputProtocolFactory) thttpserver = self self._replied = None class RequestHander(BaseHTTPServer.BaseHTTPRequestHandler): def do_POST(self): # Don't care about the request path. thttpserver._replied = False iftrans = TTransport.TFileObjectTransport(self.rfile) itrans = TTransport.TBufferedTransport( iftrans, int(self.headers['Content-Length'])) otrans = TTransport.TMemoryBuffer() iprot = thttpserver.inputProtocolFactory.getProtocol(itrans) oprot = thttpserver.outputProtocolFactory.getProtocol(otrans) try: thttpserver.processor.on_message_begin(self.on_begin) thttpserver.processor.process(iprot, oprot) except ResponseException as exn: exn.handler(self) else: if not thttpserver._replied: # If the request was ONEWAY we would have replied already data = otrans.getvalue() self.send_response(200) self.send_header("Content-Length", len(data)) self.send_header("Content-Type", "application/x-thrift") self.end_headers() self.wfile.write(data) def on_begin(self, name, type, seqid): """ Inspect the message header. This allows us to post an immediate transport response if the request is a ONEWAY message type. """ if type == TMessageType.ONEWAY: self.send_response(200) self.send_header("Content-Type", "application/x-thrift") self.end_headers() thttpserver._replied = True self.httpd = server_class(server_address, RequestHander) if (kwargs.get('cafile') or kwargs.get('cert_file') or kwargs.get('key_file')): context = ssl.create_default_context(cafile=kwargs.get('cafile')) context.check_hostname = False context.load_cert_chain(kwargs.get('cert_file'), kwargs.get('key_file')) context.verify_mode = ssl.CERT_REQUIRED if kwargs.get('cafile') else ssl.CERT_NONE self.httpd.socket = context.wrap_socket(self.httpd.socket, server_side=True) def serve(self): self.httpd.serve_forever() def shutdown(self): self.httpd.socket.close() # self.httpd.shutdown() # hangs forever, python doesn't handle POLLNVAL properly! thrift-0.16.0/lib/py/src/server/TNonblockingServer.py000066400000000000000000000303171420101504100225110ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # """Implementation of non-blocking server. The main idea of the server is to receive and send requests only from the main thread. The thread poool should be sized for concurrent tasks, not maximum connections """ import logging import select import socket import struct import threading from collections import deque from six.moves import queue from thrift.transport import TTransport from thrift.protocol.TBinaryProtocol import TBinaryProtocolFactory __all__ = ['TNonblockingServer'] logger = logging.getLogger(__name__) class Worker(threading.Thread): """Worker is a small helper to process incoming connection.""" def __init__(self, queue): threading.Thread.__init__(self) self.queue = queue def run(self): """Process queries from task queue, stop if processor is None.""" while True: try: processor, iprot, oprot, otrans, callback = self.queue.get() if processor is None: break processor.process(iprot, oprot) callback(True, otrans.getvalue()) except Exception: logger.exception("Exception while processing request", exc_info=True) callback(False, b'') WAIT_LEN = 0 WAIT_MESSAGE = 1 WAIT_PROCESS = 2 SEND_ANSWER = 3 CLOSED = 4 def locked(func): """Decorator which locks self.lock.""" def nested(self, *args, **kwargs): self.lock.acquire() try: return func(self, *args, **kwargs) finally: self.lock.release() return nested def socket_exception(func): """Decorator close object on socket.error.""" def read(self, *args, **kwargs): try: return func(self, *args, **kwargs) except socket.error: logger.debug('ignoring socket exception', exc_info=True) self.close() return read class Message(object): def __init__(self, offset, len_, header): self.offset = offset self.len = len_ self.buffer = None self.is_header = header @property def end(self): return self.offset + self.len class Connection(object): """Basic class is represented connection. It can be in state: WAIT_LEN --- connection is reading request len. WAIT_MESSAGE --- connection is reading request. WAIT_PROCESS --- connection has just read whole request and waits for call ready routine. SEND_ANSWER --- connection is sending answer string (including length of answer). CLOSED --- socket was closed and connection should be deleted. """ def __init__(self, new_socket, wake_up): self.socket = new_socket self.socket.setblocking(False) self.status = WAIT_LEN self.len = 0 self.received = deque() self._reading = Message(0, 4, True) self._rbuf = b'' self._wbuf = b'' self.lock = threading.Lock() self.wake_up = wake_up self.remaining = False @socket_exception def read(self): """Reads data from stream and switch state.""" assert self.status in (WAIT_LEN, WAIT_MESSAGE) assert not self.received buf_size = 8192 first = True done = False while not done: read = self.socket.recv(buf_size) rlen = len(read) done = rlen < buf_size self._rbuf += read if first and rlen == 0: if self.status != WAIT_LEN or self._rbuf: logger.error('could not read frame from socket') else: logger.debug('read zero length. client might have disconnected') self.close() while len(self._rbuf) >= self._reading.end: if self._reading.is_header: mlen, = struct.unpack('!i', self._rbuf[:4]) self._reading = Message(self._reading.end, mlen, False) self.status = WAIT_MESSAGE else: self._reading.buffer = self._rbuf self.received.append(self._reading) self._rbuf = self._rbuf[self._reading.end:] self._reading = Message(0, 4, True) first = False if self.received: self.status = WAIT_PROCESS break self.remaining = not done @socket_exception def write(self): """Writes data from socket and switch state.""" assert self.status == SEND_ANSWER sent = self.socket.send(self._wbuf) if sent == len(self._wbuf): self.status = WAIT_LEN self._wbuf = b'' self.len = 0 else: self._wbuf = self._wbuf[sent:] @locked def ready(self, all_ok, message): """Callback function for switching state and waking up main thread. This function is the only function witch can be called asynchronous. The ready can switch Connection to three states: WAIT_LEN if request was oneway. SEND_ANSWER if request was processed in normal way. CLOSED if request throws unexpected exception. The one wakes up main thread. """ assert self.status == WAIT_PROCESS if not all_ok: self.close() self.wake_up() return self.len = 0 if len(message) == 0: # it was a oneway request, do not write answer self._wbuf = b'' self.status = WAIT_LEN else: self._wbuf = struct.pack('!i', len(message)) + message self.status = SEND_ANSWER self.wake_up() @locked def is_writeable(self): """Return True if connection should be added to write list of select""" return self.status == SEND_ANSWER # it's not necessary, but... @locked def is_readable(self): """Return True if connection should be added to read list of select""" return self.status in (WAIT_LEN, WAIT_MESSAGE) @locked def is_closed(self): """Returns True if connection is closed.""" return self.status == CLOSED def fileno(self): """Returns the file descriptor of the associated socket.""" return self.socket.fileno() def close(self): """Closes connection""" self.status = CLOSED self.socket.close() class TNonblockingServer(object): """Non-blocking server.""" def __init__(self, processor, lsocket, inputProtocolFactory=None, outputProtocolFactory=None, threads=10): self.processor = processor self.socket = lsocket self.in_protocol = inputProtocolFactory or TBinaryProtocolFactory() self.out_protocol = outputProtocolFactory or self.in_protocol self.threads = int(threads) self.clients = {} self.tasks = queue.Queue() self._read, self._write = socket.socketpair() self.prepared = False self._stop = False def setNumThreads(self, num): """Set the number of worker threads that should be created.""" # implement ThreadPool interface assert not self.prepared, "Can't change number of threads after start" self.threads = num def prepare(self): """Prepares server for serve requests.""" if self.prepared: return self.socket.listen() for _ in range(self.threads): thread = Worker(self.tasks) thread.setDaemon(True) thread.start() self.prepared = True def wake_up(self): """Wake up main thread. The server usually waits in select call in we should terminate one. The simplest way is using socketpair. Select always wait to read from the first socket of socketpair. In this case, we can just write anything to the second socket from socketpair. """ self._write.send(b'1') def stop(self): """Stop the server. This method causes the serve() method to return. stop() may be invoked from within your handler, or from another thread. After stop() is called, serve() will return but the server will still be listening on the socket. serve() may then be called again to resume processing requests. Alternatively, close() may be called after serve() returns to close the server socket and shutdown all worker threads. """ self._stop = True self.wake_up() def _select(self): """Does select on open connections.""" readable = [self.socket.handle.fileno(), self._read.fileno()] writable = [] remaining = [] for i, connection in list(self.clients.items()): if connection.is_readable(): readable.append(connection.fileno()) if connection.remaining or connection.received: remaining.append(connection.fileno()) if connection.is_writeable(): writable.append(connection.fileno()) if connection.is_closed(): del self.clients[i] if remaining: return remaining, [], [], False else: return select.select(readable, writable, readable) + (True,) def handle(self): """Handle requests. WARNING! You must call prepare() BEFORE calling handle() """ assert self.prepared, "You have to call prepare before handle" rset, wset, xset, selected = self._select() for readable in rset: if readable == self._read.fileno(): # don't care i just need to clean readable flag self._read.recv(1024) elif readable == self.socket.handle.fileno(): try: client = self.socket.accept() if client: self.clients[client.handle.fileno()] = Connection(client.handle, self.wake_up) except socket.error: logger.debug('error while accepting', exc_info=True) else: connection = self.clients[readable] if selected: connection.read() if connection.received: connection.status = WAIT_PROCESS msg = connection.received.popleft() itransport = TTransport.TMemoryBuffer(msg.buffer, msg.offset) otransport = TTransport.TMemoryBuffer() iprot = self.in_protocol.getProtocol(itransport) oprot = self.out_protocol.getProtocol(otransport) self.tasks.put([self.processor, iprot, oprot, otransport, connection.ready]) for writeable in wset: self.clients[writeable].write() for oob in xset: self.clients[oob].close() del self.clients[oob] def close(self): """Closes the server.""" for _ in range(self.threads): self.tasks.put([None, None, None, None, None]) self.socket.close() self.prepared = False def serve(self): """Serve requests. Serve requests forever, or until stop() is called. """ self._stop = False self.prepare() while not self._stop: self.handle() thrift-0.16.0/lib/py/src/server/TProcessPoolServer.py000066400000000000000000000101151420101504100225100ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import logging from multiprocessing import Process, Value, Condition from .TServer import TServer from thrift.transport.TTransport import TTransportException logger = logging.getLogger(__name__) class TProcessPoolServer(TServer): """Server with a fixed size pool of worker subprocesses to service requests Note that if you need shared state between the handlers - it's up to you! Written by Dvir Volk, doat.com """ def __init__(self, *args): TServer.__init__(self, *args) self.numWorkers = 10 self.workers = [] self.isRunning = Value('b', False) self.stopCondition = Condition() self.postForkCallback = None def __getstate__(self): state = self.__dict__.copy() state['workers'] = None return state def setPostForkCallback(self, callback): if not callable(callback): raise TypeError("This is not a callback!") self.postForkCallback = callback def setNumWorkers(self, num): """Set the number of worker threads that should be created""" self.numWorkers = num def workerProcess(self): """Loop getting clients from the shared queue and process them""" if self.postForkCallback: self.postForkCallback() while self.isRunning.value: try: client = self.serverTransport.accept() if not client: continue self.serveClient(client) except (KeyboardInterrupt, SystemExit): return 0 except Exception as x: logger.exception(x) def serveClient(self, client): """Process input/output from a client for as long as possible""" itrans = self.inputTransportFactory.getTransport(client) otrans = self.outputTransportFactory.getTransport(client) iprot = self.inputProtocolFactory.getProtocol(itrans) oprot = self.outputProtocolFactory.getProtocol(otrans) try: while True: self.processor.process(iprot, oprot) except TTransportException: pass except Exception as x: logger.exception(x) itrans.close() otrans.close() def serve(self): """Start workers and put into queue""" # this is a shared state that can tell the workers to exit when False self.isRunning.value = True # first bind and listen to the port self.serverTransport.listen() # fork the children for i in range(self.numWorkers): try: w = Process(target=self.workerProcess) w.daemon = True w.start() self.workers.append(w) except Exception as x: logger.exception(x) # wait until the condition is set by stop() while True: self.stopCondition.acquire() try: self.stopCondition.wait() break except (SystemExit, KeyboardInterrupt): break except Exception as x: logger.exception(x) self.isRunning.value = False def stop(self): self.isRunning.value = False self.stopCondition.acquire() self.stopCondition.notify() self.stopCondition.release() thrift-0.16.0/lib/py/src/server/TServer.py000066400000000000000000000270101420101504100203210ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from six.moves import queue import logging import os import threading from thrift.protocol import TBinaryProtocol from thrift.protocol.THeaderProtocol import THeaderProtocolFactory from thrift.transport import TTransport logger = logging.getLogger(__name__) class TServer(object): """Base interface for a server, which must have a serve() method. Three constructors for all servers: 1) (processor, serverTransport) 2) (processor, serverTransport, transportFactory, protocolFactory) 3) (processor, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory) """ def __init__(self, *args): if (len(args) == 2): self.__initArgs__(args[0], args[1], TTransport.TTransportFactoryBase(), TTransport.TTransportFactoryBase(), TBinaryProtocol.TBinaryProtocolFactory(), TBinaryProtocol.TBinaryProtocolFactory()) elif (len(args) == 4): self.__initArgs__(args[0], args[1], args[2], args[2], args[3], args[3]) elif (len(args) == 6): self.__initArgs__(args[0], args[1], args[2], args[3], args[4], args[5]) def __initArgs__(self, processor, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory): self.processor = processor self.serverTransport = serverTransport self.inputTransportFactory = inputTransportFactory self.outputTransportFactory = outputTransportFactory self.inputProtocolFactory = inputProtocolFactory self.outputProtocolFactory = outputProtocolFactory input_is_header = isinstance(self.inputProtocolFactory, THeaderProtocolFactory) output_is_header = isinstance(self.outputProtocolFactory, THeaderProtocolFactory) if any((input_is_header, output_is_header)) and input_is_header != output_is_header: raise ValueError("THeaderProtocol servers require that both the input and " "output protocols are THeaderProtocol.") def serve(self): pass class TSimpleServer(TServer): """Simple single-threaded server that just pumps around one transport.""" def __init__(self, *args): TServer.__init__(self, *args) def serve(self): self.serverTransport.listen() while True: client = self.serverTransport.accept() if not client: continue itrans = self.inputTransportFactory.getTransport(client) iprot = self.inputProtocolFactory.getProtocol(itrans) # for THeaderProtocol, we must use the same protocol instance for # input and output so that the response is in the same dialect that # the server detected the request was in. if isinstance(self.inputProtocolFactory, THeaderProtocolFactory): otrans = None oprot = iprot else: otrans = self.outputTransportFactory.getTransport(client) oprot = self.outputProtocolFactory.getProtocol(otrans) try: while True: self.processor.process(iprot, oprot) except TTransport.TTransportException: pass except Exception as x: logger.exception(x) itrans.close() if otrans: otrans.close() class TThreadedServer(TServer): """Threaded server that spawns a new thread per each connection.""" def __init__(self, *args, **kwargs): TServer.__init__(self, *args) self.daemon = kwargs.get("daemon", False) def serve(self): self.serverTransport.listen() while True: try: client = self.serverTransport.accept() if not client: continue t = threading.Thread(target=self.handle, args=(client,)) t.setDaemon(self.daemon) t.start() except KeyboardInterrupt: raise except Exception as x: logger.exception(x) def handle(self, client): itrans = self.inputTransportFactory.getTransport(client) iprot = self.inputProtocolFactory.getProtocol(itrans) # for THeaderProtocol, we must use the same protocol instance for input # and output so that the response is in the same dialect that the # server detected the request was in. if isinstance(self.inputProtocolFactory, THeaderProtocolFactory): otrans = None oprot = iprot else: otrans = self.outputTransportFactory.getTransport(client) oprot = self.outputProtocolFactory.getProtocol(otrans) try: while True: self.processor.process(iprot, oprot) except TTransport.TTransportException: pass except Exception as x: logger.exception(x) itrans.close() if otrans: otrans.close() class TThreadPoolServer(TServer): """Server with a fixed size pool of threads which service requests.""" def __init__(self, *args, **kwargs): TServer.__init__(self, *args) self.clients = queue.Queue() self.threads = 10 self.daemon = kwargs.get("daemon", False) def setNumThreads(self, num): """Set the number of worker threads that should be created""" self.threads = num def serveThread(self): """Loop around getting clients from the shared queue and process them.""" while True: try: client = self.clients.get() self.serveClient(client) except Exception as x: logger.exception(x) def serveClient(self, client): """Process input/output from a client for as long as possible""" itrans = self.inputTransportFactory.getTransport(client) iprot = self.inputProtocolFactory.getProtocol(itrans) # for THeaderProtocol, we must use the same protocol instance for input # and output so that the response is in the same dialect that the # server detected the request was in. if isinstance(self.inputProtocolFactory, THeaderProtocolFactory): otrans = None oprot = iprot else: otrans = self.outputTransportFactory.getTransport(client) oprot = self.outputProtocolFactory.getProtocol(otrans) try: while True: self.processor.process(iprot, oprot) except TTransport.TTransportException: pass except Exception as x: logger.exception(x) itrans.close() if otrans: otrans.close() def serve(self): """Start a fixed number of worker threads and put client into a queue""" for i in range(self.threads): try: t = threading.Thread(target=self.serveThread) t.setDaemon(self.daemon) t.start() except Exception as x: logger.exception(x) # Pump the socket for clients self.serverTransport.listen() while True: try: client = self.serverTransport.accept() if not client: continue self.clients.put(client) except Exception as x: logger.exception(x) class TForkingServer(TServer): """A Thrift server that forks a new process for each request This is more scalable than the threaded server as it does not cause GIL contention. Note that this has different semantics from the threading server. Specifically, updates to shared variables will no longer be shared. It will also not work on windows. This code is heavily inspired by SocketServer.ForkingMixIn in the Python stdlib. """ def __init__(self, *args): TServer.__init__(self, *args) self.children = [] def serve(self): def try_close(file): try: file.close() except IOError as e: logger.warning(e, exc_info=True) self.serverTransport.listen() while True: client = self.serverTransport.accept() if not client: continue try: pid = os.fork() if pid: # parent # add before collect, otherwise you race w/ waitpid self.children.append(pid) self.collect_children() # Parent must close socket or the connection may not get # closed promptly itrans = self.inputTransportFactory.getTransport(client) otrans = self.outputTransportFactory.getTransport(client) try_close(itrans) try_close(otrans) else: itrans = self.inputTransportFactory.getTransport(client) iprot = self.inputProtocolFactory.getProtocol(itrans) # for THeaderProtocol, we must use the same protocol # instance for input and output so that the response is in # the same dialect that the server detected the request was # in. if isinstance(self.inputProtocolFactory, THeaderProtocolFactory): otrans = None oprot = iprot else: otrans = self.outputTransportFactory.getTransport(client) oprot = self.outputProtocolFactory.getProtocol(otrans) ecode = 0 try: try: while True: self.processor.process(iprot, oprot) except TTransport.TTransportException: pass except Exception as e: logger.exception(e) ecode = 1 finally: try_close(itrans) if otrans: try_close(otrans) os._exit(ecode) except TTransport.TTransportException: pass except Exception as x: logger.exception(x) def collect_children(self): while self.children: try: pid, status = os.waitpid(0, os.WNOHANG) except os.error: pid = None if pid: self.children.remove(pid) else: break thrift-0.16.0/lib/py/src/server/__init__.py000066400000000000000000000014761420101504100204760ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # __all__ = ['TServer', 'TNonblockingServer'] thrift-0.16.0/lib/py/src/transport/000077500000000000000000000000001420101504100171035ustar00rootroot00000000000000thrift-0.16.0/lib/py/src/transport/THeaderTransport.py000066400000000000000000000313261420101504100227130ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import struct import zlib from thrift.compat import BufferIO, byte_index from thrift.protocol.TBinaryProtocol import TBinaryProtocol from thrift.protocol.TCompactProtocol import TCompactProtocol, readVarint, writeVarint from thrift.Thrift import TApplicationException from thrift.transport.TTransport import ( CReadableTransport, TMemoryBuffer, TTransportBase, TTransportException, ) U16 = struct.Struct("!H") I32 = struct.Struct("!i") HEADER_MAGIC = 0x0FFF HARD_MAX_FRAME_SIZE = 0x3FFFFFFF class THeaderClientType(object): HEADERS = 0x00 FRAMED_BINARY = 0x01 UNFRAMED_BINARY = 0x02 FRAMED_COMPACT = 0x03 UNFRAMED_COMPACT = 0x04 class THeaderSubprotocolID(object): BINARY = 0x00 COMPACT = 0x02 class TInfoHeaderType(object): KEY_VALUE = 0x01 class THeaderTransformID(object): ZLIB = 0x01 READ_TRANSFORMS_BY_ID = { THeaderTransformID.ZLIB: zlib.decompress, } WRITE_TRANSFORMS_BY_ID = { THeaderTransformID.ZLIB: zlib.compress, } def _readString(trans): size = readVarint(trans) if size < 0: raise TTransportException( TTransportException.NEGATIVE_SIZE, "Negative length" ) return trans.read(size) def _writeString(trans, value): writeVarint(trans, len(value)) trans.write(value) class THeaderTransport(TTransportBase, CReadableTransport): def __init__(self, transport, allowed_client_types, default_protocol=THeaderSubprotocolID.BINARY): self._transport = transport self._client_type = THeaderClientType.HEADERS self._allowed_client_types = allowed_client_types self._read_buffer = BufferIO(b"") self._read_headers = {} self._write_buffer = BufferIO() self._write_headers = {} self._write_transforms = [] self.flags = 0 self.sequence_id = 0 self._protocol_id = default_protocol self._max_frame_size = HARD_MAX_FRAME_SIZE def isOpen(self): return self._transport.isOpen() def open(self): return self._transport.open() def close(self): return self._transport.close() def get_headers(self): return self._read_headers def set_header(self, key, value): if not isinstance(key, bytes): raise ValueError("header names must be bytes") if not isinstance(value, bytes): raise ValueError("header values must be bytes") self._write_headers[key] = value def clear_headers(self): self._write_headers.clear() def add_transform(self, transform_id): if transform_id not in WRITE_TRANSFORMS_BY_ID: raise ValueError("unknown transform") self._write_transforms.append(transform_id) def set_max_frame_size(self, size): if not 0 < size < HARD_MAX_FRAME_SIZE: raise ValueError("maximum frame size should be < %d and > 0" % HARD_MAX_FRAME_SIZE) self._max_frame_size = size @property def protocol_id(self): if self._client_type == THeaderClientType.HEADERS: return self._protocol_id elif self._client_type in (THeaderClientType.FRAMED_BINARY, THeaderClientType.UNFRAMED_BINARY): return THeaderSubprotocolID.BINARY elif self._client_type in (THeaderClientType.FRAMED_COMPACT, THeaderClientType.UNFRAMED_COMPACT): return THeaderSubprotocolID.COMPACT else: raise TTransportException( TTransportException.INVALID_CLIENT_TYPE, "Protocol ID not know for client type %d" % self._client_type, ) def read(self, sz): # if there are bytes left in the buffer, produce those first. bytes_read = self._read_buffer.read(sz) bytes_left_to_read = sz - len(bytes_read) if bytes_left_to_read == 0: return bytes_read # if we've determined this is an unframed client, just pass the read # through to the underlying transport until we're reset again at the # beginning of the next message. if self._client_type in (THeaderClientType.UNFRAMED_BINARY, THeaderClientType.UNFRAMED_COMPACT): return bytes_read + self._transport.read(bytes_left_to_read) # we're empty and (maybe) framed. fill the buffers with the next frame. self.readFrame(bytes_left_to_read) return bytes_read + self._read_buffer.read(bytes_left_to_read) def _set_client_type(self, client_type): if client_type not in self._allowed_client_types: raise TTransportException( TTransportException.INVALID_CLIENT_TYPE, "Client type %d not allowed by server." % client_type, ) self._client_type = client_type def readFrame(self, req_sz): # the first word could either be the length field of a framed message # or the first bytes of an unframed message. first_word = self._transport.readAll(I32.size) frame_size, = I32.unpack(first_word) is_unframed = False if frame_size & TBinaryProtocol.VERSION_MASK == TBinaryProtocol.VERSION_1: self._set_client_type(THeaderClientType.UNFRAMED_BINARY) is_unframed = True elif (byte_index(first_word, 0) == TCompactProtocol.PROTOCOL_ID and byte_index(first_word, 1) & TCompactProtocol.VERSION_MASK == TCompactProtocol.VERSION): self._set_client_type(THeaderClientType.UNFRAMED_COMPACT) is_unframed = True if is_unframed: bytes_left_to_read = req_sz - I32.size if bytes_left_to_read > 0: rest = self._transport.read(bytes_left_to_read) else: rest = b"" self._read_buffer = BufferIO(first_word + rest) return # ok, we're still here so we're framed. if frame_size > self._max_frame_size: raise TTransportException( TTransportException.SIZE_LIMIT, "Frame was too large.", ) read_buffer = BufferIO(self._transport.readAll(frame_size)) # the next word is either going to be the version field of a # binary/compact protocol message or the magic value + flags of a # header protocol message. second_word = read_buffer.read(I32.size) version, = I32.unpack(second_word) read_buffer.seek(0) if version >> 16 == HEADER_MAGIC: self._set_client_type(THeaderClientType.HEADERS) self._read_buffer = self._parse_header_format(read_buffer) elif version & TBinaryProtocol.VERSION_MASK == TBinaryProtocol.VERSION_1: self._set_client_type(THeaderClientType.FRAMED_BINARY) self._read_buffer = read_buffer elif (byte_index(second_word, 0) == TCompactProtocol.PROTOCOL_ID and byte_index(second_word, 1) & TCompactProtocol.VERSION_MASK == TCompactProtocol.VERSION): self._set_client_type(THeaderClientType.FRAMED_COMPACT) self._read_buffer = read_buffer else: raise TTransportException( TTransportException.INVALID_CLIENT_TYPE, "Could not detect client transport type.", ) def _parse_header_format(self, buffer): # make BufferIO look like TTransport for varint helpers buffer_transport = TMemoryBuffer() buffer_transport._buffer = buffer buffer.read(2) # discard the magic bytes self.flags, = U16.unpack(buffer.read(U16.size)) self.sequence_id, = I32.unpack(buffer.read(I32.size)) header_length = U16.unpack(buffer.read(U16.size))[0] * 4 end_of_headers = buffer.tell() + header_length if end_of_headers > len(buffer.getvalue()): raise TTransportException( TTransportException.SIZE_LIMIT, "Header size is larger than whole frame.", ) self._protocol_id = readVarint(buffer_transport) transforms = [] transform_count = readVarint(buffer_transport) for _ in range(transform_count): transform_id = readVarint(buffer_transport) if transform_id not in READ_TRANSFORMS_BY_ID: raise TApplicationException( TApplicationException.INVALID_TRANSFORM, "Unknown transform: %d" % transform_id, ) transforms.append(transform_id) transforms.reverse() headers = {} while buffer.tell() < end_of_headers: header_type = readVarint(buffer_transport) if header_type == TInfoHeaderType.KEY_VALUE: count = readVarint(buffer_transport) for _ in range(count): key = _readString(buffer_transport) value = _readString(buffer_transport) headers[key] = value else: break # ignore unknown headers self._read_headers = headers # skip padding / anything we didn't understand buffer.seek(end_of_headers) payload = buffer.read() for transform_id in transforms: transform_fn = READ_TRANSFORMS_BY_ID[transform_id] payload = transform_fn(payload) return BufferIO(payload) def write(self, buf): self._write_buffer.write(buf) def flush(self): payload = self._write_buffer.getvalue() self._write_buffer = BufferIO() buffer = BufferIO() if self._client_type == THeaderClientType.HEADERS: for transform_id in self._write_transforms: transform_fn = WRITE_TRANSFORMS_BY_ID[transform_id] payload = transform_fn(payload) headers = BufferIO() writeVarint(headers, self._protocol_id) writeVarint(headers, len(self._write_transforms)) for transform_id in self._write_transforms: writeVarint(headers, transform_id) if self._write_headers: writeVarint(headers, TInfoHeaderType.KEY_VALUE) writeVarint(headers, len(self._write_headers)) for key, value in self._write_headers.items(): _writeString(headers, key) _writeString(headers, value) self._write_headers = {} padding_needed = (4 - (len(headers.getvalue()) % 4)) % 4 headers.write(b"\x00" * padding_needed) header_bytes = headers.getvalue() buffer.write(I32.pack(10 + len(header_bytes) + len(payload))) buffer.write(U16.pack(HEADER_MAGIC)) buffer.write(U16.pack(self.flags)) buffer.write(I32.pack(self.sequence_id)) buffer.write(U16.pack(len(header_bytes) // 4)) buffer.write(header_bytes) buffer.write(payload) elif self._client_type in (THeaderClientType.FRAMED_BINARY, THeaderClientType.FRAMED_COMPACT): buffer.write(I32.pack(len(payload))) buffer.write(payload) elif self._client_type in (THeaderClientType.UNFRAMED_BINARY, THeaderClientType.UNFRAMED_COMPACT): buffer.write(payload) else: raise TTransportException( TTransportException.INVALID_CLIENT_TYPE, "Unknown client type.", ) # the frame length field doesn't count towards the frame payload size frame_bytes = buffer.getvalue() frame_payload_size = len(frame_bytes) - 4 if frame_payload_size > self._max_frame_size: raise TTransportException( TTransportException.SIZE_LIMIT, "Attempting to send frame that is too large.", ) self._transport.write(frame_bytes) self._transport.flush() @property def cstringio_buf(self): return self._read_buffer def cstringio_refill(self, partialread, reqlen): result = bytearray(partialread) while len(result) < reqlen: result += self.read(reqlen - len(result)) self._read_buffer = BufferIO(result) return self._read_buffer thrift-0.16.0/lib/py/src/transport/THttpClient.py000066400000000000000000000161631420101504100216660ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from io import BytesIO import os import ssl import sys import warnings import base64 from six.moves import urllib from six.moves import http_client from .TTransport import TTransportBase import six class THttpClient(TTransportBase): """Http implementation of TTransport base.""" def __init__(self, uri_or_host, port=None, path=None, cafile=None, cert_file=None, key_file=None, ssl_context=None): """THttpClient supports two different types of construction: THttpClient(host, port, path) - deprecated THttpClient(uri, [port=, path=, cafile=, cert_file=, key_file=, ssl_context=]) Only the second supports https. To properly authenticate against the server, provide the client's identity by specifying cert_file and key_file. To properly authenticate the server, specify either cafile or ssl_context with a CA defined. NOTE: if both cafile and ssl_context are defined, ssl_context will override cafile. """ if port is not None: warnings.warn( "Please use the THttpClient('http{s}://host:port/path') constructor", DeprecationWarning, stacklevel=2) self.host = uri_or_host self.port = port assert path self.path = path self.scheme = 'http' else: parsed = urllib.parse.urlparse(uri_or_host) self.scheme = parsed.scheme assert self.scheme in ('http', 'https') if self.scheme == 'http': self.port = parsed.port or http_client.HTTP_PORT elif self.scheme == 'https': self.port = parsed.port or http_client.HTTPS_PORT self.certfile = cert_file self.keyfile = key_file self.context = ssl.create_default_context(cafile=cafile) if (cafile and not ssl_context) else ssl_context self.host = parsed.hostname self.path = parsed.path if parsed.query: self.path += '?%s' % parsed.query try: proxy = urllib.request.getproxies()[self.scheme] except KeyError: proxy = None else: if urllib.request.proxy_bypass(self.host): proxy = None if proxy: parsed = urllib.parse.urlparse(proxy) self.realhost = self.host self.realport = self.port self.host = parsed.hostname self.port = parsed.port self.proxy_auth = self.basic_proxy_auth_header(parsed) else: self.realhost = self.realport = self.proxy_auth = None self.__wbuf = BytesIO() self.__http = None self.__http_response = None self.__timeout = None self.__custom_headers = None @staticmethod def basic_proxy_auth_header(proxy): if proxy is None or not proxy.username: return None ap = "%s:%s" % (urllib.parse.unquote(proxy.username), urllib.parse.unquote(proxy.password)) cr = base64.b64encode(ap).strip() return "Basic " + cr def using_proxy(self): return self.realhost is not None def open(self): if self.scheme == 'http': self.__http = http_client.HTTPConnection(self.host, self.port, timeout=self.__timeout) elif self.scheme == 'https': self.__http = http_client.HTTPSConnection(self.host, self.port, key_file=self.keyfile, cert_file=self.certfile, timeout=self.__timeout, context=self.context) if self.using_proxy(): self.__http.set_tunnel(self.realhost, self.realport, {"Proxy-Authorization": self.proxy_auth}) def close(self): self.__http.close() self.__http = None self.__http_response = None def isOpen(self): return self.__http is not None def setTimeout(self, ms): if ms is None: self.__timeout = None else: self.__timeout = ms / 1000.0 def setCustomHeaders(self, headers): self.__custom_headers = headers def read(self, sz): return self.__http_response.read(sz) def write(self, buf): self.__wbuf.write(buf) def flush(self): if self.isOpen(): self.close() self.open() # Pull data out of buffer data = self.__wbuf.getvalue() self.__wbuf = BytesIO() # HTTP request if self.using_proxy() and self.scheme == "http": # need full URL of real host for HTTP proxy here (HTTPS uses CONNECT tunnel) self.__http.putrequest('POST', "http://%s:%s%s" % (self.realhost, self.realport, self.path)) else: self.__http.putrequest('POST', self.path) # Write headers self.__http.putheader('Content-Type', 'application/x-thrift') self.__http.putheader('Content-Length', str(len(data))) if self.using_proxy() and self.scheme == "http" and self.proxy_auth is not None: self.__http.putheader("Proxy-Authorization", self.proxy_auth) if not self.__custom_headers or 'User-Agent' not in self.__custom_headers: user_agent = 'Python/THttpClient' script = os.path.basename(sys.argv[0]) if script: user_agent = '%s (%s)' % (user_agent, urllib.parse.quote(script)) self.__http.putheader('User-Agent', user_agent) if self.__custom_headers: for key, val in six.iteritems(self.__custom_headers): self.__http.putheader(key, val) self.__http.endheaders() # Write payload self.__http.send(data) # Get reply to flush the request self.__http_response = self.__http.getresponse() self.code = self.__http_response.status self.message = self.__http_response.reason self.headers = self.__http_response.msg # Saves the cookie sent by the server response if 'Set-Cookie' in self.headers: self.__http.putheader('Cookie', self.headers['Set-Cookie']) thrift-0.16.0/lib/py/src/transport/TSSLSocket.py000066400000000000000000000400051420101504100214120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import logging import os import socket import ssl import sys import warnings from .sslcompat import _match_hostname, _match_has_ipaddress from thrift.transport import TSocket from thrift.transport.TTransport import TTransportException logger = logging.getLogger(__name__) warnings.filterwarnings( 'default', category=DeprecationWarning, module=__name__) class TSSLBase(object): # SSLContext is not available for Python < 2.7.9 _has_ssl_context = sys.hexversion >= 0x020709F0 # ciphers argument is not available for Python < 2.7.0 _has_ciphers = sys.hexversion >= 0x020700F0 # For python >= 2.7.9, use latest TLS that both client and server # supports. # SSL 2.0 and 3.0 are disabled via ssl.OP_NO_SSLv2 and ssl.OP_NO_SSLv3. # For python < 2.7.9, use TLS 1.0 since TLSv1_X nor OP_NO_SSLvX is # unavailable. _default_protocol = ssl.PROTOCOL_SSLv23 if _has_ssl_context else \ ssl.PROTOCOL_TLSv1 def _init_context(self, ssl_version): if self._has_ssl_context: self._context = ssl.SSLContext(ssl_version) if self._context.protocol == ssl.PROTOCOL_SSLv23: self._context.options |= ssl.OP_NO_SSLv2 self._context.options |= ssl.OP_NO_SSLv3 else: self._context = None self._ssl_version = ssl_version @property def _should_verify(self): if self._has_ssl_context: return self._context.verify_mode != ssl.CERT_NONE else: return self.cert_reqs != ssl.CERT_NONE @property def ssl_version(self): if self._has_ssl_context: return self.ssl_context.protocol else: return self._ssl_version @property def ssl_context(self): return self._context SSL_VERSION = _default_protocol """ Default SSL version. For backwards compatibility, it can be modified. Use __init__ keyword argument "ssl_version" instead. """ def _deprecated_arg(self, args, kwargs, pos, key): if len(args) <= pos: return real_pos = pos + 3 warnings.warn( '%dth positional argument is deprecated.' 'please use keyword argument instead.' % real_pos, DeprecationWarning, stacklevel=3) if key in kwargs: raise TypeError( 'Duplicate argument: %dth argument and %s keyword argument.' % (real_pos, key)) kwargs[key] = args[pos] def _unix_socket_arg(self, host, port, args, kwargs): key = 'unix_socket' if host is None and port is None and len(args) == 1 and key not in kwargs: kwargs[key] = args[0] return True return False def __getattr__(self, key): if key == 'SSL_VERSION': warnings.warn( 'SSL_VERSION is deprecated.' 'please use ssl_version attribute instead.', DeprecationWarning, stacklevel=2) return self.ssl_version def __init__(self, server_side, host, ssl_opts): self._server_side = server_side if TSSLBase.SSL_VERSION != self._default_protocol: warnings.warn( 'SSL_VERSION is deprecated.' 'please use ssl_version keyword argument instead.', DeprecationWarning, stacklevel=2) self._context = ssl_opts.pop('ssl_context', None) self._server_hostname = None if not self._server_side: self._server_hostname = ssl_opts.pop('server_hostname', host) if self._context: self._custom_context = True if ssl_opts: raise ValueError( 'Incompatible arguments: ssl_context and %s' % ' '.join(ssl_opts.keys())) if not self._has_ssl_context: raise ValueError( 'ssl_context is not available for this version of Python') else: self._custom_context = False ssl_version = ssl_opts.pop('ssl_version', TSSLBase.SSL_VERSION) self._init_context(ssl_version) self.cert_reqs = ssl_opts.pop('cert_reqs', ssl.CERT_REQUIRED) self.ca_certs = ssl_opts.pop('ca_certs', None) self.keyfile = ssl_opts.pop('keyfile', None) self.certfile = ssl_opts.pop('certfile', None) self.ciphers = ssl_opts.pop('ciphers', None) if ssl_opts: raise ValueError( 'Unknown keyword arguments: ', ' '.join(ssl_opts.keys())) if self._should_verify: if not self.ca_certs: raise ValueError( 'ca_certs is needed when cert_reqs is not ssl.CERT_NONE') if not os.access(self.ca_certs, os.R_OK): raise IOError('Certificate Authority ca_certs file "%s" ' 'is not readable, cannot validate SSL ' 'certificates.' % (self.ca_certs)) @property def certfile(self): return self._certfile @certfile.setter def certfile(self, certfile): if self._server_side and not certfile: raise ValueError('certfile is needed for server-side') if certfile and not os.access(certfile, os.R_OK): raise IOError('No such certfile found: %s' % (certfile)) self._certfile = certfile def _wrap_socket(self, sock): if self._has_ssl_context: if not self._custom_context: self.ssl_context.verify_mode = self.cert_reqs if self.certfile: self.ssl_context.load_cert_chain(self.certfile, self.keyfile) if self.ciphers: self.ssl_context.set_ciphers(self.ciphers) if self.ca_certs: self.ssl_context.load_verify_locations(self.ca_certs) return self.ssl_context.wrap_socket( sock, server_side=self._server_side, server_hostname=self._server_hostname) else: ssl_opts = { 'ssl_version': self._ssl_version, 'server_side': self._server_side, 'ca_certs': self.ca_certs, 'keyfile': self.keyfile, 'certfile': self.certfile, 'cert_reqs': self.cert_reqs, } if self.ciphers: if self._has_ciphers: ssl_opts['ciphers'] = self.ciphers else: logger.warning( 'ciphers is specified but ignored due to old Python version') return ssl.wrap_socket(sock, **ssl_opts) class TSSLSocket(TSocket.TSocket, TSSLBase): """ SSL implementation of TSocket This class creates outbound sockets wrapped using the python standard ssl module for encrypted connections. """ # New signature # def __init__(self, host='localhost', port=9090, unix_socket=None, # **ssl_args): # Deprecated signature # def __init__(self, host='localhost', port=9090, validate=True, # ca_certs=None, keyfile=None, certfile=None, # unix_socket=None, ciphers=None): def __init__(self, host='localhost', port=9090, *args, **kwargs): """Positional arguments: ``host``, ``port``, ``unix_socket`` Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, ``ssl_version``, ``ca_certs``, ``ciphers`` (Python 2.7.0 or later), ``server_hostname`` (Python 2.7.9 or later) Passed to ssl.wrap_socket. See ssl.wrap_socket documentation. Alternative keyword arguments: (Python 2.7.9 or later) ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket ``server_hostname``: Passed to SSLContext.wrap_socket Common keyword argument: ``validate_callback`` (cert, hostname) -> None: Called after SSL handshake. Can raise when hostname does not match the cert. ``socket_keepalive`` enable TCP keepalive, default off. """ self.is_valid = False self.peercert = None if args: if len(args) > 6: raise TypeError('Too many positional argument') if not self._unix_socket_arg(host, port, args, kwargs): self._deprecated_arg(args, kwargs, 0, 'validate') self._deprecated_arg(args, kwargs, 1, 'ca_certs') self._deprecated_arg(args, kwargs, 2, 'keyfile') self._deprecated_arg(args, kwargs, 3, 'certfile') self._deprecated_arg(args, kwargs, 4, 'unix_socket') self._deprecated_arg(args, kwargs, 5, 'ciphers') validate = kwargs.pop('validate', None) if validate is not None: cert_reqs_name = 'CERT_REQUIRED' if validate else 'CERT_NONE' warnings.warn( 'validate is deprecated. please use cert_reqs=ssl.%s instead' % cert_reqs_name, DeprecationWarning, stacklevel=2) if 'cert_reqs' in kwargs: raise TypeError('Cannot specify both validate and cert_reqs') kwargs['cert_reqs'] = ssl.CERT_REQUIRED if validate else ssl.CERT_NONE unix_socket = kwargs.pop('unix_socket', None) socket_keepalive = kwargs.pop('socket_keepalive', False) self._validate_callback = kwargs.pop('validate_callback', _match_hostname) TSSLBase.__init__(self, False, host, kwargs) TSocket.TSocket.__init__(self, host, port, unix_socket, socket_keepalive=socket_keepalive) def close(self): try: self.handle.settimeout(0.001) self.handle = self.handle.unwrap() except (ssl.SSLError, socket.error, OSError): # could not complete shutdown in a reasonable amount of time. bail. pass TSocket.TSocket.close(self) @property def validate(self): warnings.warn('validate is deprecated. please use cert_reqs instead', DeprecationWarning, stacklevel=2) return self.cert_reqs != ssl.CERT_NONE @validate.setter def validate(self, value): warnings.warn('validate is deprecated. please use cert_reqs instead', DeprecationWarning, stacklevel=2) self.cert_reqs = ssl.CERT_REQUIRED if value else ssl.CERT_NONE def _do_open(self, family, socktype): plain_sock = socket.socket(family, socktype) try: return self._wrap_socket(plain_sock) except Exception as ex: plain_sock.close() msg = 'failed to initialize SSL' logger.exception(msg) raise TTransportException(type=TTransportException.NOT_OPEN, message=msg, inner=ex) def open(self): super(TSSLSocket, self).open() if self._should_verify: self.peercert = self.handle.getpeercert() try: self._validate_callback(self.peercert, self._server_hostname) self.is_valid = True except TTransportException: raise except Exception as ex: raise TTransportException(message=str(ex), inner=ex) class TSSLServerSocket(TSocket.TServerSocket, TSSLBase): """SSL implementation of TServerSocket This uses the ssl module's wrap_socket() method to provide SSL negotiated encryption. """ # New signature # def __init__(self, host='localhost', port=9090, unix_socket=None, **ssl_args): # Deprecated signature # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None): def __init__(self, host=None, port=9090, *args, **kwargs): """Positional arguments: ``host``, ``port``, ``unix_socket`` Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, ``ssl_version``, ``ca_certs``, ``ciphers`` (Python 2.7.0 or later) See ssl.wrap_socket documentation. Alternative keyword arguments: (Python 2.7.9 or later) ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket ``server_hostname``: Passed to SSLContext.wrap_socket Common keyword argument: ``validate_callback`` (cert, hostname) -> None: Called after SSL handshake. Can raise when hostname does not match the cert. """ if args: if len(args) > 3: raise TypeError('Too many positional argument') if not self._unix_socket_arg(host, port, args, kwargs): self._deprecated_arg(args, kwargs, 0, 'certfile') self._deprecated_arg(args, kwargs, 1, 'unix_socket') self._deprecated_arg(args, kwargs, 2, 'ciphers') if 'ssl_context' not in kwargs: # Preserve existing behaviors for default values if 'cert_reqs' not in kwargs: kwargs['cert_reqs'] = ssl.CERT_NONE if'certfile' not in kwargs: kwargs['certfile'] = 'cert.pem' unix_socket = kwargs.pop('unix_socket', None) self._validate_callback = \ kwargs.pop('validate_callback', _match_hostname) TSSLBase.__init__(self, True, None, kwargs) TSocket.TServerSocket.__init__(self, host, port, unix_socket) if self._should_verify and not _match_has_ipaddress: raise ValueError('Need ipaddress and backports.ssl_match_hostname ' 'module to verify client certificate') def setCertfile(self, certfile): """Set or change the server certificate file used to wrap new connections. @param certfile: The filename of the server certificate, i.e. '/etc/certs/server.pem' @type certfile: str Raises an IOError exception if the certfile is not present or unreadable. """ warnings.warn( 'setCertfile is deprecated. please use certfile property instead.', DeprecationWarning, stacklevel=2) self.certfile = certfile def accept(self): plain_client, addr = self.handle.accept() try: client = self._wrap_socket(plain_client) except (ssl.SSLError, socket.error, OSError): logger.exception('Error while accepting from %s', addr) # failed handshake/ssl wrap, close socket to client plain_client.close() # raise # We can't raise the exception, because it kills most TServer derived # serve() methods. # Instead, return None, and let the TServer instance deal with it in # other exception handling. (but TSimpleServer dies anyway) return None if self._should_verify: client.peercert = client.getpeercert() try: self._validate_callback(client.peercert, addr[0]) client.is_valid = True except Exception: logger.warn('Failed to validate client certificate address: %s', addr[0], exc_info=True) client.close() plain_client.close() return None result = TSocket.TSocket() result.handle = client return result thrift-0.16.0/lib/py/src/transport/TSocket.py000066400000000000000000000216431420101504100210370ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import errno import logging import os import socket import sys from .TTransport import TTransportBase, TTransportException, TServerTransportBase logger = logging.getLogger(__name__) class TSocketBase(TTransportBase): def _resolveAddr(self): if self._unix_socket is not None: return [(socket.AF_UNIX, socket.SOCK_STREAM, None, None, self._unix_socket)] else: return socket.getaddrinfo(self.host, self.port, self._socket_family, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) def close(self): if self.handle: self.handle.close() self.handle = None class TSocket(TSocketBase): """Socket implementation of TTransport base.""" def __init__(self, host='localhost', port=9090, unix_socket=None, socket_family=socket.AF_UNSPEC, socket_keepalive=False): """Initialize a TSocket @param host(str) The host to connect to. @param port(int) The (TCP) port to connect to. @param unix_socket(str) The filename of a unix socket to connect to. (host and port will be ignored.) @param socket_family(int) The socket family to use with this socket. @param socket_keepalive(bool) enable TCP keepalive, default off. """ self.host = host self.port = port self.handle = None self._unix_socket = unix_socket self._timeout = None self._socket_family = socket_family self._socket_keepalive = socket_keepalive def setHandle(self, h): self.handle = h def isOpen(self): if self.handle is None: return False # this lets us cheaply see if the other end of the socket is still # connected. if disconnected, we'll get EOF back (expressed as zero # bytes of data) otherwise we'll get one byte or an error indicating # we'd have to block for data. # # note that we're not doing this with socket.MSG_DONTWAIT because 1) # it's linux-specific and 2) gevent-patched sockets hide EAGAIN from us # when timeout is non-zero. original_timeout = self.handle.gettimeout() try: self.handle.settimeout(0) try: peeked_bytes = self.handle.recv(1, socket.MSG_PEEK) except (socket.error, OSError) as exc: # on modern python this is just BlockingIOError if exc.errno in (errno.EWOULDBLOCK, errno.EAGAIN): return True return False finally: self.handle.settimeout(original_timeout) # the length will be zero if we got EOF (indicating connection closed) return len(peeked_bytes) == 1 def setTimeout(self, ms): if ms is None: self._timeout = None else: self._timeout = ms / 1000.0 if self.handle is not None: self.handle.settimeout(self._timeout) def _do_open(self, family, socktype): return socket.socket(family, socktype) @property def _address(self): return self._unix_socket if self._unix_socket else '%s:%d' % (self.host, self.port) def open(self): if self.handle: raise TTransportException(type=TTransportException.ALREADY_OPEN, message="already open") try: addrs = self._resolveAddr() except socket.gaierror as gai: msg = 'failed to resolve sockaddr for ' + str(self._address) logger.exception(msg) raise TTransportException(type=TTransportException.NOT_OPEN, message=msg, inner=gai) for family, socktype, _, _, sockaddr in addrs: handle = self._do_open(family, socktype) # TCP_KEEPALIVE if self._socket_keepalive: handle.setsockopt(socket.IPPROTO_TCP, socket.SO_KEEPALIVE, 1) handle.settimeout(self._timeout) try: handle.connect(sockaddr) self.handle = handle return except socket.error: handle.close() logger.info('Could not connect to %s', sockaddr, exc_info=True) msg = 'Could not connect to any of %s' % list(map(lambda a: a[4], addrs)) logger.error(msg) raise TTransportException(type=TTransportException.NOT_OPEN, message=msg) def read(self, sz): try: buff = self.handle.recv(sz) except socket.error as e: if (e.args[0] == errno.ECONNRESET and (sys.platform == 'darwin' or sys.platform.startswith('freebsd'))): # freebsd and Mach don't follow POSIX semantic of recv # and fail with ECONNRESET if peer performed shutdown. # See corresponding comment and code in TSocket::read() # in lib/cpp/src/transport/TSocket.cpp. self.close() # Trigger the check to raise the END_OF_FILE exception below. buff = '' elif e.args[0] == errno.ETIMEDOUT: raise TTransportException(type=TTransportException.TIMED_OUT, message="read timeout", inner=e) else: raise TTransportException(message="unexpected exception", inner=e) if len(buff) == 0: raise TTransportException(type=TTransportException.END_OF_FILE, message='TSocket read 0 bytes') return buff def write(self, buff): if not self.handle: raise TTransportException(type=TTransportException.NOT_OPEN, message='Transport not open') sent = 0 have = len(buff) while sent < have: try: plus = self.handle.send(buff) if plus == 0: raise TTransportException(type=TTransportException.END_OF_FILE, message='TSocket sent 0 bytes') sent += plus buff = buff[plus:] except socket.error as e: raise TTransportException(message="unexpected exception", inner=e) def flush(self): pass class TServerSocket(TSocketBase, TServerTransportBase): """Socket implementation of TServerTransport base.""" def __init__(self, host=None, port=9090, unix_socket=None, socket_family=socket.AF_UNSPEC): self.host = host self.port = port self._unix_socket = unix_socket self._socket_family = socket_family self.handle = None self._backlog = 128 def setBacklog(self, backlog=None): if not self.handle: self._backlog = backlog else: # We cann't update backlog when it is already listening, since the # handle has been created. logger.warn('You have to set backlog before listen.') def listen(self): res0 = self._resolveAddr() socket_family = self._socket_family == socket.AF_UNSPEC and socket.AF_INET6 or self._socket_family for res in res0: if res[0] is socket_family or res is res0[-1]: break # We need remove the old unix socket if the file exists and # nobody is listening on it. if self._unix_socket: tmp = socket.socket(res[0], res[1]) try: tmp.connect(res[4]) except socket.error as err: eno, message = err.args if eno == errno.ECONNREFUSED: os.unlink(res[4]) self.handle = socket.socket(res[0], res[1]) self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if hasattr(self.handle, 'settimeout'): self.handle.settimeout(None) self.handle.bind(res[4]) self.handle.listen(self._backlog) def accept(self): client, addr = self.handle.accept() result = TSocket() result.setHandle(client) return result thrift-0.16.0/lib/py/src/transport/TTransport.py000066400000000000000000000317231420101504100216030ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from struct import pack, unpack from thrift.Thrift import TException from ..compat import BufferIO class TTransportException(TException): """Custom Transport Exception class""" UNKNOWN = 0 NOT_OPEN = 1 ALREADY_OPEN = 2 TIMED_OUT = 3 END_OF_FILE = 4 NEGATIVE_SIZE = 5 SIZE_LIMIT = 6 INVALID_CLIENT_TYPE = 7 def __init__(self, type=UNKNOWN, message=None, inner=None): TException.__init__(self, message) self.type = type self.inner = inner class TTransportBase(object): """Base class for Thrift transport layer.""" def isOpen(self): pass def open(self): pass def close(self): pass def read(self, sz): pass def readAll(self, sz): buff = b'' have = 0 while (have < sz): chunk = self.read(sz - have) chunkLen = len(chunk) have += chunkLen buff += chunk if chunkLen == 0: raise EOFError() return buff def write(self, buf): pass def flush(self): pass # This class should be thought of as an interface. class CReadableTransport(object): """base class for transports that are readable from C""" # TODO(dreiss): Think about changing this interface to allow us to use # a (Python, not c) StringIO instead, because it allows # you to write after reading. # NOTE: This is a classic class, so properties will NOT work # correctly for setting. @property def cstringio_buf(self): """A cStringIO buffer that contains the current chunk we are reading.""" pass def cstringio_refill(self, partialread, reqlen): """Refills cstringio_buf. Returns the currently used buffer (which can but need not be the same as the old cstringio_buf). partialread is what the C code has read from the buffer, and should be inserted into the buffer before any more reads. The return value must be a new, not borrowed reference. Something along the lines of self._buf should be fine. If reqlen bytes can't be read, throw EOFError. """ pass class TServerTransportBase(object): """Base class for Thrift server transports.""" def listen(self): pass def accept(self): pass def close(self): pass class TTransportFactoryBase(object): """Base class for a Transport Factory""" def getTransport(self, trans): return trans class TBufferedTransportFactory(object): """Factory transport that builds buffered transports""" def getTransport(self, trans): buffered = TBufferedTransport(trans) return buffered class TBufferedTransport(TTransportBase, CReadableTransport): """Class that wraps another transport and buffers its I/O. The implementation uses a (configurable) fixed-size read buffer but buffers all writes until a flush is performed. """ DEFAULT_BUFFER = 4096 def __init__(self, trans, rbuf_size=DEFAULT_BUFFER): self.__trans = trans self.__wbuf = BufferIO() # Pass string argument to initialize read buffer as cStringIO.InputType self.__rbuf = BufferIO(b'') self.__rbuf_size = rbuf_size def isOpen(self): return self.__trans.isOpen() def open(self): return self.__trans.open() def close(self): return self.__trans.close() def read(self, sz): ret = self.__rbuf.read(sz) if len(ret) != 0: return ret self.__rbuf = BufferIO(self.__trans.read(max(sz, self.__rbuf_size))) return self.__rbuf.read(sz) def write(self, buf): try: self.__wbuf.write(buf) except Exception as e: # on exception reset wbuf so it doesn't contain a partial function call self.__wbuf = BufferIO() raise e def flush(self): out = self.__wbuf.getvalue() # reset wbuf before write/flush to preserve state on underlying failure self.__wbuf = BufferIO() self.__trans.write(out) self.__trans.flush() # Implement the CReadableTransport interface. @property def cstringio_buf(self): return self.__rbuf def cstringio_refill(self, partialread, reqlen): retstring = partialread if reqlen < self.__rbuf_size: # try to make a read of as much as we can. retstring += self.__trans.read(self.__rbuf_size) # but make sure we do read reqlen bytes. if len(retstring) < reqlen: retstring += self.__trans.readAll(reqlen - len(retstring)) self.__rbuf = BufferIO(retstring) return self.__rbuf class TMemoryBuffer(TTransportBase, CReadableTransport): """Wraps a cBytesIO object as a TTransport. NOTE: Unlike the C++ version of this class, you cannot write to it then immediately read from it. If you want to read from a TMemoryBuffer, you must either pass a string to the constructor. TODO(dreiss): Make this work like the C++ version. """ def __init__(self, value=None, offset=0): """value -- a value to read from for stringio If value is set, this will be a transport for reading, otherwise, it is for writing""" if value is not None: self._buffer = BufferIO(value) else: self._buffer = BufferIO() if offset: self._buffer.seek(offset) def isOpen(self): return not self._buffer.closed def open(self): pass def close(self): self._buffer.close() def read(self, sz): return self._buffer.read(sz) def write(self, buf): self._buffer.write(buf) def flush(self): pass def getvalue(self): return self._buffer.getvalue() # Implement the CReadableTransport interface. @property def cstringio_buf(self): return self._buffer def cstringio_refill(self, partialread, reqlen): # only one shot at reading... raise EOFError() class TFramedTransportFactory(object): """Factory transport that builds framed transports""" def getTransport(self, trans): framed = TFramedTransport(trans) return framed class TFramedTransport(TTransportBase, CReadableTransport): """Class that wraps another transport and frames its I/O when writing.""" def __init__(self, trans,): self.__trans = trans self.__rbuf = BufferIO(b'') self.__wbuf = BufferIO() def isOpen(self): return self.__trans.isOpen() def open(self): return self.__trans.open() def close(self): return self.__trans.close() def read(self, sz): ret = self.__rbuf.read(sz) if len(ret) != 0: return ret self.readFrame() return self.__rbuf.read(sz) def readFrame(self): buff = self.__trans.readAll(4) sz, = unpack('!i', buff) self.__rbuf = BufferIO(self.__trans.readAll(sz)) def write(self, buf): self.__wbuf.write(buf) def flush(self): wout = self.__wbuf.getvalue() wsz = len(wout) # reset wbuf before write/flush to preserve state on underlying failure self.__wbuf = BufferIO() # N.B.: Doing this string concatenation is WAY cheaper than making # two separate calls to the underlying socket object. Socket writes in # Python turn out to be REALLY expensive, but it seems to do a pretty # good job of managing string buffer operations without excessive copies buf = pack("!i", wsz) + wout self.__trans.write(buf) self.__trans.flush() # Implement the CReadableTransport interface. @property def cstringio_buf(self): return self.__rbuf def cstringio_refill(self, prefix, reqlen): # self.__rbuf will already be empty here because fastbinary doesn't # ask for a refill until the previous buffer is empty. Therefore, # we can start reading new frames immediately. while len(prefix) < reqlen: self.readFrame() prefix += self.__rbuf.getvalue() self.__rbuf = BufferIO(prefix) return self.__rbuf class TFileObjectTransport(TTransportBase): """Wraps a file-like object to make it work as a Thrift transport.""" def __init__(self, fileobj): self.fileobj = fileobj def isOpen(self): return True def close(self): self.fileobj.close() def read(self, sz): return self.fileobj.read(sz) def write(self, buf): self.fileobj.write(buf) def flush(self): self.fileobj.flush() class TSaslClientTransport(TTransportBase, CReadableTransport): """ SASL transport """ START = 1 OK = 2 BAD = 3 ERROR = 4 COMPLETE = 5 def __init__(self, transport, host, service, mechanism='GSSAPI', **sasl_kwargs): """ transport: an underlying transport to use, typically just a TSocket host: the name of the server, from a SASL perspective service: the name of the server's service, from a SASL perspective mechanism: the name of the preferred mechanism to use All other kwargs will be passed to the puresasl.client.SASLClient constructor. """ from puresasl.client import SASLClient self.transport = transport self.sasl = SASLClient(host, service, mechanism, **sasl_kwargs) self.__wbuf = BufferIO() self.__rbuf = BufferIO(b'') def open(self): if not self.transport.isOpen(): self.transport.open() self.send_sasl_msg(self.START, bytes(self.sasl.mechanism, 'ascii')) self.send_sasl_msg(self.OK, self.sasl.process()) while True: status, challenge = self.recv_sasl_msg() if status == self.OK: self.send_sasl_msg(self.OK, self.sasl.process(challenge)) elif status == self.COMPLETE: if not self.sasl.complete: raise TTransportException( TTransportException.NOT_OPEN, "The server erroneously indicated " "that SASL negotiation was complete") else: break else: raise TTransportException( TTransportException.NOT_OPEN, "Bad SASL negotiation status: %d (%s)" % (status, challenge)) def isOpen(self): return self.transport.isOpen() def send_sasl_msg(self, status, body): header = pack(">BI", status, len(body)) self.transport.write(header + body) self.transport.flush() def recv_sasl_msg(self): header = self.transport.readAll(5) status, length = unpack(">BI", header) if length > 0: payload = self.transport.readAll(length) else: payload = "" return status, payload def write(self, data): self.__wbuf.write(data) def flush(self): data = self.__wbuf.getvalue() encoded = self.sasl.wrap(data) self.transport.write(pack("!i", len(encoded)) + encoded) self.transport.flush() self.__wbuf = BufferIO() def read(self, sz): ret = self.__rbuf.read(sz) if len(ret) != 0: return ret self._read_frame() return self.__rbuf.read(sz) def _read_frame(self): header = self.transport.readAll(4) length, = unpack('!i', header) encoded = self.transport.readAll(length) self.__rbuf = BufferIO(self.sasl.unwrap(encoded)) def close(self): self.sasl.dispose() self.transport.close() # based on TFramedTransport @property def cstringio_buf(self): return self.__rbuf def cstringio_refill(self, prefix, reqlen): # self.__rbuf will already be empty here because fastbinary doesn't # ask for a refill until the previous buffer is empty. Therefore, # we can start reading new frames immediately. while len(prefix) < reqlen: self._read_frame() prefix += self.__rbuf.getvalue() self.__rbuf = BufferIO(prefix) return self.__rbuf thrift-0.16.0/lib/py/src/transport/TTwisted.py000066400000000000000000000252301420101504100212260ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from io import BytesIO import struct from zope.interface import implementer, Interface, Attribute from twisted.internet.protocol import ServerFactory, ClientFactory, \ connectionDone from twisted.internet import defer from twisted.internet.threads import deferToThread from twisted.protocols import basic from twisted.web import server, resource, http from thrift.transport import TTransport class TMessageSenderTransport(TTransport.TTransportBase): def __init__(self): self.__wbuf = BytesIO() def write(self, buf): self.__wbuf.write(buf) def flush(self): msg = self.__wbuf.getvalue() self.__wbuf = BytesIO() return self.sendMessage(msg) def sendMessage(self, message): raise NotImplementedError class TCallbackTransport(TMessageSenderTransport): def __init__(self, func): TMessageSenderTransport.__init__(self) self.func = func def sendMessage(self, message): return self.func(message) class ThriftClientProtocol(basic.Int32StringReceiver): MAX_LENGTH = 2 ** 31 - 1 def __init__(self, client_class, iprot_factory, oprot_factory=None): self._client_class = client_class self._iprot_factory = iprot_factory if oprot_factory is None: self._oprot_factory = iprot_factory else: self._oprot_factory = oprot_factory self.recv_map = {} self.started = defer.Deferred() def dispatch(self, msg): self.sendString(msg) def connectionMade(self): tmo = TCallbackTransport(self.dispatch) self.client = self._client_class(tmo, self._oprot_factory) self.started.callback(self.client) def connectionLost(self, reason=connectionDone): # the called errbacks can add items to our client's _reqs, # so we need to use a tmp, and iterate until no more requests # are added during errbacks if self.client: tex = TTransport.TTransportException( type=TTransport.TTransportException.END_OF_FILE, message='Connection closed (%s)' % reason) while self.client._reqs: _, v = self.client._reqs.popitem() v.errback(tex) del self.client._reqs self.client = None def stringReceived(self, frame): tr = TTransport.TMemoryBuffer(frame) iprot = self._iprot_factory.getProtocol(tr) (fname, mtype, rseqid) = iprot.readMessageBegin() try: method = self.recv_map[fname] except KeyError: method = getattr(self.client, 'recv_' + fname) self.recv_map[fname] = method method(iprot, mtype, rseqid) class ThriftSASLClientProtocol(ThriftClientProtocol): START = 1 OK = 2 BAD = 3 ERROR = 4 COMPLETE = 5 MAX_LENGTH = 2 ** 31 - 1 def __init__(self, client_class, iprot_factory, oprot_factory=None, host=None, service=None, mechanism='GSSAPI', **sasl_kwargs): """ host: the name of the server, from a SASL perspective service: the name of the server's service, from a SASL perspective mechanism: the name of the preferred mechanism to use All other kwargs will be passed to the puresasl.client.SASLClient constructor. """ from puresasl.client import SASLClient self.SASLCLient = SASLClient ThriftClientProtocol.__init__(self, client_class, iprot_factory, oprot_factory) self._sasl_negotiation_deferred = None self._sasl_negotiation_status = None self.client = None if host is not None: self.createSASLClient(host, service, mechanism, **sasl_kwargs) def createSASLClient(self, host, service, mechanism, **kwargs): self.sasl = self.SASLClient(host, service, mechanism, **kwargs) def dispatch(self, msg): encoded = self.sasl.wrap(msg) len_and_encoded = ''.join((struct.pack('!i', len(encoded)), encoded)) ThriftClientProtocol.dispatch(self, len_and_encoded) @defer.inlineCallbacks def connectionMade(self): self._sendSASLMessage(self.START, self.sasl.mechanism) initial_message = yield deferToThread(self.sasl.process) self._sendSASLMessage(self.OK, initial_message) while True: status, challenge = yield self._receiveSASLMessage() if status == self.OK: response = yield deferToThread(self.sasl.process, challenge) self._sendSASLMessage(self.OK, response) elif status == self.COMPLETE: if not self.sasl.complete: msg = "The server erroneously indicated that SASL " \ "negotiation was complete" raise TTransport.TTransportException(msg, message=msg) else: break else: msg = "Bad SASL negotiation status: %d (%s)" % (status, challenge) raise TTransport.TTransportException(msg, message=msg) self._sasl_negotiation_deferred = None ThriftClientProtocol.connectionMade(self) def _sendSASLMessage(self, status, body): if body is None: body = "" header = struct.pack(">BI", status, len(body)) self.transport.write(header + body) def _receiveSASLMessage(self): self._sasl_negotiation_deferred = defer.Deferred() self._sasl_negotiation_status = None return self._sasl_negotiation_deferred def connectionLost(self, reason=connectionDone): if self.client: ThriftClientProtocol.connectionLost(self, reason) def dataReceived(self, data): if self._sasl_negotiation_deferred: # we got a sasl challenge in the format (status, length, challenge) # save the status, let IntNStringReceiver piece the challenge data together self._sasl_negotiation_status, = struct.unpack("B", data[0]) ThriftClientProtocol.dataReceived(self, data[1:]) else: # normal frame, let IntNStringReceiver piece it together ThriftClientProtocol.dataReceived(self, data) def stringReceived(self, frame): if self._sasl_negotiation_deferred: # the frame is just a SASL challenge response = (self._sasl_negotiation_status, frame) self._sasl_negotiation_deferred.callback(response) else: # there's a second 4 byte length prefix inside the frame decoded_frame = self.sasl.unwrap(frame[4:]) ThriftClientProtocol.stringReceived(self, decoded_frame) class ThriftServerProtocol(basic.Int32StringReceiver): MAX_LENGTH = 2 ** 31 - 1 def dispatch(self, msg): self.sendString(msg) def processError(self, error): self.transport.loseConnection() def processOk(self, _, tmo): msg = tmo.getvalue() if len(msg) > 0: self.dispatch(msg) def stringReceived(self, frame): tmi = TTransport.TMemoryBuffer(frame) tmo = TTransport.TMemoryBuffer() iprot = self.factory.iprot_factory.getProtocol(tmi) oprot = self.factory.oprot_factory.getProtocol(tmo) d = self.factory.processor.process(iprot, oprot) d.addCallbacks(self.processOk, self.processError, callbackArgs=(tmo,)) class IThriftServerFactory(Interface): processor = Attribute("Thrift processor") iprot_factory = Attribute("Input protocol factory") oprot_factory = Attribute("Output protocol factory") class IThriftClientFactory(Interface): client_class = Attribute("Thrift client class") iprot_factory = Attribute("Input protocol factory") oprot_factory = Attribute("Output protocol factory") @implementer(IThriftServerFactory) class ThriftServerFactory(ServerFactory): protocol = ThriftServerProtocol def __init__(self, processor, iprot_factory, oprot_factory=None): self.processor = processor self.iprot_factory = iprot_factory if oprot_factory is None: self.oprot_factory = iprot_factory else: self.oprot_factory = oprot_factory @implementer(IThriftClientFactory) class ThriftClientFactory(ClientFactory): protocol = ThriftClientProtocol def __init__(self, client_class, iprot_factory, oprot_factory=None): self.client_class = client_class self.iprot_factory = iprot_factory if oprot_factory is None: self.oprot_factory = iprot_factory else: self.oprot_factory = oprot_factory def buildProtocol(self, addr): p = self.protocol(self.client_class, self.iprot_factory, self.oprot_factory) p.factory = self return p class ThriftResource(resource.Resource): allowedMethods = ('POST',) def __init__(self, processor, inputProtocolFactory, outputProtocolFactory=None): resource.Resource.__init__(self) self.inputProtocolFactory = inputProtocolFactory if outputProtocolFactory is None: self.outputProtocolFactory = inputProtocolFactory else: self.outputProtocolFactory = outputProtocolFactory self.processor = processor def getChild(self, path, request): return self def _cbProcess(self, _, request, tmo): msg = tmo.getvalue() request.setResponseCode(http.OK) request.setHeader("content-type", "application/x-thrift") request.write(msg) request.finish() def render_POST(self, request): request.content.seek(0, 0) data = request.content.read() tmi = TTransport.TMemoryBuffer(data) tmo = TTransport.TMemoryBuffer() iprot = self.inputProtocolFactory.getProtocol(tmi) oprot = self.outputProtocolFactory.getProtocol(tmo) d = self.processor.process(iprot, oprot) d.addCallback(self._cbProcess, request, tmo) return server.NOT_DONE_YET thrift-0.16.0/lib/py/src/transport/TZlibTransport.py000066400000000000000000000211121420101504100224130ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # """TZlibTransport provides a compressed transport and transport factory class, using the python standard library zlib module to implement data compression. """ from __future__ import division import zlib from .TTransport import TTransportBase, CReadableTransport from ..compat import BufferIO class TZlibTransportFactory(object): """Factory transport that builds zlib compressed transports. This factory caches the last single client/transport that it was passed and returns the same TZlibTransport object that was created. This caching means the TServer class will get the _same_ transport object for both input and output transports from this factory. (For non-threaded scenarios only, since the cache only holds one object) The purpose of this caching is to allocate only one TZlibTransport where only one is really needed (since it must have separate read/write buffers), and makes the statistics from getCompSavings() and getCompRatio() easier to understand. """ # class scoped cache of last transport given and zlibtransport returned _last_trans = None _last_z = None def getTransport(self, trans, compresslevel=9): """Wrap a transport, trans, with the TZlibTransport compressed transport class, returning a new transport to the caller. @param compresslevel: The zlib compression level, ranging from 0 (no compression) to 9 (best compression). Defaults to 9. @type compresslevel: int This method returns a TZlibTransport which wraps the passed C{trans} TTransport derived instance. """ if trans == self._last_trans: return self._last_z ztrans = TZlibTransport(trans, compresslevel) self._last_trans = trans self._last_z = ztrans return ztrans class TZlibTransport(TTransportBase, CReadableTransport): """Class that wraps a transport with zlib, compressing writes and decompresses reads, using the python standard library zlib module. """ # Read buffer size for the python fastbinary C extension, # the TBinaryProtocolAccelerated class. DEFAULT_BUFFSIZE = 4096 def __init__(self, trans, compresslevel=9): """Create a new TZlibTransport, wrapping C{trans}, another TTransport derived object. @param trans: A thrift transport object, i.e. a TSocket() object. @type trans: TTransport @param compresslevel: The zlib compression level, ranging from 0 (no compression) to 9 (best compression). Default is 9. @type compresslevel: int """ self.__trans = trans self.compresslevel = compresslevel self.__rbuf = BufferIO() self.__wbuf = BufferIO() self._init_zlib() self._init_stats() def _reinit_buffers(self): """Internal method to initialize/reset the internal StringIO objects for read and write buffers. """ self.__rbuf = BufferIO() self.__wbuf = BufferIO() def _init_stats(self): """Internal method to reset the internal statistics counters for compression ratios and bandwidth savings. """ self.bytes_in = 0 self.bytes_out = 0 self.bytes_in_comp = 0 self.bytes_out_comp = 0 def _init_zlib(self): """Internal method for setting up the zlib compression and decompression objects. """ self._zcomp_read = zlib.decompressobj() self._zcomp_write = zlib.compressobj(self.compresslevel) def getCompRatio(self): """Get the current measured compression ratios (in,out) from this transport. Returns a tuple of: (inbound_compression_ratio, outbound_compression_ratio) The compression ratios are computed as: compressed / uncompressed E.g., data that compresses by 10x will have a ratio of: 0.10 and data that compresses to half of ts original size will have a ratio of 0.5 None is returned if no bytes have yet been processed in a particular direction. """ r_percent, w_percent = (None, None) if self.bytes_in > 0: r_percent = self.bytes_in_comp / self.bytes_in if self.bytes_out > 0: w_percent = self.bytes_out_comp / self.bytes_out return (r_percent, w_percent) def getCompSavings(self): """Get the current count of saved bytes due to data compression. Returns a tuple of: (inbound_saved_bytes, outbound_saved_bytes) Note: if compression is actually expanding your data (only likely with very tiny thrift objects), then the values returned will be negative. """ r_saved = self.bytes_in - self.bytes_in_comp w_saved = self.bytes_out - self.bytes_out_comp return (r_saved, w_saved) def isOpen(self): """Return the underlying transport's open status""" return self.__trans.isOpen() def open(self): """Open the underlying transport""" self._init_stats() return self.__trans.open() def listen(self): """Invoke the underlying transport's listen() method""" self.__trans.listen() def accept(self): """Accept connections on the underlying transport""" return self.__trans.accept() def close(self): """Close the underlying transport,""" self._reinit_buffers() self._init_zlib() return self.__trans.close() def read(self, sz): """Read up to sz bytes from the decompressed bytes buffer, and read from the underlying transport if the decompression buffer is empty. """ ret = self.__rbuf.read(sz) if len(ret) > 0: return ret # keep reading from transport until something comes back while True: if self.readComp(sz): break ret = self.__rbuf.read(sz) return ret def readComp(self, sz): """Read compressed data from the underlying transport, then decompress it and append it to the internal StringIO read buffer """ zbuf = self.__trans.read(sz) zbuf = self._zcomp_read.unconsumed_tail + zbuf buf = self._zcomp_read.decompress(zbuf) self.bytes_in += len(zbuf) self.bytes_in_comp += len(buf) old = self.__rbuf.read() self.__rbuf = BufferIO(old + buf) if len(old) + len(buf) == 0: return False return True def write(self, buf): """Write some bytes, putting them into the internal write buffer for eventual compression. """ self.__wbuf.write(buf) def flush(self): """Flush any queued up data in the write buffer and ensure the compression buffer is flushed out to the underlying transport """ wout = self.__wbuf.getvalue() if len(wout) > 0: zbuf = self._zcomp_write.compress(wout) self.bytes_out += len(wout) self.bytes_out_comp += len(zbuf) else: zbuf = '' ztail = self._zcomp_write.flush(zlib.Z_SYNC_FLUSH) self.bytes_out_comp += len(ztail) if (len(zbuf) + len(ztail)) > 0: self.__wbuf = BufferIO() self.__trans.write(zbuf + ztail) self.__trans.flush() @property def cstringio_buf(self): """Implement the CReadableTransport interface""" return self.__rbuf def cstringio_refill(self, partialread, reqlen): """Implement the CReadableTransport interface for refill""" retstring = partialread if reqlen < self.DEFAULT_BUFFSIZE: retstring += self.read(self.DEFAULT_BUFFSIZE) while len(retstring) < reqlen: retstring += self.read(reqlen - len(retstring)) self.__rbuf = BufferIO(retstring) return self.__rbuf thrift-0.16.0/lib/py/src/transport/__init__.py000066400000000000000000000015271420101504100212210ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # __all__ = ['TTransport', 'TSocket', 'THttpClient', 'TZlibTransport'] thrift-0.16.0/lib/py/src/transport/sslcompat.py000066400000000000000000000071161420101504100214670ustar00rootroot00000000000000# # licensed to the apache software foundation (asf) under one # or more contributor license agreements. see the notice file # distributed with this work for additional information # regarding copyright ownership. the asf licenses this file # to you under the apache license, version 2.0 (the # "license"); you may not use this file except in compliance # with the license. you may obtain a copy of the license at # # http://www.apache.org/licenses/license-2.0 # # unless required by applicable law or agreed to in writing, # software distributed under the license is distributed on an # "as is" basis, without warranties or conditions of any # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import logging import sys from thrift.transport.TTransport import TTransportException logger = logging.getLogger(__name__) def legacy_validate_callback(cert, hostname): """legacy method to validate the peer's SSL certificate, and to check the commonName of the certificate to ensure it matches the hostname we used to make this connection. Does not support subjectAltName records in certificates. raises TTransportException if the certificate fails validation. """ if 'subject' not in cert: raise TTransportException( TTransportException.NOT_OPEN, 'No SSL certificate found from %s' % hostname) fields = cert['subject'] for field in fields: # ensure structure we get back is what we expect if not isinstance(field, tuple): continue cert_pair = field[0] if len(cert_pair) < 2: continue cert_key, cert_value = cert_pair[0:2] if cert_key != 'commonName': continue certhost = cert_value # this check should be performed by some sort of Access Manager if certhost == hostname: # success, cert commonName matches desired hostname return else: raise TTransportException( TTransportException.UNKNOWN, 'Hostname we connected to "%s" doesn\'t match certificate ' 'provided commonName "%s"' % (hostname, certhost)) raise TTransportException( TTransportException.UNKNOWN, 'Could not validate SSL certificate from host "%s". Cert=%s' % (hostname, cert)) def _optional_dependencies(): try: import ipaddress # noqa logger.debug('ipaddress module is available') ipaddr = True except ImportError: logger.warn('ipaddress module is unavailable') ipaddr = False if sys.hexversion < 0x030500F0: try: from backports.ssl_match_hostname import match_hostname, __version__ as ver ver = list(map(int, ver.split('.'))) logger.debug('backports.ssl_match_hostname module is available') match = match_hostname if ver[0] * 10 + ver[1] >= 35: return ipaddr, match else: logger.warn('backports.ssl_match_hostname module is too old') ipaddr = False except ImportError: logger.warn('backports.ssl_match_hostname is unavailable') ipaddr = False try: from ssl import match_hostname logger.debug('ssl.match_hostname is available') match = match_hostname except ImportError: logger.warn('using legacy validation callback') match = legacy_validate_callback return ipaddr, match _match_has_ipaddress, _match_hostname = _optional_dependencies() thrift-0.16.0/lib/py/test/000077500000000000000000000000001420101504100152375ustar00rootroot00000000000000thrift-0.16.0/lib/py/test/_import_local_thrift.py000066400000000000000000000022121420101504100220110ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import glob import os import sys SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))) for libpath in glob.glob(os.path.join(ROOT_DIR, 'lib', 'py', 'build', 'lib.*')): if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])): sys.path.insert(0, libpath) break thrift-0.16.0/lib/py/test/test_socket.py000066400000000000000000000034001420101504100201350ustar00rootroot00000000000000import errno import unittest from test_sslsocket import ServerAcceptor import _import_local_thrift # noqa from thrift.transport.TSocket import TServerSocket from thrift.transport.TSocket import TSocket from thrift.transport.TTransport import TTransportException class TSocketTest(unittest.TestCase): def test_isOpen_checks_for_readability(self): # https://docs.python.org/3/library/socket.html#notes-on-socket-timeouts # https://docs.python.org/3/library/socket.html#socket.socket.settimeout timeouts = [ None, # blocking mode 0, # non-blocking mode 1.0, # timeout mode ] for timeout in timeouts: acc = ServerAcceptor(TServerSocket(port=0)) acc.start() sock = TSocket(host="localhost", port=acc.port) sock.open() sock.setTimeout(timeout) # the socket shows as open immediately after connecting self.assertTrue(sock.isOpen()) # and remains open during usage sock.write(b"hello") self.assertTrue(sock.isOpen()) while True: try: sock.read(5) except TTransportException as exc: if exc.inner.errno == errno.EAGAIN: # try again when we're in non-blocking mode continue raise break self.assertTrue(sock.isOpen()) # once the server side closes, it no longer shows open acc.client.close() # this also blocks until the other thread is done acc.close() self.assertFalse(sock.isOpen()) sock.close() if __name__ == "__main__": unittest.main() thrift-0.16.0/lib/py/test/test_sslsocket.py000066400000000000000000000351701420101504100206700ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import inspect import logging import os import platform import ssl import sys import tempfile import threading import unittest import warnings from contextlib import contextmanager import _import_local_thrift # noqa SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))) SERVER_PEM = os.path.join(ROOT_DIR, 'test', 'keys', 'server.pem') SERVER_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'server.crt') SERVER_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'server.key') CLIENT_CERT_NO_IP = os.path.join(ROOT_DIR, 'test', 'keys', 'client.crt') CLIENT_KEY_NO_IP = os.path.join(ROOT_DIR, 'test', 'keys', 'client.key') CLIENT_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'client_v3.crt') CLIENT_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'client_v3.key') CLIENT_CA = os.path.join(ROOT_DIR, 'test', 'keys', 'CA.pem') TEST_CIPHERS = 'DES-CBC3-SHA:ECDHE-RSA-AES128-GCM-SHA256' class ServerAcceptor(threading.Thread): def __init__(self, server, expect_failure=False): super(ServerAcceptor, self).__init__() self.daemon = True self._server = server self._listening = threading.Event() self._port = None self._port_bound = threading.Event() self._client = None self._client_accepted = threading.Event() self._expect_failure = expect_failure frame = inspect.stack(3)[2] self.name = frame[3] del frame def run(self): self._server.listen() self._listening.set() try: address = self._server.handle.getsockname() if len(address) > 1: # AF_INET addresses are 2-tuples (host, port) and AF_INET6 are # 4-tuples (host, port, ...), but in each case port is in the second slot. self._port = address[1] finally: self._port_bound.set() try: self._client = self._server.accept() if self._client: self._client.read(5) # hello self._client.write(b"there") except Exception: logging.exception('error on server side (%s):' % self.name) if not self._expect_failure: raise finally: self._client_accepted.set() def await_listening(self): self._listening.wait() @property def port(self): self._port_bound.wait() return self._port @property def client(self): self._client_accepted.wait() return self._client def close(self): if self._client: self._client.close() self._server.close() # Python 2.6 compat class AssertRaises(object): def __init__(self, expected): self._expected = expected def __enter__(self): pass def __exit__(self, exc_type, exc_value, traceback): if not exc_type or not issubclass(exc_type, self._expected): raise Exception('fail') return True class TSSLSocketTest(unittest.TestCase): def _server_socket(self, **kwargs): return TSSLServerSocket(port=0, **kwargs) @contextmanager def _connectable_client(self, server, expect_failure=False, path=None, **client_kwargs): acc = ServerAcceptor(server, expect_failure) try: acc.start() acc.await_listening() host, port = ('localhost', acc.port) if path is None else (None, None) client = TSSLSocket(host, port, unix_socket=path, **client_kwargs) yield acc, client finally: acc.close() def _assert_connection_failure(self, server, path=None, **client_args): logging.disable(logging.CRITICAL) try: with self._connectable_client(server, True, path=path, **client_args) as (acc, client): # We need to wait for a connection failure, but not too long. 20ms is a tunable # compromise between test speed and stability client.setTimeout(20) with self._assert_raises(TTransportException): client.open() client.write(b"hello") client.read(5) # b"there" finally: logging.disable(logging.NOTSET) def _assert_raises(self, exc): if sys.hexversion >= 0x020700F0: return self.assertRaises(exc) else: return AssertRaises(exc) def _assert_connection_success(self, server, path=None, **client_args): with self._connectable_client(server, path=path, **client_args) as (acc, client): try: client.open() client.write(b"hello") self.assertEqual(client.read(5), b"there") self.assertTrue(acc.client is not None) finally: client.close() # deprecated feature def test_deprecation(self): with warnings.catch_warnings(record=True) as w: warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) TSSLSocket('localhost', 0, validate=True, ca_certs=SERVER_CERT) self.assertEqual(len(w), 1) with warnings.catch_warnings(record=True) as w: warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) # Deprecated signature # def __init__(self, host='localhost', port=9090, validate=True, ca_certs=None, keyfile=None, certfile=None, unix_socket=None, ciphers=None): TSSLSocket('localhost', 0, True, SERVER_CERT, CLIENT_KEY, CLIENT_CERT, None, TEST_CIPHERS) self.assertEqual(len(w), 7) with warnings.catch_warnings(record=True) as w: warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) # Deprecated signature # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None): TSSLServerSocket(None, 0, SERVER_PEM, None, TEST_CIPHERS) self.assertEqual(len(w), 3) # deprecated feature def test_set_cert_reqs_by_validate(self): with warnings.catch_warnings(record=True) as w: warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) c1 = TSSLSocket('localhost', 0, validate=True, ca_certs=SERVER_CERT) self.assertEqual(c1.cert_reqs, ssl.CERT_REQUIRED) c1 = TSSLSocket('localhost', 0, validate=False) self.assertEqual(c1.cert_reqs, ssl.CERT_NONE) self.assertEqual(len(w), 2) # deprecated feature def test_set_validate_by_cert_reqs(self): with warnings.catch_warnings(record=True) as w: warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__) c1 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_NONE) self.assertFalse(c1.validate) c2 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) self.assertTrue(c2.validate) c3 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_OPTIONAL, ca_certs=SERVER_CERT) self.assertTrue(c3.validate) self.assertEqual(len(w), 3) def test_unix_domain_socket(self): if platform.system() == 'Windows': print('skipping test_unix_domain_socket') return fd, path = tempfile.mkstemp() os.close(fd) os.unlink(path) try: server = self._server_socket(unix_socket=path, keyfile=SERVER_KEY, certfile=SERVER_CERT) self._assert_connection_success(server, path=path, cert_reqs=ssl.CERT_NONE) finally: os.unlink(path) def test_server_cert(self): server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) self._assert_connection_success(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) # server cert not in ca_certs self._assert_connection_failure(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=CLIENT_CERT) server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE) def test_set_server_cert(self): server = self._server_socket(keyfile=SERVER_KEY, certfile=CLIENT_CERT) with self._assert_raises(Exception): server.certfile = 'foo' with self._assert_raises(Exception): server.certfile = None server.certfile = SERVER_CERT self._assert_connection_success(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) def test_client_cert(self): if not _match_has_ipaddress: print('skipping test_client_cert') return server = self._server_socket( cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY, certfile=SERVER_CERT, ca_certs=CLIENT_CERT) self._assert_connection_failure(server, cert_reqs=ssl.CERT_NONE, certfile=SERVER_CERT, keyfile=SERVER_KEY) server = self._server_socket( cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY, certfile=SERVER_CERT, ca_certs=CLIENT_CA) self._assert_connection_failure(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT_NO_IP, keyfile=CLIENT_KEY_NO_IP) server = self._server_socket( cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY, certfile=SERVER_CERT, ca_certs=CLIENT_CA) self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT, keyfile=CLIENT_KEY) server = self._server_socket( cert_reqs=ssl.CERT_OPTIONAL, keyfile=SERVER_KEY, certfile=SERVER_CERT, ca_certs=CLIENT_CA) self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT, keyfile=CLIENT_KEY) def test_ciphers(self): server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS) self._assert_connection_success(server, ca_certs=SERVER_CERT, ciphers=TEST_CIPHERS) if not TSSLSocket._has_ciphers: # unittest.skip is not available for Python 2.6 print('skipping test_ciphers') return server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) self._assert_connection_failure(server, ca_certs=SERVER_CERT, ciphers='NULL') server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS) self._assert_connection_failure(server, ca_certs=SERVER_CERT, ciphers='NULL') def test_ssl2_and_ssl3_disabled(self): if not hasattr(ssl, 'PROTOCOL_SSLv3'): print('PROTOCOL_SSLv3 is not available') else: server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3) server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3) self._assert_connection_failure(server, ca_certs=SERVER_CERT) if not hasattr(ssl, 'PROTOCOL_SSLv2'): print('PROTOCOL_SSLv2 is not available') else: server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT) self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2) server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2) self._assert_connection_failure(server, ca_certs=SERVER_CERT) def test_newer_tls(self): if not TSSLSocket._has_ssl_context: # unittest.skip is not available for Python 2.6 print('skipping test_newer_tls') return if not hasattr(ssl, 'PROTOCOL_TLSv1_2'): print('PROTOCOL_TLSv1_2 is not available') else: server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) self._assert_connection_success(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) if not hasattr(ssl, 'PROTOCOL_TLSv1_1'): print('PROTOCOL_TLSv1_1 is not available') else: server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) self._assert_connection_success(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) if not hasattr(ssl, 'PROTOCOL_TLSv1_1') or not hasattr(ssl, 'PROTOCOL_TLSv1_2'): print('PROTOCOL_TLSv1_1 and/or PROTOCOL_TLSv1_2 is not available') else: server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) def test_ssl_context(self): if not TSSLSocket._has_ssl_context: # unittest.skip is not available for Python 2.6 print('skipping test_ssl_context') return server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) server_context.load_cert_chain(SERVER_CERT, SERVER_KEY) server_context.load_verify_locations(CLIENT_CA) server_context.verify_mode = ssl.CERT_REQUIRED server = self._server_socket(ssl_context=server_context) client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) client_context.load_cert_chain(CLIENT_CERT, CLIENT_KEY) client_context.load_verify_locations(SERVER_CERT) client_context.verify_mode = ssl.CERT_REQUIRED self._assert_connection_success(server, ssl_context=client_context) if __name__ == '__main__': logging.basicConfig(level=logging.WARN) from thrift.transport.TSSLSocket import TSSLSocket, TSSLServerSocket, _match_has_ipaddress from thrift.transport.TTransport import TTransportException unittest.main() thrift-0.16.0/lib/py/test/test_thrift_file/000077500000000000000000000000001420101504100205755ustar00rootroot00000000000000thrift-0.16.0/lib/py/test/test_thrift_file/TestServer.thrift000066400000000000000000000016261420101504100241320ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # struct Message { 1: optional string body, 2: optional i64 num, } service TestServer{ string add_and_get_msg(1:string msg) } thrift-0.16.0/lib/py/test/thrift_TBinaryProtocol.py000066400000000000000000000224001420101504100222610ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import unittest import _import_local_thrift # noqa from thrift.protocol.TBinaryProtocol import TBinaryProtocol from thrift.transport import TTransport def testNaked(type, data): buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TBinaryProtocol(transport) if type.capitalize() == 'Byte': protocol.writeByte(data) if type.capitalize() == 'I16': protocol.writeI16(data) if type.capitalize() == 'I32': protocol.writeI32(data) if type.capitalize() == 'I64': protocol.writeI64(data) if type.capitalize() == 'String': protocol.writeString(data) if type.capitalize() == 'Double': protocol.writeDouble(data) if type.capitalize() == 'Binary': protocol.writeBinary(data) if type.capitalize() == 'Bool': protocol.writeBool(data) transport.flush() data_r = buf.getvalue() buf = TTransport.TMemoryBuffer(data_r) transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TBinaryProtocol(transport) if type.capitalize() == 'Byte': return protocol.readByte() if type.capitalize() == 'I16': return protocol.readI16() if type.capitalize() == 'I32': return protocol.readI32() if type.capitalize() == 'I64': return protocol.readI64() if type.capitalize() == 'String': return protocol.readString() if type.capitalize() == 'Double': return protocol.readDouble() if type.capitalize() == 'Binary': return protocol.readBinary() if type.capitalize() == 'Bool': return protocol.readBool() def testField(type, data): TType = {"Bool": 2, "Byte": 3, "Binary": 5, "I16": 6, "I32": 8, "I64": 10, "Double": 11, "String": 12} buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TBinaryProtocol(transport) protocol.writeStructBegin('struct') protocol.writeFieldBegin("field", TType[type.capitalize()], 10) if type.capitalize() == 'Byte': protocol.writeByte(data) if type.capitalize() == 'I16': protocol.writeI16(data) if type.capitalize() == 'I32': protocol.writeI32(data) if type.capitalize() == 'I64': protocol.writeI64(data) if type.capitalize() == 'String': protocol.writeString(data) if type.capitalize() == 'Double': protocol.writeDouble(data) if type.capitalize() == 'Binary': protocol.writeBinary(data) if type.capitalize() == 'Bool': protocol.writeBool(data) protocol.writeFieldEnd() protocol.writeStructEnd() transport.flush() data_r = buf.getvalue() buf = TTransport.TMemoryBuffer(data_r) transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TBinaryProtocol(transport) protocol.readStructBegin() protocol.readFieldBegin() if type.capitalize() == 'Byte': return protocol.readByte() if type.capitalize() == 'I16': return protocol.readI16() if type.capitalize() == 'I32': return protocol.readI32() if type.capitalize() == 'I64': return protocol.readI64() if type.capitalize() == 'String': return protocol.readString() if type.capitalize() == 'Double': return protocol.readDouble() if type.capitalize() == 'Binary': return protocol.readBinary() if type.capitalize() == 'Bool': return protocol.readBool() protocol.readFieldEnd() protocol.readStructEnd() def testMessage(data): message = {} message['name'] = data[0] message['type'] = data[1] message['seqid'] = data[2] buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TBinaryProtocol(transport) protocol.writeMessageBegin(message['name'], message['type'], message['seqid']) protocol.writeMessageEnd() transport.flush() data_r = buf.getvalue() buf = TTransport.TMemoryBuffer(data_r) transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TBinaryProtocol(transport) result = protocol.readMessageBegin() protocol.readMessageEnd() return result class TestTBinaryProtocol(unittest.TestCase): def test_TBinaryProtocol_write_read(self): try: testNaked('Byte', 123) for i in range(0, 128): self.assertEqual(i, testField('Byte', i)) self.assertEqual(-i, testField('Byte', -i)) self.assertEqual(0, testNaked("I16", 0)) self.assertEqual(1, testNaked("I16", 1)) self.assertEqual(15000, testNaked("I16", 15000)) self.assertEqual(0x7fff, testNaked("I16", 0x7fff)) self.assertEqual(-1, testNaked("I16", -1)) self.assertEqual(-15000, testNaked("I16", -15000)) self.assertEqual(-0x7fff, testNaked("I16", -0x7fff)) self.assertEqual(32767, testNaked("I16", 32767)) self.assertEqual(-32768, testNaked("I16", -32768)) self.assertEqual(0, testField("I16", 0)) self.assertEqual(1, testField("I16", 1)) self.assertEqual(7, testField("I16", 7)) self.assertEqual(150, testField("I16", 150)) self.assertEqual(15000, testField("I16", 15000)) self.assertEqual(0x7fff, testField("I16", 0x7fff)) self.assertEqual(-1, testField("I16", -1)) self.assertEqual(-7, testField("I16", -7)) self.assertEqual(-150, testField("I16", -150)) self.assertEqual(-15000, testField("I16", -15000)) self.assertEqual(-0xfff, testField("I16", -0xfff)) self.assertEqual(0, testNaked("I32", 0)) self.assertEqual(1, testNaked("I32", 1)) self.assertEqual(15000, testNaked("I32", 15000)) self.assertEqual(0xffff, testNaked("I32", 0xffff)) self.assertEqual(-1, testNaked("I32", -1)) self.assertEqual(-15000, testNaked("I32", -15000)) self.assertEqual(-0xffff, testNaked("I32", -0xffff)) self.assertEqual(2147483647, testNaked("I32", 2147483647)) self.assertEqual(-2147483647, testNaked("I32", -2147483647)) self.assertEqual(0, testField("I32", 0)) self.assertEqual(1, testField("I32", 1)) self.assertEqual(7, testField("I32", 7)) self.assertEqual(150, testField("I32", 150)) self.assertEqual(15000, testField("I32", 15000)) self.assertEqual(31337, testField("I32", 31337)) self.assertEqual(0xffff, testField("I32", 0xffff)) self.assertEqual(0xffffff, testField("I32", 0xffffff)) self.assertEqual(-1, testField("I32", -1)) self.assertEqual(-7, testField("I32", -7)) self.assertEqual(-150, testField("I32", -150)) self.assertEqual(-15000, testField("I32", -15000)) self.assertEqual(-0xffff, testField("I32", -0xffff)) self.assertEqual(-0xffffff, testField("I32", -0xffffff)) self.assertEqual(9223372036854775807, testNaked("I64", 9223372036854775807)) self.assertEqual(-9223372036854775807, testNaked("I64", -9223372036854775807)) self.assertEqual(-0, testNaked("I64", 0)) self.assertEqual(True, testNaked("Bool", True)) self.assertEqual(3.14159261, testNaked("Double", 3.14159261)) self.assertEqual("hello thrift", testNaked("String", "hello thrift")) self.assertEqual(True, testField('Bool', True)) self.assertEqual(3.1415926, testNaked("Double", 3.1415926)) self.assertEqual("hello thrift", testNaked("String", "hello thrift")) TMessageType = {"T_CALL": 1, "T_REPLY": 2, "T_EXCEPTION": 3, "T_ONEWAY": 4} test_data = [("short message name", TMessageType['T_CALL'], 0), ("1", TMessageType['T_REPLY'], 12345), ("loooooooooooooooooooooooooooooooooong", TMessageType['T_EXCEPTION'], 1 << 16), ("one way push", TMessageType['T_ONEWAY'], 12), ("Janky", TMessageType['T_CALL'], 0)] for dt in test_data: result = testMessage(dt) self.assertEqual(result[0], dt[0]) self.assertEqual(result[1], dt[1]) self.assertEqual(result[2], dt[2]) except Exception as e: print("Assertion fail") raise e if __name__ == '__main__': unittest.main() thrift-0.16.0/lib/py/test/thrift_TCompactProtocol.py000066400000000000000000000242111420101504100224250ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import _import_local_thrift # noqa from thrift.protocol import TCompactProtocol from thrift.transport import TTransport import unittest CLEAR = 0 FIELD_WRITE = 1 VALUE_WRITE = 2 CONTAINER_WRITE = 3 BOOL_WRITE = 4 FIELD_READ = 5 CONTAINER_READ = 6 VALUE_READ = 7 BOOL_READ = 8 def testNaked(type, data): buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TCompactProtocol.TCompactProtocol(transport) if type.capitalize() == 'Byte': protocol.state = VALUE_WRITE protocol.writeByte(data) elif type.capitalize() == 'I16': protocol.state = CONTAINER_WRITE protocol.writeI16(data) elif type.capitalize() == 'I32': protocol.state = CONTAINER_WRITE protocol.writeI32(data) elif type.capitalize() == 'I64': protocol.state = CONTAINER_WRITE protocol.writeI64(data) elif type.capitalize() == 'String': protocol.state = CONTAINER_WRITE protocol.writeString(data) elif type.capitalize() == 'Double': protocol.state = VALUE_WRITE protocol.writeDouble(data) elif type.capitalize() == 'Binary': protocol.state = FIELD_WRITE protocol.writeBinary(data) elif type.capitalize() == 'Bool': protocol.state = CONTAINER_WRITE protocol.writeBool(True) transport.flush() data_r = buf.getvalue() buf = TTransport.TMemoryBuffer(data_r) transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TCompactProtocol.TCompactProtocol(transport) if type.capitalize() == 'Byte': protocol.state = VALUE_READ return protocol.readByte() elif type.capitalize() == 'I16': protocol.state = CONTAINER_READ return protocol.readI16() elif type.capitalize() == 'I32': protocol.state = CONTAINER_READ return protocol.readI32() elif type.capitalize() == 'I64': protocol.state = CONTAINER_READ return protocol.readI64() elif type.capitalize() == 'String': protocol.state = VALUE_READ return protocol.readString() elif type.capitalize() == 'Double': protocol.state = VALUE_READ return protocol.readDouble() elif type.capitalize() == 'Binary': protocol.state = FIELD_READ return protocol.readBinary() elif type.capitalize() == 'Bool': protocol.state = CONTAINER_READ return protocol.readBool() def testField(type, data): TType = {"Bool": 2, "Byte": 3, "Binary": 5, "I16": 6, "I32": 8, "I64": 10, "Double": 11, "String": 12} buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TCompactProtocol.TCompactProtocol(transport) protocol.writeStructBegin('struct') protocol.writeFieldBegin("field", TType[type.capitalize()], 10) if type.capitalize() == 'Byte': protocol.writeByte(data) elif type.capitalize() == 'I16': protocol.writeI16(data) elif type.capitalize() == 'I32': protocol.writeI32(data) elif type.capitalize() == 'I64': protocol.writeI64(data) elif type.capitalize() == 'String': protocol.writeString(data) elif type.capitalize() == 'Double': protocol.writeDouble(data) elif type.capitalize() == 'Binary': protocol.writeBinary(data) elif type.capitalize() == 'Bool': protocol.writeBool(data) protocol.writeFieldEnd() protocol.writeStructEnd() transport.flush() data_r = buf.getvalue() buf = TTransport.TMemoryBuffer(data_r) transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TCompactProtocol.TCompactProtocol(transport) protocol.readStructBegin() protocol.readFieldBegin() if type.capitalize() == 'Byte': return protocol.readByte() elif type.capitalize() == 'I16': return protocol.readI16() elif type.capitalize() == 'I32': return protocol.readI32() elif type.capitalize() == 'I64': return protocol.readI32() elif type.capitalize() == 'String': return protocol.readString() elif type.capitalize() == 'Double': return protocol.readDouble() elif type.capitalize() == 'Binary': return protocol.readBinary() elif type.capitalize() == 'Bool': return protocol.readBool() protocol.readFieldEnd() protocol.readStructEnd() def testMessage(data): message = {} message['name'] = data[0] message['type'] = data[1] message['seqid'] = data[2] buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TCompactProtocol.TCompactProtocol(transport) protocol.writeMessageBegin(message['name'], message['type'], message['seqid']) protocol.writeMessageEnd() transport.flush() data_r = buf.getvalue() buf = TTransport.TMemoryBuffer(data_r) transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TCompactProtocol.TCompactProtocol(transport) result = protocol.readMessageBegin() protocol.readMessageEnd() return result class TestTCompactProtocol(unittest.TestCase): def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) def test_TCompactProtocol_write_read(self): try: testNaked('Byte', 123) for i in range(0, 128): self.assertEqual(i, testField('Byte', i)) self.assertEqual(-i, testField('Byte', -i)) self.assertEqual(0, testNaked("I16", 0)) self.assertEqual(1, testNaked("I16", 1)) self.assertEqual(15000, testNaked("I16", 15000)) self.assertEqual(0x7fff, testNaked('I16', 0x7fff)) self.assertEqual(-1, testNaked('I16', -1)) self.assertEqual(-15000, testNaked('I16', -15000)) self.assertEqual(-0x7fff, testNaked('I16', -0x7fff)) self.assertEqual(32767, testNaked('I16', 32767)) self.assertEqual(0, testField('I16', 0)) self.assertEqual(1, testField('I16', 1)) self.assertEqual(7, testField('I16', 7)) self.assertEqual(150, testField('I16', 150)) self.assertEqual(15000, testField('I16', 15000)) self.assertEqual(0x7fff, testField('I16', 0x7fff)) self.assertEqual(-1, testField('I16', -1)) self.assertEqual(-7, testField('I16', -7)) self.assertEqual(-150, testField('I16', -150)) self.assertEqual(-15000, testField('I16', -15000)) self.assertEqual(-0xfff, testField('I16', -0xfff)) self.assertEqual(0, testNaked('I32', 0)) self.assertEqual(1, testNaked('I32', 1)) self.assertEqual(15000, testNaked('I32', 15000)) self.assertEqual(0xfff, testNaked('I32', 0xfff)) self.assertEqual(-1, testNaked('I32', -1)) self.assertEqual(-15000, testNaked('I32', -15000)) self.assertEqual(-0xfff, testNaked('I32', -0xfff)) self.assertEqual(2147483647, testNaked('I32', 2147483647)) self.assertEqual(-2147483647, testNaked('I32', -2147483647)) self.assertEqual(0, testField('I32', 0)) self.assertEqual(1, testField('I32', 1)) self.assertEqual(7, testField('I32', 7)) self.assertEqual(150, testField('I32', 150)) self.assertEqual(15000, testField('I32', 15000)) self.assertEqual(31337, testField('I32', 31337)) self.assertEqual(0xffff, testField('I32', 0xffff)) self.assertEqual(0xffffff, testField('I32', 0xffffff)) self.assertEqual(-1, testField('I32', -1)) self.assertEqual(-7, testField('I32', -7)) self.assertEqual(-150, testField('I32', -150)) self.assertEqual(-15000, testField('I32', -15000)) self.assertEqual(-0xffff, testField('I32', -0xffff)) self.assertEqual(-0xffffff, testField('I32', -0xffffff)) self.assertEqual(9223372036854775807, testNaked("I64", 9223372036854775807)) self.assertEqual(-9223372036854775807, testNaked('I64', -9223372036854775807)) self.assertEqual(-0, testNaked('I64', 0)) self.assertEqual(True, testNaked('Bool', True)) self.assertEqual(3.14159261, testNaked('Double', 3.14159261)) self.assertEqual("hello thrift", testNaked('String', "hello thrift")) self.assertEqual(True, testField('Bool', True)) self.assertEqual(3.14159261, testField('Double', 3.14159261)) self.assertEqual("hello thrift", testField('String', "hello thrift")) TMessage = {"T_CALL": 1, "T_REPLY": 2, "T_EXCEPTION": 3, "T_ONEWAY": 4} test_data = [("short message name", TMessage["T_CALL"], 0), ("1", TMessage["T_REPLY"], 12345), ("loooooooooooooooooooong", TMessage["T_EXCEPTION"], 1 << 16), ("one way push", TMessage["T_ONEWAY"], 12), ("JANKY", TMessage["T_CALL"], 0)] for dt in test_data: result = testMessage(dt) self.assertEqual(result[0], dt[0]) self.assertEqual(result[1], dt[1]) self.assertEqual(result[2], dt[2]) except Exception as e: print("Assertion fail") raise e if __name__ == "__main__": unittest.main() thrift-0.16.0/lib/py/test/thrift_TNonblockingServer.py000066400000000000000000000056151420101504100227560ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os import sys import threading import unittest import time gen_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "gen-py") sys.path.append(gen_path) import _import_local_thrift # noqa from TestServer import TestServer from thrift.transport import TSocket, TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TNonblockingServer class Handler: def add_and_get_msg(self, msg): return msg class Server: def __init__(self): handler = Handler() processor = TestServer.Processor(handler) transport = TSocket.TServerSocket("127.0.0.1", 30030) self.server = TNonblockingServer.TNonblockingServer(processor, transport) def start_server(self): print("-------start server ------\n") self.server.serve() print("------stop server -----\n") def close_server(self): self.server.stop() self.server.close() class Client: def start_client(self): transport = TSocket.TSocket("127.0.0.1", 30030) trans = TTransport.TFramedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(trans) client = TestServer.Client(protocol) trans.open() self.msg = client.add_and_get_msg("hello thrift") def get_message(self): try: msg = self.msg return msg except AttributeError as e: raise e print("self.msg not exit\n") class TestNonblockingServer(unittest.TestCase): def test_normalconnection(self): serve = Server() client = Client() serve_thread = threading.Thread(target=serve.start_server) client_thread = threading.Thread(target=client.start_client) serve_thread.start() time.sleep(10) client_thread.start() client_thread.join(0.5) try: msg = client.get_message() self.assertEqual("hello thrift", msg) except AssertionError as e: raise e print("assert failure") finally: serve.close_server() if __name__ == '__main__': unittest.main() thrift-0.16.0/lib/py/test/thrift_TSerializer.py000066400000000000000000000057151420101504100214360ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import unittest import os import sys gen_path = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "gen-py" ) sys.path.append(gen_path) import _import_local_thrift # noqa from thrift.protocol.TBinaryProtocol import TBinaryProtocolFactory from thrift.protocol.TBinaryProtocol import TBinaryProtocolAcceleratedFactory from thrift.protocol.TCompactProtocol import TCompactProtocolFactory from thrift.protocol.TCompactProtocol import TCompactProtocolAcceleratedFactory from thrift.transport import TTransport from thrift.TSerialization import serialize, deserialize from TestServer.ttypes import Message class TestSerializer(unittest.TestCase): def setUp(self): self.message = Message("hello thrift", 42) self.binary_serialized = b"\x0b\x00\x01\x00\x00\x00\x0chello thrift\n\x00\x02\x00\x00\x00\x00\x00\x00\x00*\x00" self.compact_serialized = b'\x18\x0chello thrift\x16T\x00' def verify(self, serialized, factory): self.assertEqual(serialized, serialize(self.message, factory)) self.assertEqual( "hello thrift", deserialize(Message(), serialized, factory).body, ) self.assertEqual( 42, deserialize(Message(), serialized, factory).num ) self.assertRaises(EOFError, deserialize, Message(), b'', factory) def test_TBinaryProtocol(self): buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) factory = TBinaryProtocolFactory(transport) self.verify(self.binary_serialized, factory) def test_TBinaryProtocolAccelerated(self): buf = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buf) factory = TBinaryProtocolAcceleratedFactory(transport) self.verify(self.binary_serialized, factory) def test_TCompactProtocol(self): factory = TCompactProtocolFactory() self.verify(self.compact_serialized, factory) def test_TCompactProtocolAccelerated(self): factory = TCompactProtocolAcceleratedFactory() self.verify(self.compact_serialized, factory) if __name__ == "__main__": unittest.main() thrift-0.16.0/lib/py/test/thrift_TZlibTransport.py000066400000000000000000000063751420101504100221450ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import unittest import random import string import _import_local_thrift # noqa from thrift.transport import TTransport from thrift.transport import TZlibTransport def generate_random_buff(): data = [] buf_len = 1024 * 32 index = 0 while index < buf_len: run_len = random.randint(1, 64) if index + run_len > buf_len: run_len = buf_len - index for i in range(run_len): data.extend(random.sample(string.printable, 1)) index += 1 new_data = ''.join(data) return new_data class TestTZlibTransport(unittest.TestCase): def test_write_then_read(self): buff = TTransport.TMemoryBuffer() trans = TTransport.TBufferedTransportFactory().getTransport(buff) zlib_trans = TZlibTransport.TZlibTransport(trans) data_w = generate_random_buff() zlib_trans.write(data_w.encode('utf-8')) zlib_trans.flush() value = buff.getvalue() zlib_trans.close() buff = TTransport.TMemoryBuffer(value) trans = TTransport.TBufferedTransportFactory().getTransport(buff) zlib_trans = TZlibTransport.TZlibTransport(trans) data_r = zlib_trans.read(len(data_w)) zlib_trans.close() try: self.assertEqual(data_w, data_r.decode('utf-8')) self.assertEqual(len(data_w), len(data_r.decode('utf-8'))) except AssertionError: raise def test_after_flushd_write_then_read(self): buff = TTransport.TMemoryBuffer() trans = TTransport.TBufferedTransportFactory().getTransport(buff) zlib_trans = TZlibTransport.TZlibTransport(trans) data_w_1 = "hello thrift !@#" * 50 zlib_trans.write(data_w_1.encode('utf-8')) zlib_trans.flush() data_w_2 = "{'name': 'thrift', 1: ['abcd' , 233, ('a','c')]}" * 20 zlib_trans.write(data_w_2.encode('utf-8')) zlib_trans.flush() value = buff.getvalue() zlib_trans.close() buff = TTransport.TMemoryBuffer(value) trans = TTransport.TBufferedTransportFactory().getTransport(buff) zlib_trans = TZlibTransport.TZlibTransport(trans) data_r = zlib_trans.read(len(data_w_1) + len(data_w_2)) zlib_trans.close() try: self.assertEqual(data_w_1 + data_w_2, data_r.decode('utf-8')) self.assertEqual(len(data_w_1) + len(data_w_2), len(data_r.decode('utf-8'))) except AssertionError: raise if __name__ == '__main__': unittest.main() thrift-0.16.0/lib/py/test/thrift_json.py000066400000000000000000000104141420101504100201420ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import sys import unittest import _import_local_thrift # noqa from thrift.protocol.TJSONProtocol import TJSONProtocol from thrift.transport import TTransport # # In order to run the test under Windows. We need to create symbolic link # name 'thrift' to '../src' folder by using: # # mklink /D thrift ..\src # class TestJSONString(unittest.TestCase): def test_escaped_unicode_string(self): unicode_json = b'"hello \\u0e01\\u0e02\\u0e03\\ud835\\udcab\\udb40\\udc70 unicode"' unicode_text = u'hello \u0e01\u0e02\u0e03\U0001D4AB\U000E0070 unicode' buf = TTransport.TMemoryBuffer(unicode_json) transport = TTransport.TBufferedTransportFactory().getTransport(buf) protocol = TJSONProtocol(transport) if sys.version_info[0] == 2: unicode_text = unicode_text.encode('utf8') self.assertEqual(protocol.readString(), unicode_text) def test_TJSONProtocol_write(self): write_data = '{"software":"thrift","1":[23,1.2010000000000001,32767,2147483647,9223372036854775807],"base64":"aGVsbG8gdGhyaWZ0","bool":0}' buff = TTransport.TMemoryBuffer() transport = TTransport.TBufferedTransportFactory().getTransport(buff) protocol = TJSONProtocol(transport) protocol.writeJSONObjectStart() protocol.writeJSONString("software") protocol.writeJSONString("thrift") protocol.writeJSONString("1") protocol.writeJSONArrayStart() protocol.writeJSONNumber(23) protocol.writeDouble(1.201) protocol.writeI16(32767) protocol.writeI32(2147483647) protocol.writeI64(9223372036854775807) protocol.writeJSONArrayEnd() protocol.writeJSONString("base64") protocol.writeJSONBase64("hello thrift".encode('utf-8')) protocol.writeJSONString("bool") protocol.writeBool(0) protocol.writeJSONObjectEnd() transport.flush() value = buff.getvalue() self.assertEqual(write_data, value.decode('utf-8')) def test_TJSONProtol_read(self): expected = "{'software':'thrift','1':[23,1.2010000000000001,32767,2147483647,9223372036854775807],'base64':'hello thrift','bool':False}" read_data = '{"software":"thrift","1":[23,1.2010000000000001,32767,2147483647,9223372036854775807],"base64":"aGVsbG8gdGhyaWZ0","bool":0}' buff = TTransport.TMemoryBuffer(read_data.encode('utf-8')) transport = TTransport.TBufferedTransportFactory().getTransport(buff) protocol = TJSONProtocol(transport) protocol.readJSONObjectStart() u_1 = protocol.readString() u_2 = protocol.readString() u_3 = protocol.readString() protocol.readJSONArrayStart() u_4 = protocol.readNumber() u_5 = protocol.readDouble() u_6 = protocol.readI16() u_7 = protocol.readI32() u_8 = protocol.readI64() protocol.readJSONArrayEnd() u_9 = protocol.readString() u_10 = protocol.readJSONBase64() u_11 = protocol.readString() u_12 = protocol.readBool() protocol.writeJSONObjectEnd() result_read = {} result_read[u_1] = u_2 result_read[u_3] = [] result_read[u_3].append(u_4) result_read[u_3].append(u_5) result_read[u_3].append(u_6) result_read[u_3].append(u_7) result_read[u_3].append(u_8) result_read[u_9] = u_10.decode('utf-8') result_read[u_11] = u_12 self.assertEqual(eval(expected), result_read) if __name__ == '__main__': unittest.main() thrift-0.16.0/lib/py/test/thrift_transport.py000066400000000000000000000045501420101504100212310ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import unittest import os import _import_local_thrift # noqa from thrift.transport import TTransport class TestTFileObjectTransport(unittest.TestCase): def test_TFileObjectTransport(self): test_dir = os.path.dirname(os.path.abspath(__file__)) datatxt_path = os.path.join(test_dir, 'data.txt') buffer = '{"soft":"thrift","version":0.13,"1":true}' with open(datatxt_path, "w+") as f: buf = TTransport.TFileObjectTransport(f) buf.write(buffer) buf.flush() buf.close() with open(datatxt_path, "rb") as f: buf = TTransport.TFileObjectTransport(f) value = buf.read(len(buffer)).decode('utf-8') self.assertEqual(buffer, value) buf.close() os.remove(datatxt_path) class TestMemoryBuffer(unittest.TestCase): def test_memorybuffer_write(self): data = '{"1":[1,"hello"],"a":{"A":"abc"},"bool":true,"num":12345}' buffer_w = TTransport.TMemoryBuffer() buffer_w.write(data.encode('utf-8')) value = buffer_w.getvalue() self.assertEqual(value.decode('utf-8'), data) buffer_w.close() def test_memorybuffer_read(self): data = '{"1":[1, "hello"],"a":{"A":"abc"},"bool":true,"num":12345}' buffer_r = TTransport.TMemoryBuffer(data.encode('utf-8')) value_r = buffer_r.read(len(data)) value = buffer_r.getvalue() self.assertEqual(value.decode('utf-8'), data) self.assertEqual(value_r.decode('utf-8'), data) buffer_r.close() if __name__ == '__main__': unittest.main() thrift-0.16.0/lib/rb/000077500000000000000000000000001420101504100142335ustar00rootroot00000000000000thrift-0.16.0/lib/rb/Gemfile000066400000000000000000000000471420101504100155270ustar00rootroot00000000000000source "http://rubygems.org" gemspec thrift-0.16.0/lib/rb/Makefile.am000077500000000000000000000023601420101504100162730ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # DESTDIR ?= / if HAVE_BUNDLER all-local: $(BUNDLER) install $(BUNDLER) exec rake build_ext install-exec-hook: $(BUNDLER) exec rake install clean-local: $(BUNDLER) install $(BUNDLER) exec rake clean $(RM) -r spec/gen-rb/ check-local: all $(BUNDLER) install $(BUNDLER) exec rake endif dist-hook: $(RM) -r $(distdir)/spec/gen-rb/ EXTRA_DIST = \ coding_standards.md \ Rakefile \ Gemfile \ thrift.gemspec \ lib \ ext \ benchmark \ script \ spec \ README.md thrift-0.16.0/lib/rb/README.md000066400000000000000000000026731420101504100155220ustar00rootroot00000000000000Thrift Ruby Software Library http://thrift.apache.org == LICENSE: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. == DESCRIPTION: Thrift is a strongly-typed language-agnostic RPC system. This library is the ruby implementation for both clients and servers. == INSTALL: $ gem install thrift == CAVEATS: This library provides the client and server implementations of thrift. It does not provide the compiler for the .thrift files. To compile .thrift files into language-specific implementations, please download the full thrift software package. == USAGE: This section should get written by someone with the time and inclination. In the meantime, look at existing code, such as the benchmark or the tutorial in the full thrift distribution. thrift-0.16.0/lib/rb/Rakefile000066400000000000000000000075441420101504100157120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'rubygems' require 'rake' require 'rake/clean' require 'rspec/core/rake_task' THRIFT = '../../compiler/cpp/thrift' task :default => [:gem] task :spec => [:'gen-rb', :build_ext, :realspec] RSpec::Core::RakeTask.new(:realspec) do |t| t.rspec_opts = ['--color', '--format d'] end RSpec::Core::RakeTask.new(:'spec:rcov') do |t| t.rspec_opts = ['--color', '--format d'] t.rcov = true t.rcov_opts = ['--exclude', '^spec,/gems/'] end desc 'Compile the .thrift files for the specs' task :'gen-rb' => [:'gen-rb:spec', :'gen-rb:namespaced_spec', :'gen-rb:flat_spec', :'gen-rb:benchmark', :'gen-rb:debug_proto'] namespace :'gen-rb' do task :'spec' do dir = File.dirname(__FILE__) + '/spec' sh THRIFT, '--gen', 'rb', '-o', dir, "#{dir}/ThriftSpec.thrift" end task :'namespaced_spec' do dir = File.dirname(__FILE__) + '/spec' sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/ThriftNamespacedSpec.thrift" sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/BaseService.thrift" sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/ExtendedService.thrift" end task :'flat_spec' do dir = File.dirname(__FILE__) + '/spec' FileUtils.mkdir_p("#{dir}/gen-rb/flat") sh THRIFT, '--gen', 'rb', '--recurse', '-out', "#{dir}/gen-rb/flat", "#{dir}/ThriftNamespacedSpec.thrift" end task :'benchmark' do dir = File.dirname(__FILE__) + '/benchmark' sh THRIFT, '--gen', 'rb', '-o', dir, "#{dir}/Benchmark.thrift" end task :'debug_proto' do sh "mkdir", "-p", "test/debug_proto" sh THRIFT, '--gen', 'rb', "-o", "test/debug_proto", "../../test/DebugProtoTest.thrift" end end desc "Build the native library" task :build_ext => :'gen-rb' do next if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ Dir::chdir(File::dirname('ext/extconf.rb')) do unless sh "ruby #{File::basename('ext/extconf.rb')}" $stderr.puts "Failed to run extconf" break end unless sh "make" $stderr.puts "make failed" break end end end desc 'Run the compiler tests (requires full thrift checkout)' task :test do # ensure this is a full thrift checkout and not a tarball of the ruby libs cmd = 'head -1 ../../README.md 2>/dev/null | grep Thrift >/dev/null 2>/dev/null' system(cmd) or fail "rake test requires a full thrift checkout" sh 'make', '-C', File.dirname(__FILE__) + "/../../test/rb", "check" end desc 'Run benchmarking of NonblockingServer' task :benchmark do ruby 'benchmark/benchmark.rb' end desc 'Builds the thrift gem' task :gem => [:spec, :build_ext] do unless sh 'gem', 'build', 'thrift.gemspec' $stderr.puts "Failed to build thrift gem" break end end desc 'Install the thrift gem' task :install => [:gem] do unless sh 'gem', 'install', Dir.glob('thrift-*.gem').last $stderr.puts "Failed to install thrift gem" break end end CLEAN.include [ '.bundle', 'benchmark/gen-rb', 'coverage', 'ext/*.{o,bundle,so,dll}', 'ext/mkmf.log', 'ext/Makefile', 'ext/conftest.dSYM', 'Gemfile.lock', 'mkmf.log', 'pkg', 'spec/gen-rb', 'test', 'thrift-*.gem' ] thrift-0.16.0/lib/rb/benchmark/000077500000000000000000000000001420101504100161655ustar00rootroot00000000000000thrift-0.16.0/lib/rb/benchmark/Benchmark.thrift000066400000000000000000000015471420101504100213100ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # namespace rb ThriftBenchmark service BenchmarkService { i32 fibonacci(1:byte n) } thrift-0.16.0/lib/rb/benchmark/benchmark.rb000066400000000000000000000207741420101504100204560ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'rubygems' $:.unshift File.dirname(__FILE__) + '/../lib' require 'thrift' require 'stringio' HOST = '127.0.0.1' PORT = 42587 ############### ## Server ############### class Server attr_accessor :serverclass attr_accessor :interpreter attr_accessor :host attr_accessor :port def initialize(opts) @serverclass = opts.fetch(:class, Thrift::NonblockingServer) @interpreter = opts.fetch(:interpreter, "ruby") @host = opts.fetch(:host, ::HOST) @port = opts.fetch(:port, ::PORT) end def start return if @serverclass == Object args = (File.basename(@interpreter) == "jruby" ? "-J-server" : "") @pipe = IO.popen("#{@interpreter} #{args} #{File.dirname(__FILE__)}/server.rb #{@host} #{@port} #{@serverclass.name}", "r+") Marshal.load(@pipe) # wait until the server has started sleep 0.4 # give the server time to actually start spawning sockets end def shutdown return unless @pipe Marshal.dump(:shutdown, @pipe) begin @pipe.read(10) # block until the server shuts down rescue EOFError end @pipe.close @pipe = nil end end class BenchmarkManager def initialize(opts, server) @socket = opts.fetch(:socket) do @host = opts.fetch(:host, 'localhost') @port = opts.fetch(:port) nil end @num_processes = opts.fetch(:num_processes, 40) @clients_per_process = opts.fetch(:clients_per_process, 10) @calls_per_client = opts.fetch(:calls_per_client, 50) @interpreter = opts.fetch(:interpreter, "ruby") @server = server @log_exceptions = opts.fetch(:log_exceptions, false) end def run @pool = [] @benchmark_start = Time.now puts "Spawning benchmark processes..." @num_processes.times do spawn sleep 0.02 # space out spawns end collect_output @benchmark_end = Time.now # we know the procs are done here translate_output analyze_output report_output end def spawn pipe = IO.popen("#{@interpreter} #{File.dirname(__FILE__)}/client.rb #{"-log-exceptions" if @log_exceptions} #{@host} #{@port} #{@clients_per_process} #{@calls_per_client}") @pool << pipe end def socket_class if @socket Thrift::UNIXSocket else Thrift::Socket end end def collect_output puts "Collecting output..." # read from @pool until all sockets are closed @buffers = Hash.new { |h,k| h[k] = '' } until @pool.empty? rd, = select(@pool) next if rd.nil? rd.each do |fd| begin @buffers[fd] << fd.readpartial(4096) rescue EOFError @pool.delete fd end end end end def translate_output puts "Translating output..." @output = [] @buffers.each do |fd, buffer| strio = StringIO.new(buffer) logs = [] begin loop do logs << Marshal.load(strio) end rescue EOFError @output << logs end end end def analyze_output puts "Analyzing output..." call_times = [] client_times = [] connection_failures = [] connection_errors = [] shortest_call = 0 shortest_client = 0 longest_call = 0 longest_client = 0 @output.each do |logs| cur_call, cur_client = nil logs.each do |tok, time| case tok when :start cur_client = time when :call_start cur_call = time when :call_end delta = time - cur_call call_times << delta longest_call = delta unless longest_call > delta shortest_call = delta if shortest_call == 0 or delta < shortest_call cur_call = nil when :end delta = time - cur_client client_times << delta longest_client = delta unless longest_client > delta shortest_client = delta if shortest_client == 0 or delta < shortest_client cur_client = nil when :connection_failure connection_failures << time when :connection_error connection_errors << time end end end @report = {} @report[:total_calls] = call_times.inject(0.0) { |a,t| a += t } @report[:avg_calls] = @report[:total_calls] / call_times.size @report[:total_clients] = client_times.inject(0.0) { |a,t| a += t } @report[:avg_clients] = @report[:total_clients] / client_times.size @report[:connection_failures] = connection_failures.size @report[:connection_errors] = connection_errors.size @report[:shortest_call] = shortest_call @report[:shortest_client] = shortest_client @report[:longest_call] = longest_call @report[:longest_client] = longest_client @report[:total_benchmark_time] = @benchmark_end - @benchmark_start @report[:fastthread] = $".include?('fastthread.bundle') end def report_output fmt = "%.4f seconds" puts tabulate "%d", [["Server class", "%s"], @server.serverclass == Object ? "" : @server.serverclass], [["Server interpreter", "%s"], @server.interpreter], [["Client interpreter", "%s"], @interpreter], [["Socket class", "%s"], socket_class], ["Number of processes", @num_processes], ["Clients per process", @clients_per_process], ["Calls per client", @calls_per_client], [["Using fastthread", "%s"], @report[:fastthread] ? "yes" : "no"] puts failures = (@report[:connection_failures] > 0) tabulate fmt, [["Connection failures", "%d", [:red, :bold]], @report[:connection_failures]], [["Connection errors", "%d", [:red, :bold]], @report[:connection_errors]], ["Average time per call", @report[:avg_calls]], ["Average time per client (%d calls)" % @calls_per_client, @report[:avg_clients]], ["Total time for all calls", @report[:total_calls]], ["Real time for benchmarking", @report[:total_benchmark_time]], ["Shortest call time", @report[:shortest_call]], ["Longest call time", @report[:longest_call]], ["Shortest client time (%d calls)" % @calls_per_client, @report[:shortest_client]], ["Longest client time (%d calls)" % @calls_per_client, @report[:longest_client]] end ANSI = { :reset => 0, :bold => 1, :black => 30, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36, :white => 37 } def tabulate(fmt, *labels_and_values) labels = labels_and_values.map { |l| Array === l ? l.first : l } label_width = labels.inject(0) { |w,l| l.size > w ? l.size : w } labels_and_values.each do |(l,v)| f = fmt l, f, c = l if Array === l fmtstr = "%-#{label_width+1}s #{f}" if STDOUT.tty? and c and v.to_i > 0 fmtstr = "\e[#{[*c].map { |x| ANSI[x] } * ";"}m" + fmtstr + "\e[#{ANSI[:reset]}m" end puts fmtstr % [l+":", v] end end end def resolve_const(const) const and const.split('::').inject(Object) { |k,c| k.const_get(c) } end puts "Starting server..." args = {} args[:interpreter] = ENV['THRIFT_SERVER_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby" args[:class] = resolve_const(ENV['THRIFT_SERVER']) || Thrift::NonblockingServer args[:host] = ENV['THRIFT_HOST'] || HOST args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i server = Server.new(args) server.start args = {} args[:host] = ENV['THRIFT_HOST'] || HOST args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i args[:num_processes] = (ENV['THRIFT_NUM_PROCESSES'] || 40).to_i args[:clients_per_process] = (ENV['THRIFT_NUM_CLIENTS'] || 5).to_i args[:calls_per_client] = (ENV['THRIFT_NUM_CALLS'] || 50).to_i args[:interpreter] = ENV['THRIFT_CLIENT_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby" args[:log_exceptions] = !!ENV['THRIFT_LOG_EXCEPTIONS'] BenchmarkManager.new(args, server).run server.shutdown thrift-0.16.0/lib/rb/benchmark/client.rb000066400000000000000000000047261420101504100200010ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # $:.unshift File.dirname(__FILE__) + '/../lib' require 'thrift' $:.unshift File.dirname(__FILE__) + "/gen-rb" require 'benchmark_service' class Client def initialize(host, port, clients_per_process, calls_per_client, log_exceptions) @host = host @port = port @clients_per_process = clients_per_process @calls_per_client = calls_per_client @log_exceptions = log_exceptions end def run @clients_per_process.times do socket = Thrift::Socket.new(@host, @port) transport = Thrift::FramedTransport.new(socket) protocol = Thrift::BinaryProtocol.new(transport) client = ThriftBenchmark::BenchmarkService::Client.new(protocol) begin start = Time.now transport.open Marshal.dump [:start, start], STDOUT rescue => e Marshal.dump [:connection_failure, Time.now], STDOUT print_exception e if @log_exceptions else begin @calls_per_client.times do Marshal.dump [:call_start, Time.now], STDOUT client.fibonacci(15) Marshal.dump [:call_end, Time.now], STDOUT end transport.close Marshal.dump [:end, Time.now], STDOUT rescue Thrift::TransportException => e Marshal.dump [:connection_error, Time.now], STDOUT print_exception e if @log_exceptions end end end end def print_exception(e) STDERR.puts "ERROR: #{e.message}" STDERR.puts "\t#{e.backtrace * "\n\t"}" end end log_exceptions = true if ARGV[0] == '-log-exceptions' and ARGV.shift host, port, clients_per_process, calls_per_client = ARGV Client.new(host, port.to_i, clients_per_process.to_i, calls_per_client.to_i, log_exceptions).run thrift-0.16.0/lib/rb/benchmark/server.rb000066400000000000000000000045101420101504100200200ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # $:.unshift File.dirname(__FILE__) + '/../lib' require 'thrift' $:.unshift File.dirname(__FILE__) + "/gen-rb" require 'benchmark_service' module Server include Thrift class BenchmarkHandler # 1-based index into the fibonacci sequence def fibonacci(n) seq = [1, 1] 3.upto(n) do seq << seq[-1] + seq[-2] end seq[n-1] # n is 1-based end end def self.start_server(host, port, serverClass) handler = BenchmarkHandler.new processor = ThriftBenchmark::BenchmarkService::Processor.new(handler) transport = ServerSocket.new(host, port) transport_factory = FramedTransportFactory.new args = [processor, transport, transport_factory, nil, 20] if serverClass == NonblockingServer logger = Logger.new(STDERR) logger.level = Logger::WARN args << logger end server = serverClass.new(*args) @server_thread = Thread.new do server.serve end @server = server end def self.shutdown return if @server.nil? if @server.respond_to? :shutdown @server.shutdown else @server_thread.kill end end end def resolve_const(const) const and const.split('::').inject(Object) { |k,c| k.const_get(c) } end host, port, serverklass = ARGV Server.start_server(host, port.to_i, resolve_const(serverklass)) # let our host know that the interpreter has started # ideally we'd wait until the server was serving, but we don't have a hook for that Marshal.dump(:started, STDOUT) STDOUT.flush Marshal.load(STDIN) # wait until we're instructed to shut down Server.shutdown thrift-0.16.0/lib/rb/benchmark/thin_server.rb000066400000000000000000000027471420101504100210540ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # $:.unshift File.dirname(__FILE__) + '/../lib' require 'thrift' $:.unshift File.dirname(__FILE__) + "/gen-rb" require 'benchmark_service' HOST = 'localhost' PORT = 42587 class BenchmarkHandler # 1-based index into the fibonacci sequence def fibonacci(n) seq = [1, 1] 3.upto(n) do seq << seq[-1] + seq[-2] end seq[n-1] # n is 1-based end end handler = BenchmarkHandler.new processor = ThriftBenchmark::BenchmarkService::Processor.new(handler) transport = Thrift::ServerSocket.new(HOST, PORT) transport_factory = Thrift::FramedTransportFactory.new logger = Logger.new(STDERR) logger.level = Logger::WARN Thrift::NonblockingServer.new(processor, transport, transport_factory, nil, 20, logger).serve thrift-0.16.0/lib/rb/coding_standards.md000066400000000000000000000001031420101504100200550ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/rb/ext/000077500000000000000000000000001420101504100150335ustar00rootroot00000000000000thrift-0.16.0/lib/rb/ext/binary_protocol_accelerated.c000066400000000000000000000365461420101504100227360ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include VALUE rb_thrift_binary_proto_native_qmark(VALUE self) { return Qtrue; } static int VERSION_1; static int VERSION_MASK; static int TYPE_MASK; static int BAD_VERSION; static ID rbuf_ivar_id; static void write_byte_direct(VALUE trans, int8_t b) { WRITE(trans, (char*)&b, 1); } static void write_i16_direct(VALUE trans, int16_t value) { char data[2]; data[1] = value; data[0] = (value >> 8); WRITE(trans, data, 2); } static void write_i32_direct(VALUE trans, int32_t value) { char data[4]; data[3] = value; data[2] = (value >> 8); data[1] = (value >> 16); data[0] = (value >> 24); WRITE(trans, data, 4); } static void write_i64_direct(VALUE trans, int64_t value) { char data[8]; data[7] = value; data[6] = (value >> 8); data[5] = (value >> 16); data[4] = (value >> 24); data[3] = (value >> 32); data[2] = (value >> 40); data[1] = (value >> 48); data[0] = (value >> 56); WRITE(trans, data, 8); } static void write_string_direct(VALUE trans, VALUE str) { if (TYPE(str) != T_STRING) { rb_raise(rb_eStandardError, "Value should be a string"); } str = convert_to_utf8_byte_buffer(str); write_i32_direct(trans, RSTRING_LEN(str)); rb_funcall(trans, write_method_id, 1, str); } //-------------------------------- // interface writing methods //-------------------------------- VALUE rb_thrift_binary_proto_write_message_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_write_struct_begin(VALUE self, VALUE name) { return Qnil; } VALUE rb_thrift_binary_proto_write_struct_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_write_field_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_write_map_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_write_list_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_write_set_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) { VALUE trans = GET_TRANSPORT(self); VALUE strict_write = GET_STRICT_WRITE(self); if (strict_write == Qtrue) { write_i32_direct(trans, VERSION_1 | FIX2INT(type)); write_string_direct(trans, name); write_i32_direct(trans, FIX2INT(seqid)); } else { write_string_direct(trans, name); write_byte_direct(trans, FIX2INT(type)); write_i32_direct(trans, FIX2INT(seqid)); } return Qnil; } VALUE rb_thrift_binary_proto_write_field_begin(VALUE self, VALUE name, VALUE type, VALUE id) { VALUE trans = GET_TRANSPORT(self); write_byte_direct(trans, FIX2INT(type)); write_i16_direct(trans, FIX2INT(id)); return Qnil; } VALUE rb_thrift_binary_proto_write_field_stop(VALUE self) { write_byte_direct(GET_TRANSPORT(self), TTYPE_STOP); return Qnil; } VALUE rb_thrift_binary_proto_write_map_begin(VALUE self, VALUE ktype, VALUE vtype, VALUE size) { VALUE trans = GET_TRANSPORT(self); write_byte_direct(trans, FIX2INT(ktype)); write_byte_direct(trans, FIX2INT(vtype)); write_i32_direct(trans, FIX2INT(size)); return Qnil; } VALUE rb_thrift_binary_proto_write_list_begin(VALUE self, VALUE etype, VALUE size) { VALUE trans = GET_TRANSPORT(self); write_byte_direct(trans, FIX2INT(etype)); write_i32_direct(trans, FIX2INT(size)); return Qnil; } VALUE rb_thrift_binary_proto_write_set_begin(VALUE self, VALUE etype, VALUE size) { rb_thrift_binary_proto_write_list_begin(self, etype, size); return Qnil; } VALUE rb_thrift_binary_proto_write_bool(VALUE self, VALUE b) { write_byte_direct(GET_TRANSPORT(self), RTEST(b) ? 1 : 0); return Qnil; } VALUE rb_thrift_binary_proto_write_byte(VALUE self, VALUE byte) { CHECK_NIL(byte); write_byte_direct(GET_TRANSPORT(self), NUM2INT(byte)); return Qnil; } VALUE rb_thrift_binary_proto_write_i16(VALUE self, VALUE i16) { CHECK_NIL(i16); write_i16_direct(GET_TRANSPORT(self), FIX2INT(i16)); return Qnil; } VALUE rb_thrift_binary_proto_write_i32(VALUE self, VALUE i32) { CHECK_NIL(i32); write_i32_direct(GET_TRANSPORT(self), NUM2INT(i32)); return Qnil; } VALUE rb_thrift_binary_proto_write_i64(VALUE self, VALUE i64) { CHECK_NIL(i64); write_i64_direct(GET_TRANSPORT(self), NUM2LL(i64)); return Qnil; } VALUE rb_thrift_binary_proto_write_double(VALUE self, VALUE dub) { CHECK_NIL(dub); // Unfortunately, bitwise_cast doesn't work in C. Bad C! union { double f; int64_t t; } transfer; transfer.f = RFLOAT_VALUE(rb_Float(dub)); write_i64_direct(GET_TRANSPORT(self), transfer.t); return Qnil; } VALUE rb_thrift_binary_proto_write_string(VALUE self, VALUE str) { CHECK_NIL(str); VALUE trans = GET_TRANSPORT(self); write_string_direct(trans, str); return Qnil; } VALUE rb_thrift_binary_proto_write_binary(VALUE self, VALUE buf) { CHECK_NIL(buf); VALUE trans = GET_TRANSPORT(self); buf = force_binary_encoding(buf); write_i32_direct(trans, RSTRING_LEN(buf)); rb_funcall(trans, write_method_id, 1, buf); return Qnil; } //--------------------------------------- // interface reading methods //--------------------------------------- VALUE rb_thrift_binary_proto_read_string(VALUE self); VALUE rb_thrift_binary_proto_read_binary(VALUE self); VALUE rb_thrift_binary_proto_read_byte(VALUE self); VALUE rb_thrift_binary_proto_read_i32(VALUE self); VALUE rb_thrift_binary_proto_read_i16(VALUE self); static char read_byte_direct(VALUE self) { VALUE byte = rb_funcall(GET_TRANSPORT(self), read_byte_method_id, 0); return (char)(FIX2INT(byte)); } static int16_t read_i16_direct(VALUE self) { VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(2)); return (int16_t)(((uint8_t)(RSTRING_PTR(rbuf)[1])) | ((uint16_t)((RSTRING_PTR(rbuf)[0]) << 8))); } static int32_t read_i32_direct(VALUE self) { VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(4)); return ((uint8_t)(RSTRING_PTR(rbuf)[3])) | (((uint8_t)(RSTRING_PTR(rbuf)[2])) << 8) | (((uint8_t)(RSTRING_PTR(rbuf)[1])) << 16) | (((uint8_t)(RSTRING_PTR(rbuf)[0])) << 24); } static int64_t read_i64_direct(VALUE self) { VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(8)); uint64_t hi = ((uint8_t)(RSTRING_PTR(rbuf)[3])) | (((uint8_t)(RSTRING_PTR(rbuf)[2])) << 8) | (((uint8_t)(RSTRING_PTR(rbuf)[1])) << 16) | (((uint8_t)(RSTRING_PTR(rbuf)[0])) << 24); uint32_t lo = ((uint8_t)(RSTRING_PTR(rbuf)[7])) | (((uint8_t)(RSTRING_PTR(rbuf)[6])) << 8) | (((uint8_t)(RSTRING_PTR(rbuf)[5])) << 16) | (((uint8_t)(RSTRING_PTR(rbuf)[4])) << 24); return (hi << 32) | lo; } static VALUE get_protocol_exception(VALUE code, VALUE message) { VALUE args[2]; args[0] = code; args[1] = message; return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class); } VALUE rb_thrift_binary_proto_read_message_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_read_struct_begin(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_read_struct_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_read_field_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_read_map_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_read_list_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_read_set_end(VALUE self) { return Qnil; } VALUE rb_thrift_binary_proto_read_message_begin(VALUE self) { VALUE strict_read = GET_STRICT_READ(self); VALUE name, seqid; int type; int version = read_i32_direct(self); if (version < 0) { if ((version & VERSION_MASK) != VERSION_1) { rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("Missing version identifier"))); } type = version & TYPE_MASK; name = rb_thrift_binary_proto_read_string(self); seqid = rb_thrift_binary_proto_read_i32(self); } else { if (strict_read == Qtrue) { rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("No version identifier, old protocol client?"))); } name = READ(self, version); type = read_byte_direct(self); seqid = rb_thrift_binary_proto_read_i32(self); } return rb_ary_new3(3, name, INT2FIX(type), seqid); } VALUE rb_thrift_binary_proto_read_field_begin(VALUE self) { int type = read_byte_direct(self); if (type == TTYPE_STOP) { return rb_ary_new3(3, Qnil, INT2FIX(type), INT2FIX(0)); } else { VALUE id = rb_thrift_binary_proto_read_i16(self); return rb_ary_new3(3, Qnil, INT2FIX(type), id); } } VALUE rb_thrift_binary_proto_read_map_begin(VALUE self) { VALUE ktype = rb_thrift_binary_proto_read_byte(self); VALUE vtype = rb_thrift_binary_proto_read_byte(self); VALUE size = rb_thrift_binary_proto_read_i32(self); return rb_ary_new3(3, ktype, vtype, size); } VALUE rb_thrift_binary_proto_read_list_begin(VALUE self) { VALUE etype = rb_thrift_binary_proto_read_byte(self); VALUE size = rb_thrift_binary_proto_read_i32(self); return rb_ary_new3(2, etype, size); } VALUE rb_thrift_binary_proto_read_set_begin(VALUE self) { return rb_thrift_binary_proto_read_list_begin(self); } VALUE rb_thrift_binary_proto_read_bool(VALUE self) { char byte = read_byte_direct(self); return byte != 0 ? Qtrue : Qfalse; } VALUE rb_thrift_binary_proto_read_byte(VALUE self) { return INT2FIX(read_byte_direct(self)); } VALUE rb_thrift_binary_proto_read_i16(VALUE self) { return INT2FIX(read_i16_direct(self)); } VALUE rb_thrift_binary_proto_read_i32(VALUE self) { return INT2NUM(read_i32_direct(self)); } VALUE rb_thrift_binary_proto_read_i64(VALUE self) { return LL2NUM(read_i64_direct(self)); } VALUE rb_thrift_binary_proto_read_double(VALUE self) { union { double f; int64_t t; } transfer; transfer.t = read_i64_direct(self); return rb_float_new(transfer.f); } VALUE rb_thrift_binary_proto_read_string(VALUE self) { VALUE buffer = rb_thrift_binary_proto_read_binary(self); return convert_to_string(buffer); } VALUE rb_thrift_binary_proto_read_binary(VALUE self) { int size = read_i32_direct(self); return READ(self, size); } void Init_binary_protocol_accelerated() { VALUE thrift_binary_protocol_class = rb_const_get(thrift_module, rb_intern("BinaryProtocol")); VERSION_1 = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_1"))); VERSION_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_MASK"))); TYPE_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("TYPE_MASK"))); VALUE bpa_class = rb_define_class_under(thrift_module, "BinaryProtocolAccelerated", thrift_binary_protocol_class); rb_define_method(bpa_class, "native?", rb_thrift_binary_proto_native_qmark, 0); rb_define_method(bpa_class, "write_message_begin", rb_thrift_binary_proto_write_message_begin, 3); rb_define_method(bpa_class, "write_field_begin", rb_thrift_binary_proto_write_field_begin, 3); rb_define_method(bpa_class, "write_field_stop", rb_thrift_binary_proto_write_field_stop, 0); rb_define_method(bpa_class, "write_map_begin", rb_thrift_binary_proto_write_map_begin, 3); rb_define_method(bpa_class, "write_list_begin", rb_thrift_binary_proto_write_list_begin, 2); rb_define_method(bpa_class, "write_set_begin", rb_thrift_binary_proto_write_set_begin, 2); rb_define_method(bpa_class, "write_byte", rb_thrift_binary_proto_write_byte, 1); rb_define_method(bpa_class, "write_bool", rb_thrift_binary_proto_write_bool, 1); rb_define_method(bpa_class, "write_i16", rb_thrift_binary_proto_write_i16, 1); rb_define_method(bpa_class, "write_i32", rb_thrift_binary_proto_write_i32, 1); rb_define_method(bpa_class, "write_i64", rb_thrift_binary_proto_write_i64, 1); rb_define_method(bpa_class, "write_double", rb_thrift_binary_proto_write_double, 1); rb_define_method(bpa_class, "write_string", rb_thrift_binary_proto_write_string, 1); rb_define_method(bpa_class, "write_binary", rb_thrift_binary_proto_write_binary, 1); // unused methods rb_define_method(bpa_class, "write_message_end", rb_thrift_binary_proto_write_message_end, 0); rb_define_method(bpa_class, "write_struct_begin", rb_thrift_binary_proto_write_struct_begin, 1); rb_define_method(bpa_class, "write_struct_end", rb_thrift_binary_proto_write_struct_end, 0); rb_define_method(bpa_class, "write_field_end", rb_thrift_binary_proto_write_field_end, 0); rb_define_method(bpa_class, "write_map_end", rb_thrift_binary_proto_write_map_end, 0); rb_define_method(bpa_class, "write_list_end", rb_thrift_binary_proto_write_list_end, 0); rb_define_method(bpa_class, "write_set_end", rb_thrift_binary_proto_write_set_end, 0); rb_define_method(bpa_class, "read_message_begin", rb_thrift_binary_proto_read_message_begin, 0); rb_define_method(bpa_class, "read_field_begin", rb_thrift_binary_proto_read_field_begin, 0); rb_define_method(bpa_class, "read_map_begin", rb_thrift_binary_proto_read_map_begin, 0); rb_define_method(bpa_class, "read_list_begin", rb_thrift_binary_proto_read_list_begin, 0); rb_define_method(bpa_class, "read_set_begin", rb_thrift_binary_proto_read_set_begin, 0); rb_define_method(bpa_class, "read_byte", rb_thrift_binary_proto_read_byte, 0); rb_define_method(bpa_class, "read_bool", rb_thrift_binary_proto_read_bool, 0); rb_define_method(bpa_class, "read_i16", rb_thrift_binary_proto_read_i16, 0); rb_define_method(bpa_class, "read_i32", rb_thrift_binary_proto_read_i32, 0); rb_define_method(bpa_class, "read_i64", rb_thrift_binary_proto_read_i64, 0); rb_define_method(bpa_class, "read_double", rb_thrift_binary_proto_read_double, 0); rb_define_method(bpa_class, "read_string", rb_thrift_binary_proto_read_string, 0); rb_define_method(bpa_class, "read_binary", rb_thrift_binary_proto_read_binary, 0); // unused methods rb_define_method(bpa_class, "read_message_end", rb_thrift_binary_proto_read_message_end, 0); rb_define_method(bpa_class, "read_struct_begin", rb_thrift_binary_proto_read_struct_begin, 0); rb_define_method(bpa_class, "read_struct_end", rb_thrift_binary_proto_read_struct_end, 0); rb_define_method(bpa_class, "read_field_end", rb_thrift_binary_proto_read_field_end, 0); rb_define_method(bpa_class, "read_map_end", rb_thrift_binary_proto_read_map_end, 0); rb_define_method(bpa_class, "read_list_end", rb_thrift_binary_proto_read_list_end, 0); rb_define_method(bpa_class, "read_set_end", rb_thrift_binary_proto_read_set_end, 0); rbuf_ivar_id = rb_intern("@rbuf"); } thrift-0.16.0/lib/rb/ext/binary_protocol_accelerated.h000066400000000000000000000015161420101504100227300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ void Init_binary_protocol_accelerated(); thrift-0.16.0/lib/rb/ext/bytes.c000066400000000000000000000024251420101504100163300ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #ifdef HAVE_RUBY_ENCODING_H #include #endif #include VALUE force_binary_encoding(VALUE buffer) { return rb_funcall(thrift_bytes_module, force_binary_encoding_id, 1, buffer); } VALUE convert_to_utf8_byte_buffer(VALUE string) { return rb_funcall(thrift_bytes_module, convert_to_utf8_byte_buffer_id, 1, string); } VALUE convert_to_string(VALUE utf8_buffer) { return rb_funcall(thrift_bytes_module, convert_to_string_id, 1, utf8_buffer); } thrift-0.16.0/lib/rb/ext/bytes.h000066400000000000000000000021721420101504100163340ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include /* * A collection of utilities for working with bytes and byte buffers. * * These methods are the native analogies to some of the methods in * Thrift::Bytes (thrift/bytes.rb). */ VALUE force_binary_encoding(VALUE buffer); VALUE convert_to_utf8_byte_buffer(VALUE string); VALUE convert_to_string(VALUE utf8_buffer); thrift-0.16.0/lib/rb/ext/compact_protocol.c000066400000000000000000000550041420101504100205520ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #define LAST_ID(obj) FIX2INT(rb_ary_pop(rb_ivar_get(obj, last_field_id))) #define SET_LAST_ID(obj, val) rb_ary_push(rb_ivar_get(obj, last_field_id), val) VALUE rb_thrift_compact_proto_native_qmark(VALUE self) { return Qtrue; } static ID last_field_id; static ID boolean_field_id; static ID bool_value_id; static ID rbuf_ivar_id; static int VERSION; static int VERSION_MASK; static int TYPE_MASK; static int TYPE_BITS; static int TYPE_SHIFT_AMOUNT; static int PROTOCOL_ID; static VALUE thrift_compact_protocol_class; static int CTYPE_BOOLEAN_TRUE = 0x01; static int CTYPE_BOOLEAN_FALSE = 0x02; static int CTYPE_BYTE = 0x03; static int CTYPE_I16 = 0x04; static int CTYPE_I32 = 0x05; static int CTYPE_I64 = 0x06; static int CTYPE_DOUBLE = 0x07; static int CTYPE_BINARY = 0x08; static int CTYPE_LIST = 0x09; static int CTYPE_SET = 0x0A; static int CTYPE_MAP = 0x0B; static int CTYPE_STRUCT = 0x0C; VALUE rb_thrift_compact_proto_write_i16(VALUE self, VALUE i16); // TODO: implement this static int get_compact_type(VALUE type_value) { int type = FIX2INT(type_value); if (type == TTYPE_BOOL) { return CTYPE_BOOLEAN_TRUE; } else if (type == TTYPE_BYTE) { return CTYPE_BYTE; } else if (type == TTYPE_I16) { return CTYPE_I16; } else if (type == TTYPE_I32) { return CTYPE_I32; } else if (type == TTYPE_I64) { return CTYPE_I64; } else if (type == TTYPE_DOUBLE) { return CTYPE_DOUBLE; } else if (type == TTYPE_STRING) { return CTYPE_BINARY; } else if (type == TTYPE_LIST) { return CTYPE_LIST; } else if (type == TTYPE_SET) { return CTYPE_SET; } else if (type == TTYPE_MAP) { return CTYPE_MAP; } else if (type == TTYPE_STRUCT) { return CTYPE_STRUCT; } else { char str[50]; sprintf(str, "don't know what type: %d", type); rb_raise(rb_eStandardError, "%s", str); return 0; } } static void write_byte_direct(VALUE transport, int8_t b) { WRITE(transport, (char*)&b, 1); } static void write_field_begin_internal(VALUE self, VALUE type, VALUE id_value, VALUE type_override) { int id = FIX2INT(id_value); int last_id = LAST_ID(self); VALUE transport = GET_TRANSPORT(self); // if there's a type override, use that. int8_t type_to_write = RTEST(type_override) ? FIX2INT(type_override) : get_compact_type(type); // check if we can use delta encoding for the field id int diff = id - last_id; if (diff > 0 && diff <= 15) { // write them together write_byte_direct(transport, diff << 4 | (type_to_write & 0x0f)); } else { // write them separate write_byte_direct(transport, type_to_write & 0x0f); rb_thrift_compact_proto_write_i16(self, id_value); } SET_LAST_ID(self, id_value); } static int32_t int_to_zig_zag(int32_t n) { return (n << 1) ^ (n >> 31); } static uint64_t ll_to_zig_zag(int64_t n) { return (n << 1) ^ (n >> 63); } static void write_varint32(VALUE transport, uint32_t n) { while (true) { if ((n & ~0x7F) == 0) { write_byte_direct(transport, n & 0x7f); break; } else { write_byte_direct(transport, (n & 0x7F) | 0x80); n = n >> 7; } } } static void write_varint64(VALUE transport, uint64_t n) { while (true) { if ((n & ~0x7F) == 0) { write_byte_direct(transport, n & 0x7f); break; } else { write_byte_direct(transport, (n & 0x7F) | 0x80); n = n >> 7; } } } static void write_collection_begin(VALUE transport, VALUE elem_type, VALUE size_value) { int size = FIX2INT(size_value); if (size <= 14) { write_byte_direct(transport, size << 4 | get_compact_type(elem_type)); } else { write_byte_direct(transport, 0xf0 | get_compact_type(elem_type)); write_varint32(transport, size); } } //-------------------------------- // interface writing methods //-------------------------------- VALUE rb_thrift_compact_proto_write_i32(VALUE self, VALUE i32); VALUE rb_thrift_compact_proto_write_string(VALUE self, VALUE str); VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf); VALUE rb_thrift_compact_proto_write_message_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_write_struct_begin(VALUE self, VALUE name) { rb_ary_push(rb_ivar_get(self, last_field_id), INT2FIX(0)); return Qnil; } VALUE rb_thrift_compact_proto_write_struct_end(VALUE self) { rb_ary_pop(rb_ivar_get(self, last_field_id)); return Qnil; } VALUE rb_thrift_compact_proto_write_field_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_write_map_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_write_list_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_write_set_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) { VALUE transport = GET_TRANSPORT(self); write_byte_direct(transport, PROTOCOL_ID); write_byte_direct(transport, (VERSION & VERSION_MASK) | ((FIX2INT(type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK)); write_varint32(transport, FIX2INT(seqid)); rb_thrift_compact_proto_write_string(self, name); return Qnil; } VALUE rb_thrift_compact_proto_write_field_begin(VALUE self, VALUE name, VALUE type, VALUE id) { if (FIX2INT(type) == TTYPE_BOOL) { // we want to possibly include the value, so we'll wait. rb_ivar_set(self, boolean_field_id, rb_ary_new3(2, type, id)); } else { write_field_begin_internal(self, type, id, Qnil); } return Qnil; } VALUE rb_thrift_compact_proto_write_field_stop(VALUE self) { write_byte_direct(GET_TRANSPORT(self), TTYPE_STOP); return Qnil; } VALUE rb_thrift_compact_proto_write_map_begin(VALUE self, VALUE ktype, VALUE vtype, VALUE size_value) { int size = FIX2INT(size_value); VALUE transport = GET_TRANSPORT(self); if (size == 0) { write_byte_direct(transport, 0); } else { write_varint32(transport, size); write_byte_direct(transport, get_compact_type(ktype) << 4 | get_compact_type(vtype)); } return Qnil; } VALUE rb_thrift_compact_proto_write_list_begin(VALUE self, VALUE etype, VALUE size) { write_collection_begin(GET_TRANSPORT(self), etype, size); return Qnil; } VALUE rb_thrift_compact_proto_write_set_begin(VALUE self, VALUE etype, VALUE size) { write_collection_begin(GET_TRANSPORT(self), etype, size); return Qnil; } VALUE rb_thrift_compact_proto_write_bool(VALUE self, VALUE b) { int8_t type = b == Qtrue ? CTYPE_BOOLEAN_TRUE : CTYPE_BOOLEAN_FALSE; VALUE boolean_field = rb_ivar_get(self, boolean_field_id); if (NIL_P(boolean_field)) { // we're not part of a field, so just write the value. write_byte_direct(GET_TRANSPORT(self), type); } else { // we haven't written the field header yet write_field_begin_internal(self, rb_ary_entry(boolean_field, 0), rb_ary_entry(boolean_field, 1), INT2FIX(type)); rb_ivar_set(self, boolean_field_id, Qnil); } return Qnil; } VALUE rb_thrift_compact_proto_write_byte(VALUE self, VALUE byte) { CHECK_NIL(byte); write_byte_direct(GET_TRANSPORT(self), FIX2INT(byte)); return Qnil; } VALUE rb_thrift_compact_proto_write_i16(VALUE self, VALUE i16) { rb_thrift_compact_proto_write_i32(self, i16); return Qnil; } VALUE rb_thrift_compact_proto_write_i32(VALUE self, VALUE i32) { CHECK_NIL(i32); write_varint32(GET_TRANSPORT(self), int_to_zig_zag(NUM2INT(i32))); return Qnil; } VALUE rb_thrift_compact_proto_write_i64(VALUE self, VALUE i64) { CHECK_NIL(i64); write_varint64(GET_TRANSPORT(self), ll_to_zig_zag(NUM2LL(i64))); return Qnil; } VALUE rb_thrift_compact_proto_write_double(VALUE self, VALUE dub) { CHECK_NIL(dub); // Unfortunately, bitwise_cast doesn't work in C. Bad C! union { double f; int64_t l; } transfer; transfer.f = RFLOAT_VALUE(rb_Float(dub)); char buf[8]; buf[0] = transfer.l & 0xff; buf[1] = (transfer.l >> 8) & 0xff; buf[2] = (transfer.l >> 16) & 0xff; buf[3] = (transfer.l >> 24) & 0xff; buf[4] = (transfer.l >> 32) & 0xff; buf[5] = (transfer.l >> 40) & 0xff; buf[6] = (transfer.l >> 48) & 0xff; buf[7] = (transfer.l >> 56) & 0xff; WRITE(GET_TRANSPORT(self), buf, 8); return Qnil; } VALUE rb_thrift_compact_proto_write_string(VALUE self, VALUE str) { str = convert_to_utf8_byte_buffer(str); rb_thrift_compact_proto_write_binary(self, str); return Qnil; } VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf) { buf = force_binary_encoding(buf); VALUE transport = GET_TRANSPORT(self); write_varint32(transport, RSTRING_LEN(buf)); WRITE(transport, StringValuePtr(buf), RSTRING_LEN(buf)); return Qnil; } //--------------------------------------- // interface reading methods //--------------------------------------- #define is_bool_type(ctype) (((ctype) & 0x0F) == CTYPE_BOOLEAN_TRUE || ((ctype) & 0x0F) == CTYPE_BOOLEAN_FALSE) VALUE rb_thrift_compact_proto_read_string(VALUE self); VALUE rb_thrift_compact_proto_read_binary(VALUE self); VALUE rb_thrift_compact_proto_read_byte(VALUE self); VALUE rb_thrift_compact_proto_read_i32(VALUE self); VALUE rb_thrift_compact_proto_read_i16(VALUE self); static int8_t get_ttype(int8_t ctype) { if (ctype == TTYPE_STOP) { return TTYPE_STOP; } else if (ctype == CTYPE_BOOLEAN_TRUE || ctype == CTYPE_BOOLEAN_FALSE) { return TTYPE_BOOL; } else if (ctype == CTYPE_BYTE) { return TTYPE_BYTE; } else if (ctype == CTYPE_I16) { return TTYPE_I16; } else if (ctype == CTYPE_I32) { return TTYPE_I32; } else if (ctype == CTYPE_I64) { return TTYPE_I64; } else if (ctype == CTYPE_DOUBLE) { return TTYPE_DOUBLE; } else if (ctype == CTYPE_BINARY) { return TTYPE_STRING; } else if (ctype == CTYPE_LIST) { return TTYPE_LIST; } else if (ctype == CTYPE_SET) { return TTYPE_SET; } else if (ctype == CTYPE_MAP) { return TTYPE_MAP; } else if (ctype == CTYPE_STRUCT) { return TTYPE_STRUCT; } else { char str[50]; sprintf(str, "don't know what type: %d", ctype); rb_raise(rb_eStandardError, "%s", str); return 0; } } static char read_byte_direct(VALUE self) { VALUE byte = rb_funcall(GET_TRANSPORT(self), read_byte_method_id, 0); return (char)(FIX2INT(byte)); } static int64_t zig_zag_to_ll(int64_t n) { return (((uint64_t)n) >> 1) ^ -(n & 1); } static int32_t zig_zag_to_int(int32_t n) { return (((uint32_t)n) >> 1) ^ -(n & 1); } static int64_t read_varint64(VALUE self) { int shift = 0; int64_t result = 0; while (true) { int8_t b = read_byte_direct(self); result = result | ((uint64_t)(b & 0x7f) << shift); if ((b & 0x80) != 0x80) { break; } shift += 7; } return result; } static int16_t read_i16(VALUE self) { return zig_zag_to_int((int32_t)read_varint64(self)); } static VALUE get_protocol_exception(VALUE code, VALUE message) { VALUE args[2]; args[0] = code; args[1] = message; return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class); } VALUE rb_thrift_compact_proto_read_message_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_read_struct_begin(VALUE self) { rb_ary_push(rb_ivar_get(self, last_field_id), INT2FIX(0)); return Qnil; } VALUE rb_thrift_compact_proto_read_struct_end(VALUE self) { rb_ary_pop(rb_ivar_get(self, last_field_id)); return Qnil; } VALUE rb_thrift_compact_proto_read_field_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_read_map_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_read_list_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_read_set_end(VALUE self) { return Qnil; } VALUE rb_thrift_compact_proto_read_message_begin(VALUE self) { int8_t protocol_id = read_byte_direct(self); if (protocol_id != PROTOCOL_ID) { char buf[100]; int len = sprintf(buf, "Expected protocol id %d but got %d", PROTOCOL_ID, protocol_id); buf[len] = 0; rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf))); } int8_t version_and_type = read_byte_direct(self); int8_t version = version_and_type & VERSION_MASK; if (version != VERSION) { char buf[100]; int len = sprintf(buf, "Expected version id %d but got %d", version, VERSION); buf[len] = 0; rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf))); } int8_t type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS; int32_t seqid = read_varint64(self); VALUE messageName = rb_thrift_compact_proto_read_string(self); return rb_ary_new3(3, messageName, INT2FIX(type), INT2NUM(seqid)); } VALUE rb_thrift_compact_proto_read_field_begin(VALUE self) { int8_t type = read_byte_direct(self); // if it's a stop, then we can return immediately, as the struct is over. if ((type & 0x0f) == TTYPE_STOP) { return rb_ary_new3(3, Qnil, INT2FIX(0), INT2FIX(0)); } else { int field_id = 0; // mask off the 4 MSB of the type header. it could contain a field id delta. uint8_t modifier = ((type & 0xf0) >> 4); if (modifier == 0) { // not a delta. look ahead for the zigzag varint field id. (void) LAST_ID(self); field_id = read_i16(self); } else { // has a delta. add the delta to the last read field id. field_id = LAST_ID(self) + modifier; } // if this happens to be a boolean field, the value is encoded in the type if (is_bool_type(type)) { // save the boolean value in a special instance variable. rb_ivar_set(self, bool_value_id, (type & 0x0f) == CTYPE_BOOLEAN_TRUE ? Qtrue : Qfalse); } // push the new field onto the field stack so we can keep the deltas going. SET_LAST_ID(self, INT2FIX(field_id)); return rb_ary_new3(3, Qnil, INT2FIX(get_ttype(type & 0x0f)), INT2FIX(field_id)); } } VALUE rb_thrift_compact_proto_read_map_begin(VALUE self) { int32_t size = read_varint64(self); uint8_t key_and_value_type = size == 0 ? 0 : read_byte_direct(self); return rb_ary_new3(3, INT2FIX(get_ttype(key_and_value_type >> 4)), INT2FIX(get_ttype(key_and_value_type & 0xf)), INT2FIX(size)); } VALUE rb_thrift_compact_proto_read_list_begin(VALUE self) { uint8_t size_and_type = read_byte_direct(self); int32_t size = (size_and_type >> 4) & 0x0f; if (size == 15) { size = read_varint64(self); } uint8_t type = get_ttype(size_and_type & 0x0f); return rb_ary_new3(2, INT2FIX(type), INT2FIX(size)); } VALUE rb_thrift_compact_proto_read_set_begin(VALUE self) { return rb_thrift_compact_proto_read_list_begin(self); } VALUE rb_thrift_compact_proto_read_bool(VALUE self) { VALUE bool_value = rb_ivar_get(self, bool_value_id); if (NIL_P(bool_value)) { return read_byte_direct(self) == CTYPE_BOOLEAN_TRUE ? Qtrue : Qfalse; } else { rb_ivar_set(self, bool_value_id, Qnil); return bool_value; } } VALUE rb_thrift_compact_proto_read_byte(VALUE self) { return INT2FIX(read_byte_direct(self)); } VALUE rb_thrift_compact_proto_read_i16(VALUE self) { return INT2FIX(read_i16(self)); } VALUE rb_thrift_compact_proto_read_i32(VALUE self) { return INT2NUM(zig_zag_to_int(read_varint64(self))); } VALUE rb_thrift_compact_proto_read_i64(VALUE self) { return LL2NUM(zig_zag_to_ll(read_varint64(self))); } VALUE rb_thrift_compact_proto_read_double(VALUE self) { union { double f; int64_t l; } transfer; VALUE rbuf = rb_ivar_get(self, rbuf_ivar_id); rb_funcall(GET_TRANSPORT(self), read_into_buffer_method_id, 2, rbuf, INT2FIX(8)); uint32_t lo = ((uint8_t)(RSTRING_PTR(rbuf)[0])) | (((uint8_t)(RSTRING_PTR(rbuf)[1])) << 8) | (((uint8_t)(RSTRING_PTR(rbuf)[2])) << 16) | (((uint8_t)(RSTRING_PTR(rbuf)[3])) << 24); uint64_t hi = (((uint8_t)(RSTRING_PTR(rbuf)[4]))) | (((uint8_t)(RSTRING_PTR(rbuf)[5])) << 8) | (((uint8_t)(RSTRING_PTR(rbuf)[6])) << 16) | (((uint8_t)(RSTRING_PTR(rbuf)[7])) << 24); transfer.l = (hi << 32) | lo; return rb_float_new(transfer.f); } VALUE rb_thrift_compact_proto_read_string(VALUE self) { VALUE buffer = rb_thrift_compact_proto_read_binary(self); return convert_to_string(buffer); } VALUE rb_thrift_compact_proto_read_binary(VALUE self) { int64_t size = read_varint64(self); return READ(self, size); } static void Init_constants() { thrift_compact_protocol_class = rb_const_get(thrift_module, rb_intern("CompactProtocol")); rb_global_variable(&thrift_compact_protocol_class); VERSION = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION"))); VERSION_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION_MASK"))); TYPE_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_MASK"))); TYPE_BITS = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_BITS"))); TYPE_SHIFT_AMOUNT = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_SHIFT_AMOUNT"))); PROTOCOL_ID = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("PROTOCOL_ID"))); last_field_id = rb_intern("@last_field"); boolean_field_id = rb_intern("@boolean_field"); bool_value_id = rb_intern("@bool_value"); rbuf_ivar_id = rb_intern("@rbuf"); } static void Init_rb_methods() { rb_define_method(thrift_compact_protocol_class, "native?", rb_thrift_compact_proto_native_qmark, 0); rb_define_method(thrift_compact_protocol_class, "write_message_begin", rb_thrift_compact_proto_write_message_begin, 3); rb_define_method(thrift_compact_protocol_class, "write_field_begin", rb_thrift_compact_proto_write_field_begin, 3); rb_define_method(thrift_compact_protocol_class, "write_field_stop", rb_thrift_compact_proto_write_field_stop, 0); rb_define_method(thrift_compact_protocol_class, "write_map_begin", rb_thrift_compact_proto_write_map_begin, 3); rb_define_method(thrift_compact_protocol_class, "write_list_begin", rb_thrift_compact_proto_write_list_begin, 2); rb_define_method(thrift_compact_protocol_class, "write_set_begin", rb_thrift_compact_proto_write_set_begin, 2); rb_define_method(thrift_compact_protocol_class, "write_byte", rb_thrift_compact_proto_write_byte, 1); rb_define_method(thrift_compact_protocol_class, "write_bool", rb_thrift_compact_proto_write_bool, 1); rb_define_method(thrift_compact_protocol_class, "write_i16", rb_thrift_compact_proto_write_i16, 1); rb_define_method(thrift_compact_protocol_class, "write_i32", rb_thrift_compact_proto_write_i32, 1); rb_define_method(thrift_compact_protocol_class, "write_i64", rb_thrift_compact_proto_write_i64, 1); rb_define_method(thrift_compact_protocol_class, "write_double", rb_thrift_compact_proto_write_double, 1); rb_define_method(thrift_compact_protocol_class, "write_string", rb_thrift_compact_proto_write_string, 1); rb_define_method(thrift_compact_protocol_class, "write_binary", rb_thrift_compact_proto_write_binary, 1); rb_define_method(thrift_compact_protocol_class, "write_message_end", rb_thrift_compact_proto_write_message_end, 0); rb_define_method(thrift_compact_protocol_class, "write_struct_begin", rb_thrift_compact_proto_write_struct_begin, 1); rb_define_method(thrift_compact_protocol_class, "write_struct_end", rb_thrift_compact_proto_write_struct_end, 0); rb_define_method(thrift_compact_protocol_class, "write_field_end", rb_thrift_compact_proto_write_field_end, 0); rb_define_method(thrift_compact_protocol_class, "write_map_end", rb_thrift_compact_proto_write_map_end, 0); rb_define_method(thrift_compact_protocol_class, "write_list_end", rb_thrift_compact_proto_write_list_end, 0); rb_define_method(thrift_compact_protocol_class, "write_set_end", rb_thrift_compact_proto_write_set_end, 0); rb_define_method(thrift_compact_protocol_class, "read_message_begin", rb_thrift_compact_proto_read_message_begin, 0); rb_define_method(thrift_compact_protocol_class, "read_field_begin", rb_thrift_compact_proto_read_field_begin, 0); rb_define_method(thrift_compact_protocol_class, "read_map_begin", rb_thrift_compact_proto_read_map_begin, 0); rb_define_method(thrift_compact_protocol_class, "read_list_begin", rb_thrift_compact_proto_read_list_begin, 0); rb_define_method(thrift_compact_protocol_class, "read_set_begin", rb_thrift_compact_proto_read_set_begin, 0); rb_define_method(thrift_compact_protocol_class, "read_byte", rb_thrift_compact_proto_read_byte, 0); rb_define_method(thrift_compact_protocol_class, "read_bool", rb_thrift_compact_proto_read_bool, 0); rb_define_method(thrift_compact_protocol_class, "read_i16", rb_thrift_compact_proto_read_i16, 0); rb_define_method(thrift_compact_protocol_class, "read_i32", rb_thrift_compact_proto_read_i32, 0); rb_define_method(thrift_compact_protocol_class, "read_i64", rb_thrift_compact_proto_read_i64, 0); rb_define_method(thrift_compact_protocol_class, "read_double", rb_thrift_compact_proto_read_double, 0); rb_define_method(thrift_compact_protocol_class, "read_string", rb_thrift_compact_proto_read_string, 0); rb_define_method(thrift_compact_protocol_class, "read_binary", rb_thrift_compact_proto_read_binary, 0); rb_define_method(thrift_compact_protocol_class, "read_message_end", rb_thrift_compact_proto_read_message_end, 0); rb_define_method(thrift_compact_protocol_class, "read_struct_begin", rb_thrift_compact_proto_read_struct_begin, 0); rb_define_method(thrift_compact_protocol_class, "read_struct_end", rb_thrift_compact_proto_read_struct_end, 0); rb_define_method(thrift_compact_protocol_class, "read_field_end", rb_thrift_compact_proto_read_field_end, 0); rb_define_method(thrift_compact_protocol_class, "read_map_end", rb_thrift_compact_proto_read_map_end, 0); rb_define_method(thrift_compact_protocol_class, "read_list_end", rb_thrift_compact_proto_read_list_end, 0); rb_define_method(thrift_compact_protocol_class, "read_set_end", rb_thrift_compact_proto_read_set_end, 0); } void Init_compact_protocol() { Init_constants(); Init_rb_methods(); } thrift-0.16.0/lib/rb/ext/compact_protocol.h000066400000000000000000000015031420101504100205520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ void Init_compact_protocol(); thrift-0.16.0/lib/rb/ext/constants.h000066400000000000000000000061361420101504100172260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ extern int TTYPE_STOP; extern int TTYPE_BOOL; extern int TTYPE_BYTE; extern int TTYPE_I16; extern int TTYPE_I32; extern int TTYPE_I64; extern int TTYPE_DOUBLE; extern int TTYPE_STRING; extern int TTYPE_MAP; extern int TTYPE_SET; extern int TTYPE_LIST; extern int TTYPE_STRUCT; extern ID validate_method_id; extern ID write_struct_begin_method_id; extern ID write_struct_end_method_id; extern ID write_field_begin_method_id; extern ID write_field_end_method_id; extern ID write_boolean_method_id; extern ID write_byte_method_id; extern ID write_i16_method_id; extern ID write_i32_method_id; extern ID write_i64_method_id; extern ID write_double_method_id; extern ID write_string_method_id; extern ID write_binary_method_id; extern ID write_map_begin_method_id; extern ID write_map_end_method_id; extern ID write_list_begin_method_id; extern ID write_list_end_method_id; extern ID write_set_begin_method_id; extern ID write_set_end_method_id; extern ID read_bool_method_id; extern ID read_byte_method_id; extern ID read_i16_method_id; extern ID read_i32_method_id; extern ID read_i64_method_id; extern ID read_string_method_id; extern ID read_binary_method_id; extern ID read_double_method_id; extern ID read_map_begin_method_id; extern ID read_map_end_method_id; extern ID read_list_begin_method_id; extern ID read_list_end_method_id; extern ID read_set_begin_method_id; extern ID read_set_end_method_id; extern ID read_struct_begin_method_id; extern ID read_struct_end_method_id; extern ID read_field_begin_method_id; extern ID read_field_end_method_id; extern ID keys_method_id; extern ID entries_method_id; extern ID write_field_stop_method_id; extern ID skip_method_id; extern ID write_method_id; extern ID read_all_method_id; extern ID read_into_buffer_method_id; extern ID force_binary_encoding_id; extern ID convert_to_utf8_byte_buffer_id; extern ID convert_to_string_id; extern ID fields_const_id; extern ID transport_ivar_id; extern ID strict_read_ivar_id; extern ID strict_write_ivar_id; extern VALUE type_sym; extern VALUE name_sym; extern VALUE key_sym; extern VALUE value_sym; extern VALUE element_sym; extern VALUE class_sym; extern VALUE binary_sym; extern VALUE rb_cSet; extern VALUE thrift_module; extern VALUE thrift_types_module; extern VALUE thrift_bytes_module; extern VALUE class_thrift_protocol; extern VALUE protocol_exception_class; thrift-0.16.0/lib/rb/ext/extconf.rb000066400000000000000000000022451420101504100170310ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ File.open('Makefile', 'w'){|f| f.puts "all:\n\ninstall:\n" } else require 'mkmf' require 'rbconfig' $ARCH_FLAGS = RbConfig::CONFIG['CFLAGS'].scan( /(-arch )(\S+)/ ).map{|x,y| x + y + ' ' }.join('') $CFLAGS = "-fsigned-char -g -O2 -Wall -Werror " + $ARCH_FLAGS have_func("strlcpy", "string.h") create_makefile 'thrift_native' end thrift-0.16.0/lib/rb/ext/macros.h000066400000000000000000000031161420101504100164710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #define GET_TRANSPORT(obj) rb_ivar_get(obj, transport_ivar_id) #define GET_STRICT_READ(obj) rb_ivar_get(obj, strict_read_ivar_id) #define GET_STRICT_WRITE(obj) rb_ivar_get(obj, strict_write_ivar_id) #define WRITE(obj, data, length) rb_funcall(obj, write_method_id, 1, rb_str_new(data, length)) #define CHECK_NIL(obj) if (NIL_P(obj)) { rb_raise(rb_eStandardError, "nil argument not allowed!");} #define READ(obj, length) rb_funcall(GET_TRANSPORT(obj), read_all_method_id, 1, INT2FIX(length)) #ifndef RFLOAT_VALUE # define RFLOAT_VALUE(v) RFLOAT(rb_Float(v))->value #endif #ifndef RSTRING_LEN # define RSTRING_LEN(v) RSTRING(rb_String(v))->len #endif #ifndef RSTRING_PTR # define RSTRING_PTR(v) RSTRING(rb_String(v))->ptr #endif #ifndef RARRAY_LEN # define RARRAY_LEN(v) RARRAY(rb_Array(v))->len #endif thrift-0.16.0/lib/rb/ext/memory_buffer.c000066400000000000000000000106171420101504100200450ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include ID buf_ivar_id; ID index_ivar_id; ID slice_method_id; int GARBAGE_BUFFER_SIZE; #define GET_BUF(self) rb_ivar_get(self, buf_ivar_id) VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str); VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value); VALUE rb_thrift_memory_buffer_read_byte(VALUE self); VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value); VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) { VALUE buf = GET_BUF(self); str = force_binary_encoding(str); rb_str_buf_cat(buf, StringValuePtr(str), RSTRING_LEN(str)); return Qnil; } VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value) { int length = FIX2INT(length_value); VALUE index_value = rb_ivar_get(self, index_ivar_id); int index = FIX2INT(index_value); VALUE buf = GET_BUF(self); VALUE data = rb_funcall(buf, slice_method_id, 2, index_value, length_value); index += length; if (index > RSTRING_LEN(buf)) { index = RSTRING_LEN(buf); } if (index >= GARBAGE_BUFFER_SIZE) { rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1))); index = 0; } rb_ivar_set(self, index_ivar_id, INT2FIX(index)); if (RSTRING_LEN(data) < length) { rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer"); } return data; } VALUE rb_thrift_memory_buffer_read_byte(VALUE self) { VALUE index_value = rb_ivar_get(self, index_ivar_id); int index = FIX2INT(index_value); VALUE buf = GET_BUF(self); if (index >= RSTRING_LEN(buf)) { rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer"); } char byte = RSTRING_PTR(buf)[index++]; if (index >= GARBAGE_BUFFER_SIZE) { rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1))); index = 0; } rb_ivar_set(self, index_ivar_id, INT2FIX(index)); int result = (int) byte; return INT2FIX(result); } VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value) { int i = 0; int size = FIX2INT(size_value); int index; VALUE buf = GET_BUF(self); index = FIX2INT(rb_ivar_get(self, index_ivar_id)); while (i < size) { if (index >= RSTRING_LEN(buf)) { rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer"); } char byte = RSTRING_PTR(buf)[index++]; if (i >= RSTRING_LEN(buffer_value)) { rb_raise(rb_eIndexError, "index %d out of string", i); } ((char*)RSTRING_PTR(buffer_value))[i] = byte; i++; } if (index >= GARBAGE_BUFFER_SIZE) { rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1))); index = 0; } rb_ivar_set(self, index_ivar_id, INT2FIX(index)); return INT2FIX(i); } void Init_memory_buffer() { VALUE thrift_memory_buffer_class = rb_const_get(thrift_module, rb_intern("MemoryBufferTransport")); rb_define_method(thrift_memory_buffer_class, "write", rb_thrift_memory_buffer_write, 1); rb_define_method(thrift_memory_buffer_class, "read", rb_thrift_memory_buffer_read, 1); rb_define_method(thrift_memory_buffer_class, "read_byte", rb_thrift_memory_buffer_read_byte, 0); rb_define_method(thrift_memory_buffer_class, "read_into_buffer", rb_thrift_memory_buffer_read_into_buffer, 2); buf_ivar_id = rb_intern("@buf"); index_ivar_id = rb_intern("@index"); slice_method_id = rb_intern("slice"); GARBAGE_BUFFER_SIZE = FIX2INT(rb_const_get(thrift_memory_buffer_class, rb_intern("GARBAGE_BUFFER_SIZE"))); } thrift-0.16.0/lib/rb/ext/memory_buffer.h000066400000000000000000000015001420101504100200410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ void Init_memory_buffer(); thrift-0.16.0/lib/rb/ext/protocol.c000066400000000000000000000000001420101504100170260ustar00rootroot00000000000000thrift-0.16.0/lib/rb/ext/protocol.h000066400000000000000000000000001420101504100170330ustar00rootroot00000000000000thrift-0.16.0/lib/rb/ext/strlcpy.c000066400000000000000000000022031420101504100166740ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "strlcpy.h" #ifndef HAVE_STRLCPY #define HAVE_STRLCPY size_t strlcpy (char *dst, const char *src, size_t dst_sz) { size_t n; for (n = 0; n < dst_sz; n++) { if ((*dst++ = *src++) == '\0') break; } if (n < dst_sz) return n; if (n > 0) *(dst - 1) = '\0'; return n + strlen (src); } #endif thrift-0.16.0/lib/rb/ext/strlcpy.h000066400000000000000000000021011420101504100166760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #ifndef __has_builtin #define __has_builtin(x) 0 #endif #ifndef HAVE_STRLCPY size_t strlcpy (char *dst, const char *src, size_t dst_sz); #else #if !__has_builtin(strlcpy) extern size_t strlcpy(char *, const char *, size_t); #endif #endif thrift-0.16.0/lib/rb/ext/struct.c000066400000000000000000000540251420101504100165310ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "struct.h" #include "constants.h" #include "macros.h" #include "strlcpy.h" VALUE thrift_union_class; ID setfield_id; ID setvalue_id; ID to_s_method_id; ID name_to_id_method_id; static ID sorted_field_ids_method_id; #define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET) #define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id) //------------------------------------------- // Writing section //------------------------------------------- // default fn pointers for protocol stuff here VALUE default_write_bool(VALUE protocol, VALUE value) { rb_funcall(protocol, write_boolean_method_id, 1, value); return Qnil; } VALUE default_write_byte(VALUE protocol, VALUE value) { rb_funcall(protocol, write_byte_method_id, 1, value); return Qnil; } VALUE default_write_i16(VALUE protocol, VALUE value) { rb_funcall(protocol, write_i16_method_id, 1, value); return Qnil; } VALUE default_write_i32(VALUE protocol, VALUE value) { rb_funcall(protocol, write_i32_method_id, 1, value); return Qnil; } VALUE default_write_i64(VALUE protocol, VALUE value) { rb_funcall(protocol, write_i64_method_id, 1, value); return Qnil; } VALUE default_write_double(VALUE protocol, VALUE value) { rb_funcall(protocol, write_double_method_id, 1, value); return Qnil; } VALUE default_write_string(VALUE protocol, VALUE value) { rb_funcall(protocol, write_string_method_id, 1, value); return Qnil; } VALUE default_write_binary(VALUE protocol, VALUE value) { rb_funcall(protocol, write_binary_method_id, 1, value); return Qnil; } VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) { rb_funcall(protocol, write_list_begin_method_id, 2, etype, length); return Qnil; } VALUE default_write_list_end(VALUE protocol) { rb_funcall(protocol, write_list_end_method_id, 0); return Qnil; } VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) { rb_funcall(protocol, write_set_begin_method_id, 2, etype, length); return Qnil; } VALUE default_write_set_end(VALUE protocol) { rb_funcall(protocol, write_set_end_method_id, 0); return Qnil; } VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) { rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length); return Qnil; } VALUE default_write_map_end(VALUE protocol) { rb_funcall(protocol, write_map_end_method_id, 0); return Qnil; } VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) { rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name); return Qnil; } VALUE default_write_struct_end(VALUE protocol) { rb_funcall(protocol, write_struct_end_method_id, 0); return Qnil; } VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) { rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id); return Qnil; } VALUE default_write_field_end(VALUE protocol) { rb_funcall(protocol, write_field_end_method_id, 0); return Qnil; } VALUE default_write_field_stop(VALUE protocol) { rb_funcall(protocol, write_field_stop_method_id, 0); return Qnil; } VALUE default_read_field_begin(VALUE protocol) { return rb_funcall(protocol, read_field_begin_method_id, 0); } VALUE default_read_field_end(VALUE protocol) { return rb_funcall(protocol, read_field_end_method_id, 0); } VALUE default_read_map_begin(VALUE protocol) { return rb_funcall(protocol, read_map_begin_method_id, 0); } VALUE default_read_map_end(VALUE protocol) { return rb_funcall(protocol, read_map_end_method_id, 0); } VALUE default_read_list_begin(VALUE protocol) { return rb_funcall(protocol, read_list_begin_method_id, 0); } VALUE default_read_list_end(VALUE protocol) { return rb_funcall(protocol, read_list_end_method_id, 0); } VALUE default_read_set_begin(VALUE protocol) { return rb_funcall(protocol, read_set_begin_method_id, 0); } VALUE default_read_set_end(VALUE protocol) { return rb_funcall(protocol, read_set_end_method_id, 0); } VALUE default_read_byte(VALUE protocol) { return rb_funcall(protocol, read_byte_method_id, 0); } VALUE default_read_bool(VALUE protocol) { return rb_funcall(protocol, read_bool_method_id, 0); } VALUE default_read_i16(VALUE protocol) { return rb_funcall(protocol, read_i16_method_id, 0); } VALUE default_read_i32(VALUE protocol) { return rb_funcall(protocol, read_i32_method_id, 0); } VALUE default_read_i64(VALUE protocol) { return rb_funcall(protocol, read_i64_method_id, 0); } VALUE default_read_double(VALUE protocol) { return rb_funcall(protocol, read_double_method_id, 0); } VALUE default_read_string(VALUE protocol) { return rb_funcall(protocol, read_string_method_id, 0); } VALUE default_read_binary(VALUE protocol) { return rb_funcall(protocol, read_binary_method_id, 0); } VALUE default_read_struct_begin(VALUE protocol) { return rb_funcall(protocol, read_struct_begin_method_id, 0); } VALUE default_read_struct_end(VALUE protocol) { return rb_funcall(protocol, read_struct_end_method_id, 0); } // end default protocol methods static VALUE rb_thrift_union_write (VALUE self, VALUE protocol); static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol); static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info); VALUE get_field_value(VALUE obj, VALUE field_name) { char name_buf[RSTRING_LEN(field_name) + 2]; name_buf[0] = '@'; strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1); VALUE value = rb_ivar_get(obj, rb_intern(name_buf)); return value; } static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) { int sz, i; if (ttype == TTYPE_MAP) { VALUE keys; VALUE key; VALUE val; Check_Type(value, T_HASH); VALUE key_info = rb_hash_aref(field_info, key_sym); VALUE keytype_value = rb_hash_aref(key_info, type_sym); int keytype = FIX2INT(keytype_value); VALUE value_info = rb_hash_aref(field_info, value_sym); VALUE valuetype_value = rb_hash_aref(value_info, type_sym); int valuetype = FIX2INT(valuetype_value); keys = rb_funcall(value, keys_method_id, 0); sz = RARRAY_LEN(keys); default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz)); for (i = 0; i < sz; i++) { key = rb_ary_entry(keys, i); val = rb_hash_aref(value, key); if (IS_CONTAINER(keytype)) { write_container(keytype, key_info, key, protocol); } else { write_anything(keytype, key, protocol, key_info); } if (IS_CONTAINER(valuetype)) { write_container(valuetype, value_info, val, protocol); } else { write_anything(valuetype, val, protocol, value_info); } } default_write_map_end(protocol); } else if (ttype == TTYPE_LIST) { Check_Type(value, T_ARRAY); sz = RARRAY_LEN(value); VALUE element_type_info = rb_hash_aref(field_info, element_sym); VALUE element_type_value = rb_hash_aref(element_type_info, type_sym); int element_type = FIX2INT(element_type_value); default_write_list_begin(protocol, element_type_value, INT2FIX(sz)); for (i = 0; i < sz; ++i) { VALUE val = rb_ary_entry(value, i); if (IS_CONTAINER(element_type)) { write_container(element_type, element_type_info, val, protocol); } else { write_anything(element_type, val, protocol, element_type_info); } } default_write_list_end(protocol); } else if (ttype == TTYPE_SET) { VALUE items; if (TYPE(value) == T_ARRAY) { items = value; } else { if (rb_cSet == CLASS_OF(value)) { items = rb_funcall(value, entries_method_id, 0); } else { Check_Type(value, T_HASH); items = rb_funcall(value, keys_method_id, 0); } } sz = RARRAY_LEN(items); VALUE element_type_info = rb_hash_aref(field_info, element_sym); VALUE element_type_value = rb_hash_aref(element_type_info, type_sym); int element_type = FIX2INT(element_type_value); default_write_set_begin(protocol, element_type_value, INT2FIX(sz)); for (i = 0; i < sz; i++) { VALUE val = rb_ary_entry(items, i); if (IS_CONTAINER(element_type)) { write_container(element_type, element_type_info, val, protocol); } else { write_anything(element_type, val, protocol, element_type_info); } } default_write_set_end(protocol); } else { rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype); } } static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) { if (ttype == TTYPE_BOOL) { default_write_bool(protocol, value); } else if (ttype == TTYPE_BYTE) { default_write_byte(protocol, value); } else if (ttype == TTYPE_I16) { default_write_i16(protocol, value); } else if (ttype == TTYPE_I32) { default_write_i32(protocol, value); } else if (ttype == TTYPE_I64) { default_write_i64(protocol, value); } else if (ttype == TTYPE_DOUBLE) { default_write_double(protocol, value); } else if (ttype == TTYPE_STRING) { VALUE is_binary = rb_hash_aref(field_info, binary_sym); if (is_binary != Qtrue) { default_write_string(protocol, value); } else { default_write_binary(protocol, value); } } else if (IS_CONTAINER(ttype)) { write_container(ttype, field_info, value, protocol); } else if (ttype == TTYPE_STRUCT) { if (rb_obj_is_kind_of(value, thrift_union_class)) { rb_thrift_union_write(value, protocol); } else { rb_thrift_struct_write(value, protocol); } } else { rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype); } } static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) { // call validate rb_funcall(self, validate_method_id, 0); // write struct begin default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self))); // iterate through all the fields here VALUE struct_fields = STRUCT_FIELDS(self); VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0); int i = 0; for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) { VALUE field_id = rb_ary_entry(sorted_field_ids, i); VALUE field_info = rb_hash_aref(struct_fields, field_id); VALUE ttype_value = rb_hash_aref(field_info, type_sym); int ttype = FIX2INT(ttype_value); VALUE field_name = rb_hash_aref(field_info, name_sym); VALUE field_value = get_field_value(self, field_name); if (!NIL_P(field_value)) { default_write_field_begin(protocol, field_name, ttype_value, field_id); write_anything(ttype, field_value, protocol, field_info); default_write_field_end(protocol); } } default_write_field_stop(protocol); // write struct end default_write_struct_end(protocol); return Qnil; } //------------------------------------------- // Reading section //------------------------------------------- static VALUE rb_thrift_union_read(VALUE self, VALUE protocol); static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol); static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size); static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size); static void set_field_value(VALUE obj, VALUE field_name, VALUE value) { char name_buf[RSTRING_LEN(field_name) + 2]; name_buf[0] = '@'; strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1); rb_ivar_set(obj, rb_intern(name_buf), value); } // Helper method to skip the contents of a map (assumes the map header has been read). static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) { int i; for (i = 0; i < size; i++) { rb_funcall(protocol, skip_method_id, 1, key_type_value); rb_funcall(protocol, skip_method_id, 1, value_type_value); } } // Helper method to skip the contents of a list or set (assumes the list/set header has been read). static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) { int i; for (i = 0; i < size; i++) { rb_funcall(protocol, skip_method_id, 1, element_type_value); } } static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) { VALUE result = Qnil; if (ttype == TTYPE_BOOL) { result = default_read_bool(protocol); } else if (ttype == TTYPE_BYTE) { result = default_read_byte(protocol); } else if (ttype == TTYPE_I16) { result = default_read_i16(protocol); } else if (ttype == TTYPE_I32) { result = default_read_i32(protocol); } else if (ttype == TTYPE_I64) { result = default_read_i64(protocol); } else if (ttype == TTYPE_STRING) { VALUE is_binary = rb_hash_aref(field_info, binary_sym); if (is_binary != Qtrue) { result = default_read_string(protocol); } else { result = default_read_binary(protocol); } } else if (ttype == TTYPE_DOUBLE) { result = default_read_double(protocol); } else if (ttype == TTYPE_STRUCT) { VALUE klass = rb_hash_aref(field_info, class_sym); result = rb_class_new_instance(0, NULL, klass); if (rb_obj_is_kind_of(result, thrift_union_class)) { rb_thrift_union_read(result, protocol); } else { rb_thrift_struct_read(result, protocol); } } else if (ttype == TTYPE_MAP) { int i; VALUE map_header = default_read_map_begin(protocol); int key_ttype = FIX2INT(rb_ary_entry(map_header, 0)); int value_ttype = FIX2INT(rb_ary_entry(map_header, 1)); int num_entries = FIX2INT(rb_ary_entry(map_header, 2)); // Check the declared key and value types against the expected ones and skip the map contents // if the types don't match. VALUE key_info = rb_hash_aref(field_info, key_sym); VALUE value_info = rb_hash_aref(field_info, value_sym); if (!NIL_P(key_info) && !NIL_P(value_info)) { int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym)); int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym)); if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) { result = rb_hash_new(); for (i = 0; i < num_entries; ++i) { VALUE key, val; key = read_anything(protocol, key_ttype, key_info); val = read_anything(protocol, value_ttype, value_info); rb_hash_aset(result, key, val); } } else { skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries); } } else { skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries); } default_read_map_end(protocol); } else if (ttype == TTYPE_LIST) { int i; VALUE list_header = default_read_list_begin(protocol); int element_ttype = FIX2INT(rb_ary_entry(list_header, 0)); int num_elements = FIX2INT(rb_ary_entry(list_header, 1)); // Check the declared element type against the expected one and skip the list contents // if the types don't match. VALUE element_info = rb_hash_aref(field_info, element_sym); if (!NIL_P(element_info)) { int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym)); if (specified_element_type == element_ttype) { result = rb_ary_new2(num_elements); for (i = 0; i < num_elements; ++i) { rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym))); } } else { skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); } } else { skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); } default_read_list_end(protocol); } else if (ttype == TTYPE_SET) { VALUE items; int i; VALUE set_header = default_read_set_begin(protocol); int element_ttype = FIX2INT(rb_ary_entry(set_header, 0)); int num_elements = FIX2INT(rb_ary_entry(set_header, 1)); // Check the declared element type against the expected one and skip the set contents // if the types don't match. VALUE element_info = rb_hash_aref(field_info, element_sym); if (!NIL_P(element_info)) { int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym)); if (specified_element_type == element_ttype) { items = rb_ary_new2(num_elements); for (i = 0; i < num_elements; ++i) { rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym))); } result = rb_class_new_instance(1, &items, rb_cSet); } else { skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); } } else { skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements); } default_read_set_end(protocol); } else { rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype); } return result; } static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) { // read struct begin default_read_struct_begin(protocol); VALUE struct_fields = STRUCT_FIELDS(self); // read each field while (true) { VALUE field_header = default_read_field_begin(protocol); VALUE field_type_value = rb_ary_entry(field_header, 1); int field_type = FIX2INT(field_type_value); if (field_type == TTYPE_STOP) { break; } // make sure we got a type we expected VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2)); if (!NIL_P(field_info)) { int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym)); if (field_type == specified_type) { // read the value VALUE name = rb_hash_aref(field_info, name_sym); set_field_value(self, name, read_anything(protocol, field_type, field_info)); } else { rb_funcall(protocol, skip_method_id, 1, field_type_value); } } else { rb_funcall(protocol, skip_method_id, 1, field_type_value); } // read field end default_read_field_end(protocol); } // read struct end default_read_struct_end(protocol); // call validate rb_funcall(self, validate_method_id, 0); return Qnil; } // -------------------------------- // Union section // -------------------------------- static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) { // read struct begin default_read_struct_begin(protocol); VALUE struct_fields = STRUCT_FIELDS(self); VALUE field_header = default_read_field_begin(protocol); VALUE field_type_value = rb_ary_entry(field_header, 1); int field_type = FIX2INT(field_type_value); // make sure we got a type we expected VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2)); if (!NIL_P(field_info)) { int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym)); if (field_type == specified_type) { // read the value VALUE name = rb_hash_aref(field_info, name_sym); rb_iv_set(self, "@setfield", rb_str_intern(name)); rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info)); } else { rb_funcall(protocol, skip_method_id, 1, field_type_value); } } else { rb_funcall(protocol, skip_method_id, 1, field_type_value); } // read field end default_read_field_end(protocol); field_header = default_read_field_begin(protocol); field_type_value = rb_ary_entry(field_header, 1); field_type = FIX2INT(field_type_value); if (field_type != TTYPE_STOP) { rb_raise(rb_eRuntimeError, "too many fields in union!"); } // read struct end default_read_struct_end(protocol); // call validate rb_funcall(self, validate_method_id, 0); return Qnil; } static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) { // call validate rb_funcall(self, validate_method_id, 0); // write struct begin default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self))); VALUE struct_fields = STRUCT_FIELDS(self); VALUE setfield = rb_ivar_get(self, setfield_id); VALUE setvalue = rb_ivar_get(self, setvalue_id); VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0)); VALUE field_info = rb_hash_aref(struct_fields, field_id); if(NIL_P(field_info)) { rb_raise(rb_eRuntimeError, "set_field is not valid for this union!"); } VALUE ttype_value = rb_hash_aref(field_info, type_sym); int ttype = FIX2INT(ttype_value); default_write_field_begin(protocol, setfield, ttype_value, field_id); write_anything(ttype, setvalue, protocol, field_info); default_write_field_end(protocol); default_write_field_stop(protocol); // write struct end default_write_struct_end(protocol); return Qnil; } void Init_struct() { VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct")); rb_define_method(struct_module, "write", rb_thrift_struct_write, 1); rb_define_method(struct_module, "read", rb_thrift_struct_read, 1); thrift_union_class = rb_const_get(thrift_module, rb_intern("Union")); rb_global_variable(&thrift_union_class); rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1); rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1); setfield_id = rb_intern("@setfield"); rb_global_variable(&setfield_id); setvalue_id = rb_intern("@value"); rb_global_variable(&setvalue_id); to_s_method_id = rb_intern("to_s"); rb_global_variable(&to_s_method_id); name_to_id_method_id = rb_intern("name_to_id"); rb_global_variable(&name_to_id_method_id); sorted_field_ids_method_id = rb_intern("sorted_field_ids"); rb_global_variable(&sorted_field_ids_method_id); } thrift-0.16.0/lib/rb/ext/struct.h000066400000000000000000000015651420101504100165370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include void Init_struct(); void Init_union(); thrift-0.16.0/lib/rb/ext/thrift_native.c000066400000000000000000000172011420101504100200460ustar00rootroot00000000000000/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include // cached classes/modules VALUE rb_cSet; VALUE thrift_module; VALUE thrift_bytes_module; VALUE thrift_types_module; // TType constants int TTYPE_STOP; int TTYPE_BOOL; int TTYPE_BYTE; int TTYPE_I16; int TTYPE_I32; int TTYPE_I64; int TTYPE_DOUBLE; int TTYPE_STRING; int TTYPE_MAP; int TTYPE_SET; int TTYPE_LIST; int TTYPE_STRUCT; // method ids ID validate_method_id; ID write_struct_begin_method_id; ID write_struct_end_method_id; ID write_field_begin_method_id; ID write_field_end_method_id; ID write_boolean_method_id; ID write_byte_method_id; ID write_i16_method_id; ID write_i32_method_id; ID write_i64_method_id; ID write_double_method_id; ID write_string_method_id; ID write_binary_method_id; ID write_map_begin_method_id; ID write_map_end_method_id; ID write_list_begin_method_id; ID write_list_end_method_id; ID write_set_begin_method_id; ID write_set_end_method_id; ID read_bool_method_id; ID read_byte_method_id; ID read_i16_method_id; ID read_i32_method_id; ID read_i64_method_id; ID read_string_method_id; ID read_binary_method_id; ID read_double_method_id; ID read_map_begin_method_id; ID read_map_end_method_id; ID read_list_begin_method_id; ID read_list_end_method_id; ID read_set_begin_method_id; ID read_set_end_method_id; ID read_struct_begin_method_id; ID read_struct_end_method_id; ID read_field_begin_method_id; ID read_field_end_method_id; ID keys_method_id; ID entries_method_id; ID write_field_stop_method_id; ID skip_method_id; ID write_method_id; ID read_all_method_id; ID read_into_buffer_method_id; ID force_binary_encoding_id; ID convert_to_utf8_byte_buffer_id; ID convert_to_string_id; // constant ids ID fields_const_id; ID transport_ivar_id; ID strict_read_ivar_id; ID strict_write_ivar_id; // cached symbols VALUE type_sym; VALUE name_sym; VALUE key_sym; VALUE value_sym; VALUE element_sym; VALUE class_sym; VALUE binary_sym; VALUE protocol_exception_class; void Init_thrift_native() { // cached classes thrift_module = rb_const_get(rb_cObject, rb_intern("Thrift")); rb_global_variable(&thrift_module); thrift_bytes_module = rb_const_get(thrift_module, rb_intern("Bytes")); rb_global_variable(&thrift_bytes_module); thrift_types_module = rb_const_get(thrift_module, rb_intern("Types")); rb_global_variable(&thrift_types_module); rb_cSet = rb_const_get(rb_cObject, rb_intern("Set")); rb_global_variable(&rb_cSet); protocol_exception_class = rb_const_get(thrift_module, rb_intern("ProtocolException")); rb_global_variable(&protocol_exception_class); // Init ttype constants TTYPE_BOOL = FIX2INT(rb_const_get(thrift_types_module, rb_intern("BOOL"))); TTYPE_BYTE = FIX2INT(rb_const_get(thrift_types_module, rb_intern("BYTE"))); TTYPE_I16 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I16"))); TTYPE_I32 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I32"))); TTYPE_I64 = FIX2INT(rb_const_get(thrift_types_module, rb_intern("I64"))); TTYPE_DOUBLE = FIX2INT(rb_const_get(thrift_types_module, rb_intern("DOUBLE"))); TTYPE_STRING = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRING"))); TTYPE_MAP = FIX2INT(rb_const_get(thrift_types_module, rb_intern("MAP"))); TTYPE_SET = FIX2INT(rb_const_get(thrift_types_module, rb_intern("SET"))); TTYPE_LIST = FIX2INT(rb_const_get(thrift_types_module, rb_intern("LIST"))); TTYPE_STRUCT = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRUCT"))); // method ids validate_method_id = rb_intern("validate"); write_struct_begin_method_id = rb_intern("write_struct_begin"); write_struct_end_method_id = rb_intern("write_struct_end"); write_field_begin_method_id = rb_intern("write_field_begin"); write_field_end_method_id = rb_intern("write_field_end"); write_boolean_method_id = rb_intern("write_bool"); write_byte_method_id = rb_intern("write_byte"); write_i16_method_id = rb_intern("write_i16"); write_i32_method_id = rb_intern("write_i32"); write_i64_method_id = rb_intern("write_i64"); write_double_method_id = rb_intern("write_double"); write_string_method_id = rb_intern("write_string"); write_binary_method_id = rb_intern("write_binary"); write_map_begin_method_id = rb_intern("write_map_begin"); write_map_end_method_id = rb_intern("write_map_end"); write_list_begin_method_id = rb_intern("write_list_begin"); write_list_end_method_id = rb_intern("write_list_end"); write_set_begin_method_id = rb_intern("write_set_begin"); write_set_end_method_id = rb_intern("write_set_end"); read_bool_method_id = rb_intern("read_bool"); read_byte_method_id = rb_intern("read_byte"); read_i16_method_id = rb_intern("read_i16"); read_i32_method_id = rb_intern("read_i32"); read_i64_method_id = rb_intern("read_i64"); read_string_method_id = rb_intern("read_string"); read_binary_method_id = rb_intern("read_binary"); read_double_method_id = rb_intern("read_double"); read_map_begin_method_id = rb_intern("read_map_begin"); read_map_end_method_id = rb_intern("read_map_end"); read_list_begin_method_id = rb_intern("read_list_begin"); read_list_end_method_id = rb_intern("read_list_end"); read_set_begin_method_id = rb_intern("read_set_begin"); read_set_end_method_id = rb_intern("read_set_end"); read_struct_begin_method_id = rb_intern("read_struct_begin"); read_struct_end_method_id = rb_intern("read_struct_end"); read_field_begin_method_id = rb_intern("read_field_begin"); read_field_end_method_id = rb_intern("read_field_end"); keys_method_id = rb_intern("keys"); entries_method_id = rb_intern("entries"); write_field_stop_method_id = rb_intern("write_field_stop"); skip_method_id = rb_intern("skip"); write_method_id = rb_intern("write"); read_all_method_id = rb_intern("read_all"); read_into_buffer_method_id = rb_intern("read_into_buffer"); force_binary_encoding_id = rb_intern("force_binary_encoding"); convert_to_utf8_byte_buffer_id = rb_intern("convert_to_utf8_byte_buffer"); convert_to_string_id = rb_intern("convert_to_string"); // constant ids fields_const_id = rb_intern("FIELDS"); transport_ivar_id = rb_intern("@trans"); strict_read_ivar_id = rb_intern("@strict_read"); strict_write_ivar_id = rb_intern("@strict_write"); // cached symbols type_sym = ID2SYM(rb_intern("type")); name_sym = ID2SYM(rb_intern("name")); key_sym = ID2SYM(rb_intern("key")); value_sym = ID2SYM(rb_intern("value")); element_sym = ID2SYM(rb_intern("element")); class_sym = ID2SYM(rb_intern("class")); binary_sym = ID2SYM(rb_intern("binary")); rb_global_variable(&type_sym); rb_global_variable(&name_sym); rb_global_variable(&key_sym); rb_global_variable(&value_sym); rb_global_variable(&element_sym); rb_global_variable(&class_sym); rb_global_variable(&binary_sym); Init_struct(); Init_binary_protocol_accelerated(); Init_compact_protocol(); Init_memory_buffer(); } thrift-0.16.0/lib/rb/lib/000077500000000000000000000000001420101504100150015ustar00rootroot00000000000000thrift-0.16.0/lib/rb/lib/thrift.rb000066400000000000000000000046011420101504100166270ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Contains some contributions under the Thrift Software License. # Please see doc/old-thrift-license.txt in the Thrift distribution for # details. $:.unshift File.dirname(__FILE__) require 'thrift/bytes' require 'thrift/core_ext' require 'thrift/exceptions' require 'thrift/types' require 'thrift/processor' require 'thrift/multiplexed_processor' require 'thrift/client' require 'thrift/struct' require 'thrift/union' require 'thrift/struct_union' # serializer require 'thrift/serializer/serializer' require 'thrift/serializer/deserializer' # protocol require 'thrift/protocol/base_protocol' require 'thrift/protocol/binary_protocol' require 'thrift/protocol/binary_protocol_accelerated' require 'thrift/protocol/compact_protocol' require 'thrift/protocol/json_protocol' require 'thrift/protocol/multiplexed_protocol' # transport require 'thrift/transport/base_transport' require 'thrift/transport/base_server_transport' require 'thrift/transport/socket' require 'thrift/transport/ssl_socket' require 'thrift/transport/server_socket' require 'thrift/transport/ssl_server_socket' require 'thrift/transport/unix_socket' require 'thrift/transport/unix_server_socket' require 'thrift/transport/buffered_transport' require 'thrift/transport/framed_transport' require 'thrift/transport/http_client_transport' require 'thrift/transport/io_stream_transport' require 'thrift/transport/memory_buffer_transport' # server require 'thrift/server/base_server' require 'thrift/server/nonblocking_server' require 'thrift/server/simple_server' require 'thrift/server/threaded_server' require 'thrift/server/thread_pool_server' require 'thrift/thrift_native' thrift-0.16.0/lib/rb/lib/thrift/000077500000000000000000000000001420101504100163015ustar00rootroot00000000000000thrift-0.16.0/lib/rb/lib/thrift/bytes.rb000066400000000000000000000105051420101504100177550ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift # A collection of utilities for working with bytes and byte buffers. module Bytes if RUBY_VERSION >= '1.9' # Creates and empty byte buffer (String with BINARY encoding) # # size - The Integer size of the buffer (default: nil) to create # # Returns a String with BINARY encoding, filled with null characters # if size is greater than zero def self.empty_byte_buffer(size = nil) if (size && size > 0) "\0".force_encoding(Encoding::BINARY) * size else ''.force_encoding(Encoding::BINARY) end end # Forces the encoding of the buffer to BINARY. If the buffer # passed is frozen, then it will be duplicated. # # buffer - The String to force the encoding of. # # Returns the String passed with an encoding of BINARY; returned # String may be a duplicate. def self.force_binary_encoding(buffer) buffer = buffer.dup if buffer.frozen? buffer.force_encoding(Encoding::BINARY) end # Gets the byte value of a given position in a String. # # string - The String to retrive the byte value from. # index - The Integer location of the byte value to retrieve. # # Returns an Integer value between 0 and 255. def self.get_string_byte(string, index) string.getbyte(index) end # Sets the byte value given to a given index in a String. # # string - The String to set the byte value in. # index - The Integer location to set the byte value at. # byte - The Integer value (0 to 255) to set in the string. # # Returns an Integer value of the byte value to set. def self.set_string_byte(string, index, byte) string.setbyte(index, byte) end # Converts the given String to a UTF-8 byte buffer. # # string - The String to convert. # # Returns a new String with BINARY encoding, containing the UTF-8 # bytes of the original string. def self.convert_to_utf8_byte_buffer(string) if string.encoding != Encoding::UTF_8 # transcode to UTF-8 string = string.encode(Encoding::UTF_8) else # encoding is already UTF-8, but a duplicate is needed string = string.dup end string.force_encoding(Encoding::BINARY) end # Converts the given UTF-8 byte buffer into a String # # utf8_buffer - A String, with BINARY encoding, containing UTF-8 bytes # # Returns a new String with UTF-8 encoding, def self.convert_to_string(utf8_buffer) # duplicate the buffer, force encoding to UTF-8 utf8_buffer.dup.force_encoding(Encoding::UTF_8) end else def self.empty_byte_buffer(size = nil) if (size && size > 0) "\0" * size else '' end end def self.force_binary_encoding(buffer) buffer end def self.get_string_byte(string, index) string[index] end def self.set_string_byte(string, index, byte) string[index] = byte end def self.convert_to_utf8_byte_buffer(string) # This assumes $KCODE is 'UTF8'/'U', which would mean the String is already a UTF-8 byte buffer # TODO consider handling other $KCODE values and transcoding with iconv string end def self.convert_to_string(utf8_buffer) # See comment in 'convert_to_utf8_byte_buffer' for relevant assumptions. utf8_buffer end end end end thrift-0.16.0/lib/rb/lib/thrift/client.rb000066400000000000000000000040021420101504100201000ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift module Client def initialize(iprot, oprot=nil) @iprot = iprot @oprot = oprot || iprot @seqid = 0 end def send_message(name, args_class, args = {}) @oprot.write_message_begin(name, MessageTypes::CALL, @seqid) send_message_args(args_class, args) end def send_oneway_message(name, args_class, args = {}) @oprot.write_message_begin(name, MessageTypes::ONEWAY, @seqid) send_message_args(args_class, args) end def send_message_args(args_class, args) data = args_class.new args.each do |k, v| data.send("#{k.to_s}=", v) end begin data.write(@oprot) rescue StandardError => e @oprot.trans.close raise e end @oprot.write_message_end @oprot.trans.flush end def receive_message(result_klass) fname, mtype, rseqid = @iprot.read_message_begin handle_exception(mtype) result = result_klass.new result.read(@iprot) @iprot.read_message_end result end def handle_exception(mtype) if mtype == MessageTypes::EXCEPTION x = ApplicationException.new x.read(@iprot) @iprot.read_message_end raise x end end end end thrift-0.16.0/lib/rb/lib/thrift/core_ext.rb000066400000000000000000000016341420101504100204420ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each do |file| name = File.basename(file, '.rb') require "thrift/core_ext/#{name}" end thrift-0.16.0/lib/rb/lib/thrift/core_ext/000077500000000000000000000000001420101504100201115ustar00rootroot00000000000000thrift-0.16.0/lib/rb/lib/thrift/core_ext/fixnum.rb000066400000000000000000000017011420101504100217430ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Versions of ruby pre 1.8.7 do not have an .ord method available in the Fixnum # class. # if RUBY_VERSION < "1.8.7" class Fixnum def ord self end end endthrift-0.16.0/lib/rb/lib/thrift/exceptions.rb000066400000000000000000000044251420101504100210140ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class Exception < StandardError def initialize(message) super @message = message end attr_reader :message end class ApplicationException < Exception UNKNOWN = 0 UNKNOWN_METHOD = 1 INVALID_MESSAGE_TYPE = 2 WRONG_METHOD_NAME = 3 BAD_SEQUENCE_ID = 4 MISSING_RESULT = 5 INTERNAL_ERROR = 6 PROTOCOL_ERROR = 7 INVALID_TRANSFORM = 8 INVALID_PROTOCOL = 9 UNSUPPORTED_CLIENT_TYPE = 10 attr_reader :type def initialize(type=UNKNOWN, message=nil) super(message) @type = type end def read(iprot) iprot.read_struct_begin while true fname, ftype, fid = iprot.read_field_begin if ftype == Types::STOP break end if fid == 1 and ftype == Types::STRING @message = iprot.read_string elsif fid == 2 and ftype == Types::I32 @type = iprot.read_i32 else iprot.skip(ftype) end iprot.read_field_end end iprot.read_struct_end end def write(oprot) oprot.write_struct_begin('Thrift::ApplicationException') unless @message.nil? oprot.write_field_begin('message', Types::STRING, 1) oprot.write_string(@message) oprot.write_field_end end unless @type.nil? oprot.write_field_begin('type', Types::I32, 2) oprot.write_i32(@type) oprot.write_field_end end oprot.write_field_stop oprot.write_struct_end end end end thrift-0.16.0/lib/rb/lib/thrift/multiplexed_processor.rb000066400000000000000000000045161420101504100232670ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. require 'thrift/protocol/protocol_decorator' require 'thrift/protocol/base_protocol' module Thrift class MultiplexedProcessor def initialize @actual_processors = {} end def register_processor(service_name, processor) @actual_processors[service_name] = processor end def process(iprot, oprot) name, type, seqid = iprot.read_message_begin check_type(type) check_separator(name) service_name, method = name.split(':') processor(service_name).process(StoredMessageProtocol.new(iprot, [method, type, seqid]), oprot) end protected def processor(service_name) if @actual_processors.has_key?(service_name) @actual_processors[service_name] else raise Thrift::Exception.new("Service name not found: #{service_name}. Did you forget to call #{self.class.name}#register_processor?") end end def check_type(type) unless [MessageTypes::CALL, MessageTypes::ONEWAY].include?(type) raise Thrift::Exception.new('This should not have happened!?') end end def check_separator(name) if name.count(':') < 1 raise Thrift::Exception.new("Service name not found in message name: #{name}. Did you forget to use a Thrift::Protocol::MultiplexedProtocol in your client?") end end end class StoredMessageProtocol < BaseProtocol include ProtocolDecorator def initialize(protocol, message_begin) super(protocol) @message_begin = message_begin end def read_message_begin @message_begin end end end thrift-0.16.0/lib/rb/lib/thrift/processor.rb000066400000000000000000000044171420101504100206530ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'logger' module Thrift module Processor def initialize(handler, logger=nil) @handler = handler if logger.nil? @logger = Logger.new(STDERR) @logger.level = Logger::WARN else @logger = logger end end def process(iprot, oprot) name, type, seqid = iprot.read_message_begin if respond_to?("process_#{name}") begin send("process_#{name}", seqid, iprot, oprot) rescue => e x = ApplicationException.new(ApplicationException::INTERNAL_ERROR, 'Internal error') @logger.debug "Internal error : #{e.message}\n#{e.backtrace.join("\n")}" write_error(x, oprot, name, seqid) end true else iprot.skip(Types::STRUCT) iprot.read_message_end x = ApplicationException.new(ApplicationException::UNKNOWN_METHOD, 'Unknown function '+name) write_error(x, oprot, name, seqid) false end end def read_args(iprot, args_class) args = args_class.new args.read(iprot) iprot.read_message_end args end def write_result(result, oprot, name, seqid) oprot.write_message_begin(name, MessageTypes::REPLY, seqid) result.write(oprot) oprot.write_message_end oprot.trans.flush end def write_error(err, oprot, name, seqid) oprot.write_message_begin(name, MessageTypes::EXCEPTION, seqid) err.write(oprot) oprot.write_message_end oprot.trans.flush end end end thrift-0.16.0/lib/rb/lib/thrift/protocol/000077500000000000000000000000001420101504100201425ustar00rootroot00000000000000thrift-0.16.0/lib/rb/lib/thrift/protocol/base_protocol.rb000066400000000000000000000224151420101504100233260ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # this require is to make generated struct definitions happy require 'set' module Thrift class ProtocolException < Exception UNKNOWN = 0 INVALID_DATA = 1 NEGATIVE_SIZE = 2 SIZE_LIMIT = 3 BAD_VERSION = 4 NOT_IMPLEMENTED = 5 DEPTH_LIMIT = 6 attr_reader :type def initialize(type=UNKNOWN, message=nil) super(message) @type = type end end class BaseProtocol attr_reader :trans def initialize(trans) @trans = trans end def native? puts "wrong method is being called!" false end def write_message_begin(name, type, seqid) raise NotImplementedError end def write_message_end; nil; end def write_struct_begin(name) raise NotImplementedError end def write_struct_end; nil; end def write_field_begin(name, type, id) raise NotImplementedError end def write_field_end; nil; end def write_field_stop raise NotImplementedError end def write_map_begin(ktype, vtype, size) raise NotImplementedError end def write_map_end; nil; end def write_list_begin(etype, size) raise NotImplementedError end def write_list_end; nil; end def write_set_begin(etype, size) raise NotImplementedError end def write_set_end; nil; end def write_bool(bool) raise NotImplementedError end def write_byte(byte) raise NotImplementedError end def write_i16(i16) raise NotImplementedError end def write_i32(i32) raise NotImplementedError end def write_i64(i64) raise NotImplementedError end def write_double(dub) raise NotImplementedError end # Writes a Thrift String. In Ruby 1.9+, the String passed will be transcoded to UTF-8. # # str - The String to write. # # Raises EncodingError if the transcoding to UTF-8 fails. # # Returns nothing. def write_string(str) raise NotImplementedError end # Writes a Thrift Binary (Thrift String with no encoding). In Ruby 1.9+, the String passed # will forced into BINARY encoding. # # buf - The String to write. # # Returns nothing. def write_binary(buf) raise NotImplementedError end def read_message_begin raise NotImplementedError end def read_message_end; nil; end def read_struct_begin raise NotImplementedError end def read_struct_end; nil; end def read_field_begin raise NotImplementedError end def read_field_end; nil; end def read_map_begin raise NotImplementedError end def read_map_end; nil; end def read_list_begin raise NotImplementedError end def read_list_end; nil; end def read_set_begin raise NotImplementedError end def read_set_end; nil; end def read_bool raise NotImplementedError end def read_byte raise NotImplementedError end def read_i16 raise NotImplementedError end def read_i32 raise NotImplementedError end def read_i64 raise NotImplementedError end def read_double raise NotImplementedError end # Reads a Thrift String. In Ruby 1.9+, all Strings will be returned with an Encoding of UTF-8. # # Returns a String. def read_string raise NotImplementedError end # Reads a Thrift Binary (Thrift String without encoding). In Ruby 1.9+, all Strings will be returned # with an Encoding of BINARY. # # Returns a String. def read_binary raise NotImplementedError end # Writes a field based on the field information, field ID and value. # # field_info - A Hash containing the definition of the field: # :name - The name of the field. # :type - The type of the field, which must be a Thrift::Types constant. # :binary - A Boolean flag that indicates if Thrift::Types::STRING is a binary string (string without encoding). # fid - The ID of the field. # value - The field's value to write; object type varies based on :type. # # Returns nothing. def write_field(*args) if args.size == 3 # handles the documented method signature - write_field(field_info, fid, value) field_info = args[0] fid = args[1] value = args[2] elsif args.size == 4 # handles the deprecated method signature - write_field(name, type, fid, value) field_info = {:name => args[0], :type => args[1]} fid = args[2] value = args[3] else raise ArgumentError, "wrong number of arguments (#{args.size} for 3)" end write_field_begin(field_info[:name], field_info[:type], fid) write_type(field_info, value) write_field_end end # Writes a field value based on the field information. # # field_info - A Hash containing the definition of the field: # :type - The Thrift::Types constant that determines how the value is written. # :binary - A Boolean flag that indicates if Thrift::Types::STRING is a binary string (string without encoding). # value - The field's value to write; object type varies based on field_info[:type]. # # Returns nothing. def write_type(field_info, value) # if field_info is a Fixnum, assume it is a Thrift::Types constant # convert it into a field_info Hash for backwards compatibility if field_info.is_a? Fixnum field_info = {:type => field_info} end case field_info[:type] when Types::BOOL write_bool(value) when Types::BYTE write_byte(value) when Types::DOUBLE write_double(value) when Types::I16 write_i16(value) when Types::I32 write_i32(value) when Types::I64 write_i64(value) when Types::STRING if field_info[:binary] write_binary(value) else write_string(value) end when Types::STRUCT value.write(self) else raise NotImplementedError end end # Reads a field value based on the field information. # # field_info - A Hash containing the pertinent data to write: # :type - The Thrift::Types constant that determines how the value is written. # :binary - A flag that indicates if Thrift::Types::STRING is a binary string (string without encoding). # # Returns the value read; object type varies based on field_info[:type]. def read_type(field_info) # if field_info is a Fixnum, assume it is a Thrift::Types constant # convert it into a field_info Hash for backwards compatibility if field_info.is_a? Fixnum field_info = {:type => field_info} end case field_info[:type] when Types::BOOL read_bool when Types::BYTE read_byte when Types::DOUBLE read_double when Types::I16 read_i16 when Types::I32 read_i32 when Types::I64 read_i64 when Types::STRING if field_info[:binary] read_binary else read_string end else raise NotImplementedError end end def skip(type) case type when Types::BOOL read_bool when Types::BYTE read_byte when Types::I16 read_i16 when Types::I32 read_i32 when Types::I64 read_i64 when Types::DOUBLE read_double when Types::STRING read_string when Types::STRUCT read_struct_begin while true name, type, id = read_field_begin break if type == Types::STOP skip(type) read_field_end end read_struct_end when Types::MAP ktype, vtype, size = read_map_begin size.times do skip(ktype) skip(vtype) end read_map_end when Types::SET etype, size = read_set_begin size.times do skip(etype) end read_set_end when Types::LIST etype, size = read_list_begin size.times do skip(etype) end read_list_end else raise ProtocolException.new(ProtocolException::INVALID_DATA, 'Invalid data') end end def to_s "#{trans.to_s}" end end class BaseProtocolFactory def get_protocol(trans) raise NotImplementedError end def to_s "base" end end end thrift-0.16.0/lib/rb/lib/thrift/protocol/binary_protocol.rb000066400000000000000000000127561420101504100237070ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class BinaryProtocol < BaseProtocol VERSION_MASK = 0xffff0000 VERSION_1 = 0x80010000 TYPE_MASK = 0x000000ff attr_reader :strict_read, :strict_write def initialize(trans, strict_read=true, strict_write=true) super(trans) @strict_read = strict_read @strict_write = strict_write # Pre-allocated read buffer for fixed-size read methods. Needs to be at least 8 bytes long for # read_i64() and read_double(). @rbuf = Bytes.empty_byte_buffer(8) end def write_message_begin(name, type, seqid) # this is necessary because we added (needed) bounds checking to # write_i32, and 0x80010000 is too big for that. if strict_write write_i16(VERSION_1 >> 16) write_i16(type) write_string(name) write_i32(seqid) else write_string(name) write_byte(type) write_i32(seqid) end end def write_struct_begin(name); nil; end def write_field_begin(name, type, id) write_byte(type) write_i16(id) end def write_field_stop write_byte(Thrift::Types::STOP) end def write_map_begin(ktype, vtype, size) write_byte(ktype) write_byte(vtype) write_i32(size) end def write_list_begin(etype, size) write_byte(etype) write_i32(size) end def write_set_begin(etype, size) write_byte(etype) write_i32(size) end def write_bool(bool) write_byte(bool ? 1 : 0) end def write_byte(byte) raise RangeError if byte < -2**31 || byte >= 2**32 trans.write([byte].pack('c')) end def write_i16(i16) trans.write([i16].pack('n')) end def write_i32(i32) raise RangeError if i32 < -2**31 || i32 >= 2**31 trans.write([i32].pack('N')) end def write_i64(i64) raise RangeError if i64 < -2**63 || i64 >= 2**64 hi = i64 >> 32 lo = i64 & 0xffffffff trans.write([hi, lo].pack('N2')) end def write_double(dub) trans.write([dub].pack('G')) end def write_string(str) buf = Bytes.convert_to_utf8_byte_buffer(str) write_binary(buf) end def write_binary(buf) write_i32(buf.bytesize) trans.write(buf) end def read_message_begin version = read_i32 if version < 0 if (version & VERSION_MASK != VERSION_1) raise ProtocolException.new(ProtocolException::BAD_VERSION, 'Missing version identifier') end type = version & TYPE_MASK name = read_string seqid = read_i32 [name, type, seqid] else if strict_read raise ProtocolException.new(ProtocolException::BAD_VERSION, 'No version identifier, old protocol client?') end name = trans.read_all(version) type = read_byte seqid = read_i32 [name, type, seqid] end end def read_struct_begin; nil; end def read_field_begin type = read_byte if (type == Types::STOP) [nil, type, 0] else id = read_i16 [nil, type, id] end end def read_map_begin ktype = read_byte vtype = read_byte size = read_i32 [ktype, vtype, size] end def read_list_begin etype = read_byte size = read_i32 [etype, size] end def read_set_begin etype = read_byte size = read_i32 [etype, size] end def read_bool byte = read_byte byte != 0 end def read_byte val = trans.read_byte if (val > 0x7f) val = 0 - ((val - 1) ^ 0xff) end val end def read_i16 trans.read_into_buffer(@rbuf, 2) val, = @rbuf.unpack('n') if (val > 0x7fff) val = 0 - ((val - 1) ^ 0xffff) end val end def read_i32 trans.read_into_buffer(@rbuf, 4) val, = @rbuf.unpack('N') if (val > 0x7fffffff) val = 0 - ((val - 1) ^ 0xffffffff) end val end def read_i64 trans.read_into_buffer(@rbuf, 8) hi, lo = @rbuf.unpack('N2') if (hi > 0x7fffffff) hi ^= 0xffffffff lo ^= 0xffffffff 0 - (hi << 32) - lo - 1 else (hi << 32) + lo end end def read_double trans.read_into_buffer(@rbuf, 8) val = @rbuf.unpack('G').first val end def read_string buffer = read_binary Bytes.convert_to_string(buffer) end def read_binary size = read_i32 trans.read_all(size) end def to_s "binary(#{super.to_s})" end end class BinaryProtocolFactory < BaseProtocolFactory def get_protocol(trans) return Thrift::BinaryProtocol.new(trans) end def to_s "binary" end end end thrift-0.16.0/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb000066400000000000000000000031101420101504100262030ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # =begin The only change required for a transport to support BinaryProtocolAccelerated is to implement 2 methods: * borrow(size), which takes an optional argument and returns atleast _size_ bytes from the transport, or the default buffer size if no argument is given * consume!(size), which removes size bytes from the front of the buffer See MemoryBuffer and BufferedTransport for examples. =end module Thrift class BinaryProtocolAcceleratedFactory < BaseProtocolFactory def get_protocol(trans) if (defined? BinaryProtocolAccelerated) BinaryProtocolAccelerated.new(trans) else BinaryProtocol.new(trans) end end def to_s if (defined? BinaryProtocolAccelerated) "binary-accel" else "binary" end end end end thrift-0.16.0/lib/rb/lib/thrift/protocol/compact_protocol.rb000066400000000000000000000260031420101504100240370ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class CompactProtocol < BaseProtocol PROTOCOL_ID = [0x82].pack('c').unpack('c').first VERSION = 1 VERSION_MASK = 0x1f TYPE_MASK = 0xE0 TYPE_BITS = 0x07 TYPE_SHIFT_AMOUNT = 5 TSTOP = ["", Types::STOP, 0] # # All of the on-wire type codes. # class CompactTypes BOOLEAN_TRUE = 0x01 BOOLEAN_FALSE = 0x02 BYTE = 0x03 I16 = 0x04 I32 = 0x05 I64 = 0x06 DOUBLE = 0x07 BINARY = 0x08 LIST = 0x09 SET = 0x0A MAP = 0x0B STRUCT = 0x0C def self.is_bool_type?(b) (b & 0x0f) == BOOLEAN_TRUE || (b & 0x0f) == BOOLEAN_FALSE end COMPACT_TO_TTYPE = { Types::STOP => Types::STOP, BOOLEAN_FALSE => Types::BOOL, BOOLEAN_TRUE => Types::BOOL, BYTE => Types::BYTE, I16 => Types::I16, I32 => Types::I32, I64 => Types::I64, DOUBLE => Types::DOUBLE, BINARY => Types::STRING, LIST => Types::LIST, SET => Types::SET, MAP => Types::MAP, STRUCT => Types::STRUCT } TTYPE_TO_COMPACT = { Types::STOP => Types::STOP, Types::BOOL => BOOLEAN_TRUE, Types::BYTE => BYTE, Types::I16 => I16, Types::I32 => I32, Types::I64 => I64, Types::DOUBLE => DOUBLE, Types::STRING => BINARY, Types::LIST => LIST, Types::SET => SET, Types::MAP => MAP, Types::STRUCT => STRUCT } def self.get_ttype(compact_type) val = COMPACT_TO_TTYPE[compact_type & 0x0f] raise "don't know what type: #{compact_type & 0x0f}" unless val val end def self.get_compact_type(ttype) val = TTYPE_TO_COMPACT[ttype] raise "don't know what type: #{ttype & 0x0f}" unless val val end end def initialize(transport) super(transport) @last_field = [0] @boolean_value = nil # Pre-allocated read buffer for read_double(). @rbuf = Bytes.empty_byte_buffer(8) end def write_message_begin(name, type, seqid) write_byte(PROTOCOL_ID) write_byte((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK)) write_varint32(seqid) write_string(name) nil end def write_struct_begin(name) @last_field.push(0) nil end def write_struct_end @last_field.pop nil end def write_field_begin(name, type, id) if type == Types::BOOL # we want to possibly include the value, so we'll wait. @boolean_field = [type, id] else write_field_begin_internal(type, id) end nil end # # The workhorse of writeFieldBegin. It has the option of doing a # 'type override' of the type header. This is used specifically in the # boolean field case. # def write_field_begin_internal(type, id, type_override=nil) last_id = @last_field.pop # if there's a type override, use that. typeToWrite = type_override || CompactTypes.get_compact_type(type) # check if we can use delta encoding for the field id if id > last_id && id - last_id <= 15 # write them together write_byte((id - last_id) << 4 | typeToWrite) else # write them separate write_byte(typeToWrite) write_i16(id) end @last_field.push(id) nil end def write_field_stop write_byte(Types::STOP) end def write_map_begin(ktype, vtype, size) if (size == 0) write_byte(0) else write_varint32(size) write_byte(CompactTypes.get_compact_type(ktype) << 4 | CompactTypes.get_compact_type(vtype)) end end def write_list_begin(etype, size) write_collection_begin(etype, size) end def write_set_begin(etype, size) write_collection_begin(etype, size); end def write_bool(bool) type = bool ? CompactTypes::BOOLEAN_TRUE : CompactTypes::BOOLEAN_FALSE unless @boolean_field.nil? # we haven't written the field header yet write_field_begin_internal(@boolean_field.first, @boolean_field.last, type) @boolean_field = nil else # we're not part of a field, so just write the value. write_byte(type) end end def write_byte(byte) @trans.write([byte].pack('c')) end def write_i16(i16) write_varint32(int_to_zig_zag(i16)) end def write_i32(i32) write_varint32(int_to_zig_zag(i32)) end def write_i64(i64) write_varint64(long_to_zig_zag(i64)) end def write_double(dub) @trans.write([dub].pack("G").reverse) end def write_string(str) buf = Bytes.convert_to_utf8_byte_buffer(str) write_binary(buf) end def write_binary(buf) write_varint32(buf.bytesize) @trans.write(buf) end def read_message_begin protocol_id = read_byte() if protocol_id != PROTOCOL_ID raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}") end version_and_type = read_byte() version = version_and_type & VERSION_MASK if (version != VERSION) raise ProtocolException.new("Expected version #{VERSION} but got #{version}"); end type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS seqid = read_varint32() messageName = read_string() [messageName, type, seqid] end def read_struct_begin @last_field.push(0) "" end def read_struct_end @last_field.pop() nil end def read_field_begin type = read_byte() # if it's a stop, then we can return immediately, as the struct is over. if (type & 0x0f) == Types::STOP TSTOP else field_id = nil # mask off the 4 MSB of the type header. it could contain a field id delta. modifier = (type & 0xf0) >> 4 if modifier == 0 # not a delta. look ahead for the zigzag varint field id. @last_field.pop field_id = read_i16() else # has a delta. add the delta to the last read field id. field_id = @last_field.pop + modifier end # if this happens to be a boolean field, the value is encoded in the type if CompactTypes.is_bool_type?(type) # save the boolean value in a special instance variable. @bool_value = (type & 0x0f) == CompactTypes::BOOLEAN_TRUE end # push the new field onto the field stack so we can keep the deltas going. @last_field.push(field_id) ["", CompactTypes.get_ttype(type & 0x0f), field_id] end end def read_map_begin size = read_varint32() key_and_value_type = size == 0 ? 0 : read_byte() [CompactTypes.get_ttype(key_and_value_type >> 4), CompactTypes.get_ttype(key_and_value_type & 0xf), size] end def read_list_begin size_and_type = read_byte() size = (size_and_type >> 4) & 0x0f if size == 15 size = read_varint32() end type = CompactTypes.get_ttype(size_and_type) [type, size] end def read_set_begin read_list_begin end def read_bool unless @bool_value.nil? bv = @bool_value @bool_value = nil bv else read_byte() == CompactTypes::BOOLEAN_TRUE end end def read_byte val = trans.read_byte if (val > 0x7f) val = 0 - ((val - 1) ^ 0xff) end val end def read_i16 zig_zag_to_int(read_varint32()) end def read_i32 zig_zag_to_int(read_varint32()) end def read_i64 zig_zag_to_long(read_varint64()) end def read_double trans.read_into_buffer(@rbuf, 8) val = @rbuf.reverse.unpack('G').first val end def read_string buffer = read_binary Bytes.convert_to_string(buffer) end def read_binary size = read_varint32() trans.read_all(size) end def to_s "compact(#{super.to_s})" end private # # Abstract method for writing the start of lists and sets. List and sets on # the wire differ only by the type indicator. # def write_collection_begin(elem_type, size) if size <= 14 write_byte(size << 4 | CompactTypes.get_compact_type(elem_type)) else write_byte(0xf0 | CompactTypes.get_compact_type(elem_type)) write_varint32(size) end end def write_varint32(n) # int idx = 0; while true if (n & ~0x7F) == 0 # i32buf[idx++] = (byte)n; write_byte(n) break # return; else # i32buf[idx++] = (byte)((n & 0x7F) | 0x80); write_byte((n & 0x7F) | 0x80) n = n >> 7 end end # trans_.write(i32buf, 0, idx); end SEVEN_BIT_MASK = 0x7F EVERYTHING_ELSE_MASK = ~SEVEN_BIT_MASK def write_varint64(n) while true if (n & EVERYTHING_ELSE_MASK) == 0 #TODO need to find a way to make this into a long... write_byte(n) break else write_byte((n & SEVEN_BIT_MASK) | 0x80) n >>= 7 end end end def read_varint32() read_varint64() end def read_varint64() shift = 0 result = 0 while true b = read_byte() result |= (b & 0x7f) << shift break if (b & 0x80) != 0x80 shift += 7 end result end def int_to_zig_zag(n) (n << 1) ^ (n >> 31) end def long_to_zig_zag(l) # puts "zz encoded #{l} to #{(l << 1) ^ (l >> 63)}" (l << 1) ^ (l >> 63) end def zig_zag_to_int(n) (n >> 1) ^ -(n & 1) end def zig_zag_to_long(n) (n >> 1) ^ -(n & 1) end end class CompactProtocolFactory < BaseProtocolFactory def get_protocol(trans) CompactProtocol.new(trans) end def to_s "compact" end end end thrift-0.16.0/lib/rb/lib/thrift/protocol/json_protocol.rb000066400000000000000000000452701420101504100233710ustar00rootroot00000000000000# encoding: UTF-8 # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'base64' module Thrift class LookaheadReader def initialize(trans) @trans = trans @hasData = false @data = nil end def read if @hasData @hasData = false else @data = @trans.read(1) end return @data end def peek if !@hasData @data = @trans.read(1) end @hasData = true return @data end end # # Class to serve as base JSON context and as base class for other context # implementations # class JSONContext @@kJSONElemSeparator = ',' # # Write context data to the trans. Default is to do nothing. # def write(trans) end # # Read context data from the trans. Default is to do nothing. # def read(reader) end # # Return true if numbers need to be escaped as strings in this context. # Default behavior is to return false. # def escapeNum return false end end # Context class for object member key-value pairs class JSONPairContext < JSONContext @@kJSONPairSeparator = ':' def initialize @first = true @colon = true end def write(trans) if (@first) @first = false @colon = true else trans.write(@colon ? @@kJSONPairSeparator : @@kJSONElemSeparator) @colon = !@colon end end def read(reader) if (@first) @first = false @colon = true else ch = (@colon ? @@kJSONPairSeparator : @@kJSONElemSeparator) @colon = !@colon JsonProtocol::read_syntax_char(reader, ch) end end # Numbers must be turned into strings if they are the key part of a pair def escapeNum return @colon end end # Context class for lists class JSONListContext < JSONContext def initialize @first = true end def write(trans) if (@first) @first = false else trans.write(@@kJSONElemSeparator) end end def read(reader) if (@first) @first = false else JsonProtocol::read_syntax_char(reader, @@kJSONElemSeparator) end end end class JsonProtocol < BaseProtocol @@kJSONObjectStart = '{' @@kJSONObjectEnd = '}' @@kJSONArrayStart = '[' @@kJSONArrayEnd = ']' @@kJSONNewline = '\n' @@kJSONBackslash = '\\' @@kJSONStringDelimiter = '"' @@kThriftVersion1 = 1 @@kThriftNan = "NaN" @@kThriftInfinity = "Infinity" @@kThriftNegativeInfinity = "-Infinity" def initialize(trans) super(trans) @context = JSONContext.new @contexts = Array.new @reader = LookaheadReader.new(trans) end def get_type_name_for_type_id(id) case id when Types::BOOL "tf" when Types::BYTE "i8" when Types::I16 "i16" when Types::I32 "i32" when Types::I64 "i64" when Types::DOUBLE "dbl" when Types::STRING "str" when Types::STRUCT "rec" when Types::MAP "map" when Types::SET "set" when Types::LIST "lst" else raise NotImplementedError end end def get_type_id_for_type_name(name) if (name == "tf") result = Types::BOOL elsif (name == "i8") result = Types::BYTE elsif (name == "i16") result = Types::I16 elsif (name == "i32") result = Types::I32 elsif (name == "i64") result = Types::I64 elsif (name == "dbl") result = Types::DOUBLE elsif (name == "str") result = Types::STRING elsif (name == "rec") result = Types::STRUCT elsif (name == "map") result = Types::MAP elsif (name == "set") result = Types::SET elsif (name == "lst") result = Types::LIST else result = Types::STOP end if (result == Types::STOP) raise NotImplementedError end return result end # Static helper functions # Read 1 character from the trans and verify that it is the expected character ch. # Throw a protocol exception if it is not. def self.read_syntax_char(reader, ch) ch2 = reader.read if (ch2 != ch) raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected \'#{ch}\' got \'#{ch2}\'.") end end # Return true if the character ch is in [-+0-9.Ee]; false otherwise def is_json_numeric(ch) case ch when '+', '-', '.', '0' .. '9', 'E', "e" return true else return false end end def push_context(context) @contexts.push(@context) @context = context end def pop_context @context = @contexts.pop end # Write the character ch as a JSON escape sequence ("\u00xx") def write_json_escape_char(ch) trans.write('\\u') ch_value = ch[0] if (ch_value.kind_of? String) ch_value = ch.bytes.first end trans.write(ch_value.to_s(16).rjust(4,'0')) end # Write the character ch as part of a JSON string, escaping as appropriate. def write_json_char(ch) # This table describes the handling for the first 0x30 characters # 0 : escape using "\u00xx" notation # 1 : just output index # : escape using "\" notation kJSONCharTable = [ # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 0, 0, 0, 0, 0, 0, 0,'b','t','n', 0,'f','r', 0, 0, # 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 1 1, 1,'"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 2 ] ch_value = ch[0] if (ch_value.kind_of? String) ch_value = ch.bytes.first end if (ch_value >= 0x30) if (ch == @@kJSONBackslash) # Only special character >= 0x30 is '\' trans.write(@@kJSONBackslash) trans.write(@@kJSONBackslash) else trans.write(ch) end else outCh = kJSONCharTable[ch_value]; # Check if regular character, backslash escaped, or JSON escaped if outCh.kind_of? String trans.write(@@kJSONBackslash) trans.write(outCh) elsif outCh == 1 trans.write(ch) else write_json_escape_char(ch) end end end # Write out the contents of the string str as a JSON string, escaping characters as appropriate. def write_json_string(str) @context.write(trans) trans.write(@@kJSONStringDelimiter) str.split('').each do |ch| write_json_char(ch) end trans.write(@@kJSONStringDelimiter) end # Write out the contents of the string as JSON string, base64-encoding # the string's contents, and escaping as appropriate def write_json_base64(str) @context.write(trans) trans.write(@@kJSONStringDelimiter) trans.write(Base64.strict_encode64(str)) trans.write(@@kJSONStringDelimiter) end # Convert the given integer type to a JSON number, or a string # if the context requires it (eg: key in a map pair). def write_json_integer(num) @context.write(trans) escapeNum = @context.escapeNum if (escapeNum) trans.write(@@kJSONStringDelimiter) end trans.write(num.to_s); if (escapeNum) trans.write(@@kJSONStringDelimiter) end end # Convert the given double to a JSON string, which is either the number, # "NaN" or "Infinity" or "-Infinity". def write_json_double(num) @context.write(trans) # Normalize output of thrift::to_string for NaNs and Infinities special = false; if (num.nan?) special = true; val = @@kThriftNan; elsif (num.infinite?) special = true; val = @@kThriftInfinity; if (num < 0.0) val = @@kThriftNegativeInfinity; end else val = num.to_s end escapeNum = special || @context.escapeNum if (escapeNum) trans.write(@@kJSONStringDelimiter) end trans.write(val) if (escapeNum) trans.write(@@kJSONStringDelimiter) end end def write_json_object_start @context.write(trans) trans.write(@@kJSONObjectStart) push_context(JSONPairContext.new); end def write_json_object_end pop_context trans.write(@@kJSONObjectEnd) end def write_json_array_start @context.write(trans) trans.write(@@kJSONArrayStart) push_context(JSONListContext.new); end def write_json_array_end pop_context trans.write(@@kJSONArrayEnd) end def write_message_begin(name, type, seqid) write_json_array_start write_json_integer(@@kThriftVersion1) write_json_string(name) write_json_integer(type) write_json_integer(seqid) end def write_message_end write_json_array_end end def write_struct_begin(name) write_json_object_start end def write_struct_end write_json_object_end end def write_field_begin(name, type, id) write_json_integer(id) write_json_object_start write_json_string(get_type_name_for_type_id(type)) end def write_field_end write_json_object_end end def write_field_stop; nil; end def write_map_begin(ktype, vtype, size) write_json_array_start write_json_string(get_type_name_for_type_id(ktype)) write_json_string(get_type_name_for_type_id(vtype)) write_json_integer(size) write_json_object_start end def write_map_end write_json_object_end write_json_array_end end def write_list_begin(etype, size) write_json_array_start write_json_string(get_type_name_for_type_id(etype)) write_json_integer(size) end def write_list_end write_json_array_end end def write_set_begin(etype, size) write_json_array_start write_json_string(get_type_name_for_type_id(etype)) write_json_integer(size) end def write_set_end write_json_array_end end def write_bool(bool) write_json_integer(bool ? 1 : 0) end def write_byte(byte) write_json_integer(byte) end def write_i16(i16) write_json_integer(i16) end def write_i32(i32) write_json_integer(i32) end def write_i64(i64) write_json_integer(i64) end def write_double(dub) write_json_double(dub) end def write_string(str) write_json_string(str) end def write_binary(str) write_json_base64(str) end ## # Reading functions ## # Reads 1 byte and verifies that it matches ch. def read_json_syntax_char(ch) JsonProtocol::read_syntax_char(@reader, ch) end # Decodes the four hex parts of a JSON escaped string character and returns # the character via out. # # Note - this only supports Unicode characters in the BMP (U+0000 to U+FFFF); # characters above the BMP are encoded as two escape sequences (surrogate pairs), # which is not yet implemented def read_json_escape_char str = @reader.read str += @reader.read str += @reader.read str += @reader.read if RUBY_VERSION >= '1.9' str.hex.chr(Encoding::UTF_8) else str.hex.chr end end # Decodes a JSON string, including unescaping, and returns the string via str def read_json_string(skipContext = false) # This string's characters must match up with the elements in escape_char_vals. # I don't have '/' on this list even though it appears on www.json.org -- # it is not in the RFC -> it is. See RFC 4627 escape_chars = "\"\\/bfnrt" # The elements of this array must match up with the sequence of characters in # escape_chars escape_char_vals = [ "\"", "\\", "\/", "\b", "\f", "\n", "\r", "\t", ] if !skipContext @context.read(@reader) end read_json_syntax_char(@@kJSONStringDelimiter) ch = "" str = "" while (true) ch = @reader.read if (ch == @@kJSONStringDelimiter) break end if (ch == @@kJSONBackslash) ch = @reader.read if (ch == 'u') ch = read_json_escape_char else pos = escape_chars.index(ch); if (pos.nil?) # not found raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected control char, got \'#{ch}\'.") end ch = escape_char_vals[pos] end end str += ch end return str end # Reads a block of base64 characters, decoding it, and returns via str def read_json_base64 str = read_json_string m = str.length % 4 if m != 0 # Add missing padding (4 - m).times do str += '=' end end Base64.strict_decode64(str) end # Reads a sequence of characters, stopping at the first one that is not # a valid JSON numeric character. def read_json_numeric_chars str = "" while (true) ch = @reader.peek if (!is_json_numeric(ch)) break; end ch = @reader.read str += ch end return str end # Reads a sequence of characters and assembles them into a number, # returning them via num def read_json_integer @context.read(@reader) if (@context.escapeNum) read_json_syntax_char(@@kJSONStringDelimiter) end str = read_json_numeric_chars begin num = Integer(str); rescue raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"") end if (@context.escapeNum) read_json_syntax_char(@@kJSONStringDelimiter) end return num end # Reads a JSON number or string and interprets it as a double. def read_json_double @context.read(@reader) num = 0 if (@reader.peek == @@kJSONStringDelimiter) str = read_json_string(true) # Check for NaN, Infinity and -Infinity if (str == @@kThriftNan) num = (+1.0/0.0)/(+1.0/0.0) elsif (str == @@kThriftInfinity) num = +1.0/0.0 elsif (str == @@kThriftNegativeInfinity) num = -1.0/0.0 else if (!@context.escapeNum) # Raise exception -- we should not be in a string in this case raise ProtocolException.new(ProtocolException::INVALID_DATA, "Numeric data unexpectedly quoted") end begin num = Float(str) rescue raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"") end end else if (@context.escapeNum) # This will throw - we should have had a quote if escapeNum == true read_json_syntax_char(@@kJSONStringDelimiter) end str = read_json_numeric_chars begin num = Float(str) rescue raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"") end end return num end def read_json_object_start @context.read(@reader) read_json_syntax_char(@@kJSONObjectStart) push_context(JSONPairContext.new) nil end def read_json_object_end read_json_syntax_char(@@kJSONObjectEnd) pop_context nil end def read_json_array_start @context.read(@reader) read_json_syntax_char(@@kJSONArrayStart) push_context(JSONListContext.new) nil end def read_json_array_end read_json_syntax_char(@@kJSONArrayEnd) pop_context nil end def read_message_begin read_json_array_start version = read_json_integer if (version != @@kThriftVersion1) raise ProtocolException.new(ProtocolException::BAD_VERSION, 'Message contained bad version.') end name = read_json_string message_type = read_json_integer seqid = read_json_integer [name, message_type, seqid] end def read_message_end read_json_array_end nil end def read_struct_begin read_json_object_start nil end def read_struct_end read_json_object_end nil end def read_field_begin # Check if we hit the end of the list ch = @reader.peek if (ch == @@kJSONObjectEnd) field_type = Types::STOP else field_id = read_json_integer read_json_object_start field_type = get_type_id_for_type_name(read_json_string) end [nil, field_type, field_id] end def read_field_end read_json_object_end end def read_map_begin read_json_array_start key_type = get_type_id_for_type_name(read_json_string) val_type = get_type_id_for_type_name(read_json_string) size = read_json_integer read_json_object_start [key_type, val_type, size] end def read_map_end read_json_object_end read_json_array_end end def read_list_begin read_json_array_start [get_type_id_for_type_name(read_json_string), read_json_integer] end def read_list_end read_json_array_end end def read_set_begin read_json_array_start [get_type_id_for_type_name(read_json_string), read_json_integer] end def read_set_end read_json_array_end end def read_bool byte = read_byte byte != 0 end def read_byte read_json_integer end def read_i16 read_json_integer end def read_i32 read_json_integer end def read_i64 read_json_integer end def read_double read_json_double end def read_string read_json_string end def read_binary read_json_base64 end def to_s "json(#{super.to_s})" end end class JsonProtocolFactory < BaseProtocolFactory def get_protocol(trans) return Thrift::JsonProtocol.new(trans) end def to_s "json" end end end thrift-0.16.0/lib/rb/lib/thrift/protocol/multiplexed_protocol.rb000066400000000000000000000025711420101504100247510ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. require 'thrift/protocol/protocol_decorator' module Thrift class MultiplexedProtocol < BaseProtocol include ProtocolDecorator def initialize(protocol, service_name) super(protocol) @service_name = service_name end def write_message_begin(name, type, seqid) case type when MessageTypes::CALL, MessageTypes::ONEWAY @protocol.write_message_begin("#{@service_name}:#{name}", type, seqid) else @protocol.write_message_begin(name, type, seqid) end end def to_s "multiplexed(#{@service_name=@protocol.to_s})" end end end thrift-0.16.0/lib/rb/lib/thrift/protocol/protocol_decorator.rb000066400000000000000000000071611420101504100243770ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. module Thrift module ProtocolDecorator def initialize(protocol) @protocol = protocol end def trans @protocol.trans end def write_message_begin(name, type, seqid) @protocol.write_message_begin end def write_message_end @protocol.write_message_end end def write_struct_begin(name) @protocol.write_struct_begin(name) end def write_struct_end @protocol.write_struct_end end def write_field_begin(name, type, id) @protocol.write_field_begin(name, type, id) end def write_field_end @protocol.write_field_end end def write_field_stop @protocol.write_field_stop end def write_map_begin(ktype, vtype, size) @protocol.write_map_begin(ktype, vtype, size) end def write_map_end @protocol.write_map_end end def write_list_begin(etype, size) @protocol.write_list_begin(etype, size) end def write_list_end @protocol.write_list_end end def write_set_begin(etype, size) @protocol.write_set_begin(etype, size) end def write_set_end @protocol.write_set_end end def write_bool(bool) @protocol.write_bool(bool) end def write_byte(byte) @protocol.write_byte(byte) end def write_i16(i16) @protocol.write_i16(i16) end def write_i32(i32) @protocol.write_i32(i32) end def write_i64(i64) @protocol.write_i64(i64) end def write_double(dub) @protocol.write_double(dub) end def write_string(str) @protocol.write_string(str) end def write_binary(buf) @protocol.write_binary(buf) end def read_message_begin @protocol.read_message_begin end def read_message_end @protocol.read_message_end end def read_struct_begin @protocol.read_struct_begin end def read_struct_end @protocol.read_struct_end end def read_field_begin @protocol.read_field_begin end def read_field_end @protocol.read_field_end end def read_map_begin @protocol.read_map_begin end def read_map_end @protocol.read_map_end end def read_list_begin @protocol.read_list_begin end def read_list_end @protocol.read_list_end end def read_set_begin @protocol.read_set_begin end def read_set_end @protocol.read_set_end end def read_bool @protocol.read_bool end def read_byte @protocol.read_byte end def read_i16 @protocol.read_i16 end def read_i32 @protocol.read_i32 end def read_i64 @protocol.read_i64 end def read_double @protocol.read_double end def read_string @protocol.read_string end def read_binary @protocol.read_binary end end endthrift-0.16.0/lib/rb/lib/thrift/serializer/000077500000000000000000000000001420101504100204525ustar00rootroot00000000000000thrift-0.16.0/lib/rb/lib/thrift/serializer/deserializer.rb000066400000000000000000000021531420101504100234620ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class Deserializer def initialize(protocol_factory = BinaryProtocolFactory.new) @transport = MemoryBufferTransport.new @protocol = protocol_factory.get_protocol(@transport) end def deserialize(base, buffer) @transport.reset_buffer(buffer) base.read(@protocol) base end end endthrift-0.16.0/lib/rb/lib/thrift/serializer/serializer.rb000066400000000000000000000021731420101504100231530ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class Serializer def initialize(protocol_factory = BinaryProtocolFactory.new) @transport = MemoryBufferTransport.new @protocol = protocol_factory.get_protocol(@transport) end def serialize(base) @transport.reset_buffer base.write(@protocol) @transport.read(@transport.available) end end end thrift-0.16.0/lib/rb/lib/thrift/server/000077500000000000000000000000001420101504100176075ustar00rootroot00000000000000thrift-0.16.0/lib/rb/lib/thrift/server/base_server.rb000066400000000000000000000025411420101504100224360ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class BaseServer def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil) @processor = processor @server_transport = server_transport @transport_factory = transport_factory ? transport_factory : Thrift::BaseTransportFactory.new @protocol_factory = protocol_factory ? protocol_factory : Thrift::BinaryProtocolFactory.new end def serve raise NotImplementedError end def to_s "server(#{@protocol_factory.to_s}(#{@transport_factory.to_s}(#{@server_transport.to_s})))" end end end thrift-0.16.0/lib/rb/lib/thrift/server/mongrel_http_server.rb000066400000000000000000000041761420101504100242340ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'mongrel' ## Sticks a service on a URL, using mongrel to do the HTTP work # DEPRECATED: Please use Thrift::ThinHTTPServer instead. module Thrift class MongrelHTTPServer < BaseServer class Handler < Mongrel::HttpHandler def initialize(processor, protocol_factory) @processor = processor @protocol_factory = protocol_factory end def process(request, response) if request.params["REQUEST_METHOD"] == "POST" response.start(200) do |head, out| head["Content-Type"] = "application/x-thrift" transport = IOStreamTransport.new request.body, out protocol = @protocol_factory.get_protocol transport @processor.process protocol, protocol end else response.start(404) { } end end end def initialize(processor, opts={}) Kernel.warn "[DEPRECATION WARNING] `Thrift::MongrelHTTPServer` is deprecated. Please use `Thrift::ThinHTTPServer` instead." port = opts[:port] || 80 ip = opts[:ip] || "0.0.0.0" path = opts[:path] || "" protocol_factory = opts[:protocol_factory] || BinaryProtocolFactory.new @server = Mongrel::HttpServer.new ip, port @server.register "/#{path}", Handler.new(processor, protocol_factory) end def serve @server.run.join end end end thrift-0.16.0/lib/rb/lib/thrift/server/nonblocking_server.rb000066400000000000000000000216601420101504100240320ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'logger' require 'thread' module Thrift # this class expects to always use a FramedTransport for reading messages class NonblockingServer < BaseServer def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20, logger=nil) super(processor, server_transport, transport_factory, protocol_factory) @num_threads = num if logger.nil? @logger = Logger.new(STDERR) @logger.level = Logger::WARN else @logger = logger end @shutdown_semaphore = Mutex.new @transport_semaphore = Mutex.new end def serve @logger.info "Starting #{self}" @server_transport.listen @io_manager = start_io_manager begin loop do break if @server_transport.closed? begin rd, = select([@server_transport], nil, nil, 0.1) rescue Errno::EBADF => e # In Ruby 1.9, calling @server_transport.close in shutdown paths causes the select() to raise an # Errno::EBADF. If this happens, ignore it and retry the loop. break end next if rd.nil? socket = @server_transport.accept @logger.debug "Accepted socket: #{socket.inspect}" @io_manager.add_connection socket end rescue IOError => e end # we must be shutting down @logger.info "#{self} is shutting down, goodbye" ensure @transport_semaphore.synchronize do @server_transport.close end @io_manager.ensure_closed unless @io_manager.nil? end def shutdown(timeout = 0, block = true) @shutdown_semaphore.synchronize do return if @is_shutdown @is_shutdown = true end # nonblocking is intended for calling from within a Handler # but we can't change the order of operations here, so lets thread shutdown_proc = lambda do @io_manager.shutdown(timeout) @transport_semaphore.synchronize do @server_transport.close # this will break the accept loop end end if block shutdown_proc.call else Thread.new &shutdown_proc end end private def start_io_manager iom = IOManager.new(@processor, @server_transport, @transport_factory, @protocol_factory, @num_threads, @logger) iom.spawn iom end class IOManager # :nodoc: DEFAULT_BUFFER = 2**20 def initialize(processor, server_transport, transport_factory, protocol_factory, num, logger) @processor = processor @server_transport = server_transport @transport_factory = transport_factory @protocol_factory = protocol_factory @num_threads = num @logger = logger @connections = [] @buffers = Hash.new { |h,k| h[k] = '' } @signal_queue = Queue.new @signal_pipes = IO.pipe @signal_pipes[1].sync = true @worker_queue = Queue.new @shutdown_queue = Queue.new end def add_connection(socket) signal [:connection, socket] end def spawn @iom_thread = Thread.new do @logger.debug "Starting #{self}" run end end def shutdown(timeout = 0) @logger.debug "#{self} is shutting down workers" @worker_queue.clear @num_threads.times { @worker_queue.push [:shutdown] } signal [:shutdown, timeout] @shutdown_queue.pop @signal_pipes[0].close @signal_pipes[1].close @logger.debug "#{self} is shutting down, goodbye" end def ensure_closed kill_worker_threads if @worker_threads @iom_thread.kill end private def run spin_worker_threads loop do rd, = select([@signal_pipes[0], *@connections]) if rd.delete @signal_pipes[0] break if read_signals == :shutdown end rd.each do |fd| begin if fd.handle.eof? remove_connection fd else read_connection fd end rescue Errno::ECONNRESET remove_connection fd end end end join_worker_threads(@shutdown_timeout) ensure @shutdown_queue.push :shutdown end def read_connection(fd) @buffers[fd] << fd.read(DEFAULT_BUFFER) while(frame = slice_frame!(@buffers[fd])) @logger.debug "#{self} is processing a frame" @worker_queue.push [:frame, fd, frame] end end def spin_worker_threads @logger.debug "#{self} is spinning up worker threads" @worker_threads = [] @num_threads.times do @worker_threads << spin_thread end end def spin_thread Worker.new(@processor, @transport_factory, @protocol_factory, @logger, @worker_queue).spawn end def signal(msg) @signal_queue << msg @signal_pipes[1].write " " end def read_signals # clear the signal pipe # note that since read_nonblock is broken in jruby, # we can only read up to a set number of signals at once sigstr = @signal_pipes[0].readpartial(1024) # now read the signals begin sigstr.length.times do signal, obj = @signal_queue.pop(true) case signal when :connection @connections << obj when :shutdown @shutdown_timeout = obj return :shutdown end end rescue ThreadError # out of signals # note that in a perfect world this would never happen, since we're # only reading the number of signals pushed on the pipe, but given the lack # of locks, in theory we could clear the pipe/queue while a new signal is being # placed on the pipe, at which point our next read_signals would hit this error end end def remove_connection(fd) # don't explicitly close it, a thread may still be writing to it @connections.delete fd @buffers.delete fd end def join_worker_threads(shutdown_timeout) start = Time.now @worker_threads.each do |t| if shutdown_timeout > 0 timeout = (start + shutdown_timeout) - Time.now break if timeout <= 0 t.join(timeout) else t.join end end kill_worker_threads end def kill_worker_threads @worker_threads.each do |t| t.kill if t.status end @worker_threads.clear end def slice_frame!(buf) if buf.length >= 4 size = buf.unpack('N').first if buf.length >= size + 4 buf.slice!(0, size + 4) else nil end else nil end end class Worker # :nodoc: def initialize(processor, transport_factory, protocol_factory, logger, queue) @processor = processor @transport_factory = transport_factory @protocol_factory = protocol_factory @logger = logger @queue = queue end def spawn Thread.new do @logger.debug "#{self} is spawning" run end end private def run loop do cmd, *args = @queue.pop case cmd when :shutdown @logger.debug "#{self} is shutting down, goodbye" break when :frame fd, frame = args begin otrans = @transport_factory.get_transport(fd) oprot = @protocol_factory.get_protocol(otrans) membuf = MemoryBufferTransport.new(frame) itrans = @transport_factory.get_transport(membuf) iprot = @protocol_factory.get_protocol(itrans) @processor.process(iprot, oprot) rescue => e @logger.error "#{Thread.current.inspect} raised error: #{e.inspect}\n#{e.backtrace.join("\n")}" end end end end end end end end thrift-0.16.0/lib/rb/lib/thrift/server/simple_server.rb000066400000000000000000000026321420101504100230160ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class SimpleServer < BaseServer def serve begin @server_transport.listen loop do client = @server_transport.accept trans = @transport_factory.get_transport(client) prot = @protocol_factory.get_protocol(trans) begin loop do @processor.process(prot, prot) end rescue Thrift::TransportException, Thrift::ProtocolException ensure trans.close end end ensure @server_transport.close end end def to_s "simple(#{super.to_s})" end end end thrift-0.16.0/lib/rb/lib/thrift/server/thin_http_server.rb000066400000000000000000000053301420101504100235240ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'rack' require 'thin' ## # Wraps the Thin web server to provide a Thrift server over HTTP. module Thrift class ThinHTTPServer < BaseServer ## # Accepts a Thrift::Processor # Options include: # * :port # * :ip # * :path # * :protocol_factory def initialize(processor, options={}) port = options[:port] || 80 ip = options[:ip] || "0.0.0.0" path = options[:path] || "/" protocol_factory = options[:protocol_factory] || BinaryProtocolFactory.new app = RackApplication.for(path, processor, protocol_factory) @server = Thin::Server.new(ip, port, app) end ## # Starts the server def serve @server.start end class RackApplication THRIFT_HEADER = "application/x-thrift" def self.for(path, processor, protocol_factory) Rack::Builder.new do use Rack::CommonLogger use Rack::ShowExceptions use Rack::Lint map path do run lambda { |env| request = Rack::Request.new(env) if RackApplication.valid_thrift_request?(request) RackApplication.successful_request(request, processor, protocol_factory) else RackApplication.failed_request end } end end end def self.successful_request(rack_request, processor, protocol_factory) response = Rack::Response.new([], 200, {'Content-Type' => THRIFT_HEADER}) transport = IOStreamTransport.new rack_request.body, response protocol = protocol_factory.get_protocol transport processor.process protocol, protocol response end def self.failed_request Rack::Response.new(['Not Found'], 404, {'Content-Type' => THRIFT_HEADER}) end def self.valid_thrift_request?(rack_request) rack_request.post? && rack_request.env["CONTENT_TYPE"] == THRIFT_HEADER end end end end thrift-0.16.0/lib/rb/lib/thrift/server/thread_pool_server.rb000066400000000000000000000047501420101504100240300ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'thread' module Thrift class ThreadPoolServer < BaseServer def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20) super(processor, server_transport, transport_factory, protocol_factory) @thread_q = SizedQueue.new(num) @exception_q = Queue.new @running = false end ## exceptions that happen in worker threads will be relayed here and ## must be caught. 'retry' can be used to continue. (threads will ## continue to run while the exception is being handled.) def rescuable_serve Thread.new { serve } unless @running @running = true raise @exception_q.pop end ## exceptions that happen in worker threads simply cause that thread ## to die and another to be spawned in its place. def serve @server_transport.listen begin loop do @thread_q.push(:token) Thread.new do begin loop do client = @server_transport.accept trans = @transport_factory.get_transport(client) prot = @protocol_factory.get_protocol(trans) begin loop do @processor.process(prot, prot) end rescue Thrift::TransportException, Thrift::ProtocolException => e ensure trans.close end end rescue => e @exception_q.push(e) ensure @thread_q.pop # thread died! end end end ensure @server_transport.close end end def to_s "threadpool(#{super.to_s})" end end end thrift-0.16.0/lib/rb/lib/thrift/server/threaded_server.rb000066400000000000000000000027601420101504100233070ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'thread' module Thrift class ThreadedServer < BaseServer def serve begin @server_transport.listen loop do client = @server_transport.accept trans = @transport_factory.get_transport(client) prot = @protocol_factory.get_protocol(trans) Thread.new(prot, trans) do |p, t| begin loop do @processor.process(p, p) end rescue Thrift::TransportException, Thrift::ProtocolException ensure t.close end end end ensure @server_transport.close end end def to_s "threaded(#{super.to_s})" end end end thrift-0.16.0/lib/rb/lib/thrift/struct.rb000066400000000000000000000167421420101504100201640ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'set' module Thrift module Struct def initialize(d={}, &block) # get a copy of the default values to work on, removing defaults in favor of arguments fields_with_defaults = fields_with_default_values.dup # check if the defaults is empty, or if there are no parameters for this # instantiation, and if so, don't bother overriding defaults. unless fields_with_defaults.empty? || d.empty? d.each_key do |name| fields_with_defaults.delete(name.to_s) end end # assign all the user-specified arguments unless d.empty? d.each do |name, value| unless name_to_id(name.to_s) raise Exception, "Unknown key given to #{self.class}.new: #{name}" end Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking instance_variable_set("@#{name}", value) end end # assign all the default values unless fields_with_defaults.empty? fields_with_defaults.each do |name, default_value| instance_variable_set("@#{name}", (default_value.dup rescue default_value)) end end yield self if block_given? end def fields_with_default_values fields_with_default_values = self.class.instance_variable_get(:@fields_with_default_values) unless fields_with_default_values fields_with_default_values = {} struct_fields.each do |fid, field_def| unless field_def[:default].nil? fields_with_default_values[field_def[:name]] = field_def[:default] end end self.class.instance_variable_set(:@fields_with_default_values, fields_with_default_values) end fields_with_default_values end def inspect(skip_optional_nulls = true) fields = [] each_field do |fid, field_info| name = field_info[:name] value = instance_variable_get("@#{name}") unless skip_optional_nulls && field_info[:optional] && value.nil? fields << "#{name}:#{inspect_field(value, field_info)}" end end "<#{self.class} #{fields.join(", ")}>" end def read(iprot) iprot.read_struct_begin loop do fname, ftype, fid = iprot.read_field_begin break if (ftype == Types::STOP) handle_message(iprot, fid, ftype) iprot.read_field_end end iprot.read_struct_end validate end def write(oprot) validate oprot.write_struct_begin(self.class.name) each_field do |fid, field_info| name = field_info[:name] type = field_info[:type] value = instance_variable_get("@#{name}") unless value.nil? if is_container? type oprot.write_field_begin(name, type, fid) write_container(oprot, value, field_info) oprot.write_field_end else oprot.write_field(field_info, fid, value) end end end oprot.write_field_stop oprot.write_struct_end end def ==(other) return false if other.nil? each_field do |fid, field_info| name = field_info[:name] return false unless other.respond_to?(name) && self.send(name) == other.send(name) end true end def eql?(other) self.class == other.class && self == other end # This implementation of hash() is inspired by Apache's Java HashCodeBuilder class. def hash total = 17 each_field do |fid, field_info| name = field_info[:name] value = self.send(name) total = (total * 37 + value.hash) & 0xffffffff end total end def differences(other) diffs = [] unless other.is_a?(self.class) diffs << "Different class!" else each_field do |fid, field_info| name = field_info[:name] diffs << "#{name} differs!" unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}") end end diffs end def self.field_accessor(klass, field_info) field_name_sym = field_info[:name].to_sym klass.send :attr_reader, field_name_sym klass.send :define_method, "#{field_info[:name]}=" do |value| Thrift.check_type(value, field_info, field_info[:name]) if Thrift.type_checking instance_variable_set("@#{field_name_sym}", value) end end def self.generate_accessors(klass) klass::FIELDS.values.each do |field_info| field_accessor(klass, field_info) qmark_isset_method(klass, field_info) end end def self.qmark_isset_method(klass, field_info) klass.send :define_method, "#{field_info[:name]}?" do !self.send(field_info[:name].to_sym).nil? end end def <=>(other) if self.class == other.class each_field do |fid, field_info| v1 = self.send(field_info[:name]) v1_set = !v1.nil? v2 = other.send(field_info[:name]) v2_set = !v2.nil? if v1_set && !v2_set return -1 elsif !v1_set && v2_set return 1 elsif v1_set && v2_set cmp = v1 <=> v2 if cmp != 0 return cmp end end end 0 else self.class <=> other.class end end protected def self.append_features(mod) if mod.ancestors.include? ::Exception mod.send :class_variable_set, :'@@__thrift_struct_real_initialize', mod.instance_method(:initialize) super # set up our custom initializer so `raise Xception, 'message'` works mod.send :define_method, :struct_initialize, mod.instance_method(:initialize) mod.send :define_method, :initialize, mod.instance_method(:exception_initialize) else super end end def exception_initialize(*args, &block) if args.size == 1 and args.first.is_a? Hash # looks like it's a regular Struct initialize method(:struct_initialize).call(args.first) else # call the Struct initializer first with no args # this will set our field default values method(:struct_initialize).call() # now give it to the exception self.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind(self).call(*args, &block) if args.size > 0 # self.class.instance_method(:initialize).bind(self).call(*args, &block) end end def handle_message(iprot, fid, ftype) field = struct_fields[fid] if field and field[:type] == ftype value = read_field(iprot, field) instance_variable_set("@#{field[:name]}", value) else iprot.skip(ftype) end end end end thrift-0.16.0/lib/rb/lib/thrift/struct_union.rb000066400000000000000000000136161420101504100213710ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'set' module Thrift module Struct_Union def name_to_id(name) names_to_ids = self.class.instance_variable_get(:@names_to_ids) unless names_to_ids names_to_ids = {} struct_fields.each do |fid, field_def| names_to_ids[field_def[:name]] = fid end self.class.instance_variable_set(:@names_to_ids, names_to_ids) end names_to_ids[name] end def sorted_field_ids sorted_field_ids = self.class.instance_variable_get(:@sorted_field_ids) unless sorted_field_ids sorted_field_ids = struct_fields.keys.sort self.class.instance_variable_set(:@sorted_field_ids, sorted_field_ids) end sorted_field_ids end def each_field sorted_field_ids.each do |fid| data = struct_fields[fid] yield fid, data end end def read_field(iprot, field = {}) case field[:type] when Types::STRUCT value = field[:class].new value.read(iprot) when Types::MAP key_type, val_type, size = iprot.read_map_begin # Skip the map contents if the declared key or value types don't match the expected ones. if (size != 0 && (key_type != field[:key][:type] || val_type != field[:value][:type])) size.times do iprot.skip(key_type) iprot.skip(val_type) end value = nil else value = {} size.times do k = read_field(iprot, field_info(field[:key])) v = read_field(iprot, field_info(field[:value])) value[k] = v end end iprot.read_map_end when Types::LIST e_type, size = iprot.read_list_begin # Skip the list contents if the declared element type doesn't match the expected one. if (e_type != field[:element][:type]) size.times do iprot.skip(e_type) end value = nil else value = Array.new(size) do |n| read_field(iprot, field_info(field[:element])) end end iprot.read_list_end when Types::SET e_type, size = iprot.read_set_begin # Skip the set contents if the declared element type doesn't match the expected one. if (e_type != field[:element][:type]) size.times do iprot.skip(e_type) end else value = Set.new size.times do element = read_field(iprot, field_info(field[:element])) value << element end end iprot.read_set_end else value = iprot.read_type(field) end value end def write_data(oprot, value, field) if is_container? field[:type] write_container(oprot, value, field) else oprot.write_type(field, value) end end def write_container(oprot, value, field = {}) case field[:type] when Types::MAP oprot.write_map_begin(field[:key][:type], field[:value][:type], value.size) value.each do |k, v| write_data(oprot, k, field[:key]) write_data(oprot, v, field[:value]) end oprot.write_map_end when Types::LIST oprot.write_list_begin(field[:element][:type], value.size) value.each do |elem| write_data(oprot, elem, field[:element]) end oprot.write_list_end when Types::SET oprot.write_set_begin(field[:element][:type], value.size) value.each do |v,| # the , is to preserve compatibility with the old Hash-style sets write_data(oprot, v, field[:element]) end oprot.write_set_end else raise "Not a container type: #{field[:type]}" end end CONTAINER_TYPES = [] CONTAINER_TYPES[Types::LIST] = true CONTAINER_TYPES[Types::MAP] = true CONTAINER_TYPES[Types::SET] = true def is_container?(type) CONTAINER_TYPES[type] end def field_info(field) { :type => field[:type], :class => field[:class], :key => field[:key], :value => field[:value], :element => field[:element] } end def inspect_field(value, field_info) if enum_class = field_info[:enum_class] "#{enum_class.const_get(:VALUE_MAP)[value]} (#{value})" elsif value.is_a? Hash if field_info[:type] == Types::MAP map_buf = [] value.each do |k, v| map_buf << inspect_field(k, field_info[:key]) + ": " + inspect_field(v, field_info[:value]) end "{" + map_buf.join(", ") + "}" else # old-style set inspect_collection(value.keys, field_info) end elsif value.is_a? Array inspect_collection(value, field_info) elsif value.is_a? Set inspect_collection(value, field_info) elsif value.is_a?(String) && field_info[:binary] value.unpack("H*").first else value.inspect end end def inspect_collection(collection, field_info) buf = [] collection.each do |k| buf << inspect_field(k, field_info[:element]) end "[" + buf.join(", ") + "]" end end endthrift-0.16.0/lib/rb/lib/thrift/thrift_native.rb000066400000000000000000000016321420101504100214760ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # begin require "thrift_native" rescue LoadError puts "Unable to load thrift_native extension. Defaulting to pure Ruby libraries." endthrift-0.16.0/lib/rb/lib/thrift/transport/000077500000000000000000000000001420101504100203355ustar00rootroot00000000000000thrift-0.16.0/lib/rb/lib/thrift/transport/base_server_transport.rb000066400000000000000000000020501420101504100252730ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class BaseServerTransport def listen raise NotImplementedError end def accept raise NotImplementedError end def close; nil; end def closed? raise NotImplementedError end end end thrift-0.16.0/lib/rb/lib/thrift/transport/base_transport.rb000066400000000000000000000054771420101504100237250ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class TransportException < Exception UNKNOWN = 0 NOT_OPEN = 1 ALREADY_OPEN = 2 TIMED_OUT = 3 END_OF_FILE = 4 attr_reader :type def initialize(type=UNKNOWN, message=nil) super(message) @type = type end end module TransportUtils # Deprecated: Use Thrift::Bytes instead def self.get_string_byte(string, index) Bytes.get_string_byte(string, index) end # Deprecated: Use Thrift::Bytes instead def self.set_string_byte(string, index, byte) Bytes.set_string_byte(string, index, byte) end end class BaseTransport def open?; end def open; end def close; end # Reads a number of bytes from the transports. In Ruby 1.9+, the String returned will have a BINARY (aka ASCII8BIT) encoding. # # sz - The number of bytes to read from the transport. # # Returns a String acting as a byte buffer. def read(sz) raise NotImplementedError end # Returns an unsigned byte as a Fixnum in the range (0..255). def read_byte buf = read_all(1) return Bytes.get_string_byte(buf, 0) end # Reads size bytes and copies them into buffer[0..size]. def read_into_buffer(buffer, size) tmp = read_all(size) i = 0 tmp.each_byte do |byte| Bytes.set_string_byte(buffer, i, byte) i += 1 end i end def read_all(size) return Bytes.empty_byte_buffer if size <= 0 buf = read(size) while (buf.length < size) chunk = read(size - buf.length) buf << chunk end buf end # Writes the byte buffer to the transport. In Ruby 1.9+, the buffer will be forced into BINARY encoding. # # buf - A String acting as a byte buffer. # # Returns nothing. def write(buf); end alias_method :<<, :write def flush; end def to_s "base" end end class BaseTransportFactory def get_transport(trans) return trans end def to_s "base" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/buffered_transport.rb000066400000000000000000000063541420101504100245700ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class BufferedTransport < BaseTransport DEFAULT_BUFFER = 4096 def initialize(transport) @transport = transport @wbuf = Bytes.empty_byte_buffer @rbuf = Bytes.empty_byte_buffer @index = 0 end def open? return @transport.open? end def open @transport.open end def close flush @transport.close end def read(sz) @index += sz ret = @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer if ret.length == 0 @rbuf = @transport.read([sz, DEFAULT_BUFFER].max) @index = sz ret = @rbuf.slice(0, sz) || Bytes.empty_byte_buffer end ret end def read_byte # If the read buffer is exhausted, try to read up to DEFAULT_BUFFER more bytes into it. if @index >= @rbuf.size @rbuf = @transport.read(DEFAULT_BUFFER) @index = 0 end # The read buffer has some data now, read a single byte. Using get_string_byte() avoids # allocating a temp string of size 1 unnecessarily. @index += 1 return Bytes.get_string_byte(@rbuf, @index - 1) end # Reads a number of bytes from the transport into the buffer passed. # # buffer - The String (byte buffer) to write data to; this is assumed to have a BINARY encoding. # size - The number of bytes to read from the transport and write to the buffer. # # Returns the number of bytes read. def read_into_buffer(buffer, size) i = 0 while i < size # If the read buffer is exhausted, try to read up to DEFAULT_BUFFER more bytes into it. if @index >= @rbuf.size @rbuf = @transport.read(DEFAULT_BUFFER) @index = 0 end # The read buffer has some data now, so copy bytes over to the output buffer. byte = Bytes.get_string_byte(@rbuf, @index) Bytes.set_string_byte(buffer, i, byte) @index += 1 i += 1 end i end def write(buf) @wbuf << Bytes.force_binary_encoding(buf) end def flush unless @wbuf.empty? @transport.write(@wbuf) @wbuf = Bytes.empty_byte_buffer end @transport.flush end def to_s "buffered(#{@transport.to_s})" end end class BufferedTransportFactory < BaseTransportFactory def get_transport(transport) return BufferedTransport.new(transport) end def to_s "buffered" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/framed_transport.rb000066400000000000000000000062271420101504100242430ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class FramedTransport < BaseTransport def initialize(transport, read=true, write=true) @transport = transport @rbuf = Bytes.empty_byte_buffer @wbuf = Bytes.empty_byte_buffer @read = read @write = write @index = 0 end def open? @transport.open? end def open @transport.open end def close @transport.close end def read(sz) return @transport.read(sz) unless @read return Bytes.empty_byte_buffer if sz <= 0 read_frame if @index >= @rbuf.length @index += sz @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer end def read_byte return @transport.read_byte() unless @read read_frame if @index >= @rbuf.length # The read buffer has some data now, read a single byte. Using get_string_byte() avoids # allocating a temp string of size 1 unnecessarily. @index += 1 return Bytes.get_string_byte(@rbuf, @index - 1) end def read_into_buffer(buffer, size) i = 0 while i < size read_frame if @index >= @rbuf.length # The read buffer has some data now, so copy bytes over to the output buffer. byte = Bytes.get_string_byte(@rbuf, @index) Bytes.set_string_byte(buffer, i, byte) @index += 1 i += 1 end i end def write(buf, sz=nil) return @transport.write(buf) unless @write buf = Bytes.force_binary_encoding(buf) @wbuf << (sz ? buf[0...sz] : buf) end # # Writes the output buffer to the stream in the format of a 4-byte length # followed by the actual data. # def flush return @transport.flush unless @write out = [@wbuf.length].pack('N') # Array#pack should return a BINARY encoded String, so it shouldn't be necessary to force encoding out << @wbuf @transport.write(out) @transport.flush @wbuf = Bytes.empty_byte_buffer end def to_s "framed(#{@transport.to_s})" end private def read_frame sz = @transport.read_all(4).unpack('N').first @index = 0 @rbuf = @transport.read_all(sz) end end class FramedTransportFactory < BaseTransportFactory def get_transport(transport) return FramedTransport.new(transport) end def to_s "framed" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/http_client_transport.rb000066400000000000000000000040151420101504100253130ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'net/http' require 'net/https' require 'openssl' require 'uri' require 'stringio' module Thrift class HTTPClientTransport < BaseTransport def initialize(url, opts = {}) @url = URI url @headers = {'Content-Type' => 'application/x-thrift'} @outbuf = Bytes.empty_byte_buffer @ssl_verify_mode = opts.fetch(:ssl_verify_mode, OpenSSL::SSL::VERIFY_PEER) end def open?; true end def read(sz); @inbuf.read sz end def write(buf); @outbuf << Bytes.force_binary_encoding(buf) end def add_headers(headers) @headers = @headers.merge(headers) end def flush http = Net::HTTP.new @url.host, @url.port http.use_ssl = @url.scheme == 'https' http.verify_mode = @ssl_verify_mode if @url.scheme == 'https' resp = http.post(@url.request_uri, @outbuf, @headers) raise TransportException.new(TransportException::UNKNOWN, "#{self.class.name} Could not connect to #{@url}, HTTP status code #{resp.code.to_i}") unless (200..299).include?(resp.code.to_i) data = resp.body data = Bytes.force_binary_encoding(data) @inbuf = StringIO.new data ensure @outbuf = Bytes.empty_byte_buffer end def to_s "@{self.url}" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/io_stream_transport.rb000066400000000000000000000030441420101504100247610ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Very very simple implementation of wrapping two objects, one with a #read # method and one with a #write method, into a transport for thrift. # # Assumes both objects are open, remain open, don't require flushing, etc. # module Thrift class IOStreamTransport < BaseTransport def initialize(input, output) @input = input @output = output end def open?; not @input.closed? or not @output.closed? end def read(sz); @input.read(sz) end def write(buf); @output.write(Bytes.force_binary_encoding(buf)) end def close; @input.close; @output.close end def to_io; @input end # we're assuming this is used in a IO.select for reading def to_s "iostream(input=#{@input.to_s},output=#{@output.to_s})" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/memory_buffer_transport.rb000066400000000000000000000062721420101504100256460ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class MemoryBufferTransport < BaseTransport GARBAGE_BUFFER_SIZE = 4*(2**10) # 4kB # If you pass a string to this, you should #dup that string # unless you want it to be modified by #read and #write #-- # this behavior is no longer required. If you wish to change it # go ahead, just make sure the specs pass def initialize(buffer = nil) @buf = buffer ? Bytes.force_binary_encoding(buffer) : Bytes.empty_byte_buffer @index = 0 end def open? return true end def open end def close end def peek @index < @buf.size end # this method does not use the passed object directly but copies it def reset_buffer(new_buf = '') @buf.replace Bytes.force_binary_encoding(new_buf) @index = 0 end def available @buf.length - @index end def read(len) data = @buf.slice(@index, len) @index += len @index = @buf.size if @index > @buf.size if @index >= GARBAGE_BUFFER_SIZE @buf = @buf.slice(@index..-1) @index = 0 end if data.size < len raise EOFError, "Not enough bytes remain in buffer" end data end def read_byte raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size val = Bytes.get_string_byte(@buf, @index) @index += 1 if @index >= GARBAGE_BUFFER_SIZE @buf = @buf.slice(@index..-1) @index = 0 end val end def read_into_buffer(buffer, size) i = 0 while i < size raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size # The read buffer has some data now, so copy bytes over to the output buffer. byte = Bytes.get_string_byte(@buf, @index) Bytes.set_string_byte(buffer, i, byte) @index += 1 i += 1 end if @index >= GARBAGE_BUFFER_SIZE @buf = @buf.slice(@index..-1) @index = 0 end i end def write(wbuf) @buf << Bytes.force_binary_encoding(wbuf) end def flush end def inspect_buffer out = [] for idx in 0...(@buf.size) # if idx != 0 # out << " " # end if idx == @index out << ">" end out << @buf[idx].ord.to_s(16) end out.join(" ") end def to_s "memory" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/server_socket.rb000066400000000000000000000031561420101504100235450ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'socket' module Thrift class ServerSocket < BaseServerTransport # call-seq: initialize(host = nil, port) def initialize(host_or_port, port = nil) if port @host = host_or_port @port = port else @host = nil @port = host_or_port end @handle = nil end attr_reader :handle def listen @handle = TCPServer.new(@host, @port) end def accept unless @handle.nil? sock = @handle.accept trans = Socket.new trans.handle = sock trans end end def close @handle.close unless @handle.nil? or @handle.closed? @handle = nil end def closed? @handle.nil? or @handle.closed? end alias to_io handle def to_s "socket(#{@host}:#{@port})" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/socket.rb000066400000000000000000000107311420101504100221540ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'socket' module Thrift class Socket < BaseTransport def initialize(host='localhost', port=9090, timeout=nil) @host = host @port = port @timeout = timeout @desc = "#{host}:#{port}" @handle = nil end attr_accessor :handle, :timeout def open for addrinfo in ::Socket::getaddrinfo(@host, @port, nil, ::Socket::SOCK_STREAM) do begin socket = ::Socket.new(addrinfo[4], ::Socket::SOCK_STREAM, 0) socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1) sockaddr = ::Socket.sockaddr_in(addrinfo[1], addrinfo[3]) begin socket.connect_nonblock(sockaddr) rescue Errno::EINPROGRESS unless IO.select(nil, [ socket ], nil, @timeout) next end begin socket.connect_nonblock(sockaddr) rescue Errno::EISCONN end end return @handle = socket rescue StandardError => e next end end raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}") end def open? !@handle.nil? and !@handle.closed? end def write(str) raise IOError, "closed stream" unless open? str = Bytes.force_binary_encoding(str) begin if @timeout.nil? or @timeout == 0 @handle.write(str) else len = 0 start = Time.now while Time.now - start < @timeout rd, wr, = IO.select(nil, [@handle], nil, @timeout) if wr and not wr.empty? len += @handle.write_nonblock(str[len..-1]) break if len >= str.length end end if len < str.length raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out writing #{str.length} bytes to #{@desc}") else len end end rescue TransportException => e # pass this on raise e rescue StandardError => e @handle.close @handle = nil raise TransportException.new(TransportException::NOT_OPEN, e.message) end end def read(sz) raise IOError, "closed stream" unless open? begin if @timeout.nil? or @timeout == 0 data = @handle.readpartial(sz) else # it's possible to interrupt select for something other than the timeout # so we need to ensure we've waited long enough, but not too long start = Time.now timespent = 0 rd = loop do rd, = IO.select([@handle], nil, nil, @timeout - timespent) timespent = Time.now - start break rd if (rd and not rd.empty?) or timespent >= @timeout end if rd.nil? or rd.empty? raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out reading #{sz} bytes from #{@desc}") else data = @handle.readpartial(sz) end end rescue TransportException => e # don't let this get caught by the StandardError handler raise e rescue StandardError => e @handle.close unless @handle.closed? @handle = nil raise TransportException.new(TransportException::NOT_OPEN, e.message) end if (data.nil? or data.length == 0) raise TransportException.new(TransportException::UNKNOWN, "Socket: Could not read #{sz} bytes from #{@desc}") end data end def close @handle.close unless @handle.nil? or @handle.closed? @handle = nil end alias to_io handle def to_s "socket(#{@host}:#{@port})" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/ssl_server_socket.rb000066400000000000000000000023351420101504100244240ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'socket' module Thrift class SSLServerSocket < ServerSocket def initialize(host_or_port, port = nil, ssl_context = nil) super(host_or_port, port) @ssl_context = ssl_context end attr_accessor :ssl_context def listen socket = TCPServer.new(@host, @port) @handle = OpenSSL::SSL::SSLServer.new(socket, @ssl_context) end def to_s "ssl(#{super.to_s})" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/ssl_socket.rb000066400000000000000000000031601420101504100230330ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. module Thrift class SSLSocket < Socket def initialize(host='localhost', port=9090, timeout=nil, ssl_context=nil) super(host, port, timeout) @ssl_context = ssl_context end attr_accessor :ssl_context def open socket = super @handle = OpenSSL::SSL::SSLSocket.new(socket, @ssl_context) begin @handle.connect_nonblock @handle.post_connection_check(@host) @handle rescue IO::WaitReadable IO.select([ @handle ], nil, nil, @timeout) retry rescue IO::WaitWritable IO.select(nil, [ @handle ], nil, @timeout) retry rescue StandardError => e raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}") end end def to_s "ssl(#{super.to_s})" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/unix_server_socket.rb000066400000000000000000000030721420101504100246050ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'socket' module Thrift class UNIXServerSocket < BaseServerTransport def initialize(path) @path = path @handle = nil end attr_accessor :handle def listen @handle = ::UNIXServer.new(@path) end def accept unless @handle.nil? sock = @handle.accept trans = UNIXSocket.new(nil) trans.handle = sock trans end end def close if @handle @handle.close unless @handle.closed? @handle = nil # UNIXServer doesn't delete the socket file, so we have to do it ourselves File.delete(@path) end end def closed? @handle.nil? or @handle.closed? end alias to_io handle def to_s "domain(#{@path})" end end end thrift-0.16.0/lib/rb/lib/thrift/transport/unix_socket.rb000066400000000000000000000024331420101504100232170ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'socket' module Thrift class UNIXSocket < Socket def initialize(path, timeout=nil) @path = path @timeout = timeout @desc = @path # for read()'s error @handle = nil end def open begin @handle = ::UNIXSocket.new(@path) rescue StandardError raise TransportException.new(TransportException::NOT_OPEN, "Could not open UNIX socket at #{@path}") end end def to_s "domain(#{@path})" end end end thrift-0.16.0/lib/rb/lib/thrift/types.rb000066400000000000000000000053771420101504100200060ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'set' module Thrift module Types STOP = 0 VOID = 1 BOOL = 2 BYTE = 3 DOUBLE = 4 I16 = 6 I32 = 8 I64 = 10 STRING = 11 STRUCT = 12 MAP = 13 SET = 14 LIST = 15 end class << self attr_accessor :type_checking end class TypeError < Exception end def self.check_type(value, field, name, skip_nil=true) return if value.nil? and skip_nil klasses = case field[:type] when Types::VOID NilClass when Types::BOOL [TrueClass, FalseClass] when Types::BYTE, Types::I16, Types::I32, Types::I64 Integer when Types::DOUBLE Float when Types::STRING String when Types::STRUCT [Struct, Union] when Types::MAP Hash when Types::SET Set when Types::LIST Array end valid = klasses && [*klasses].any? { |klass| klass === value } raise TypeError, "Expected #{type_name(field[:type])}, received #{value.class} for field #{name}" unless valid # check elements now case field[:type] when Types::MAP value.each_pair do |k,v| check_type(k, field[:key], "#{name}.key", false) check_type(v, field[:value], "#{name}.value", false) end when Types::SET, Types::LIST value.each do |el| check_type(el, field[:element], "#{name}.element", false) end when Types::STRUCT raise TypeError, "Expected #{field[:class]}, received #{value.class} for field #{name}" unless field[:class] == value.class end end def self.type_name(type) Types.constants.each do |const| return "Types::#{const}" if Types.const_get(const) == type end nil end module MessageTypes CALL = 1 REPLY = 2 EXCEPTION = 3 ONEWAY = 4 end end Thrift.type_checking = false if Thrift.type_checking.nil? thrift-0.16.0/lib/rb/lib/thrift/union.rb000066400000000000000000000120251420101504100177560ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module Thrift class Union def initialize(name=nil, value=nil) if name if name.is_a? Hash if name.size > 1 raise "#{self.class} cannot be instantiated with more than one field!" end name, value = name.keys.first, name.values.first end if Thrift.type_checking raise Exception, "#{self.class} does not contain a field named #{name}!" unless name_to_id(name.to_s) end if value.nil? raise Exception, "Union #{self.class} cannot be instantiated with setfield and nil value!" end Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking elsif !value.nil? raise Exception, "Value provided, but no name!" end @setfield = name @value = value end def inspect if get_set_field "<#{self.class} #{@setfield}: #{inspect_field(@value, struct_fields[name_to_id(@setfield.to_s)])}>" else "<#{self.class} >" end end def read(iprot) iprot.read_struct_begin fname, ftype, fid = iprot.read_field_begin handle_message(iprot, fid, ftype) iprot.read_field_end fname, ftype, fid = iprot.read_field_begin raise "Too many fields for union" unless (ftype == Types::STOP) iprot.read_struct_end validate end def write(oprot) validate oprot.write_struct_begin(self.class.name) fid = self.name_to_id(@setfield.to_s) field_info = struct_fields[fid] type = field_info[:type] if is_container? type oprot.write_field_begin(@setfield, type, fid) write_container(oprot, @value, field_info) oprot.write_field_end else oprot.write_field(@setfield, type, fid, @value) end oprot.write_field_stop oprot.write_struct_end end def ==(other) other.equal?(self) || other.instance_of?(self.class) && @setfield == other.get_set_field && @value == other.get_value end alias_method :eql?, :== def hash [self.class.name, @setfield, @value].hash end def self.field_accessor(klass, field_info) klass.send :define_method, field_info[:name] do if field_info[:name].to_sym == @setfield @value else raise RuntimeError, "#{field_info[:name]} is not union's set field." end end klass.send :define_method, "#{field_info[:name]}=" do |value| Thrift.check_type(value, field_info, field_info[:name]) if Thrift.type_checking @setfield = field_info[:name].to_sym @value = value end end def self.qmark_isset_method(klass, field_info) klass.send :define_method, "#{field_info[:name]}?" do get_set_field == field_info[:name].to_sym && !get_value.nil? end end def self.generate_accessors(klass) klass::FIELDS.values.each do |field_info| field_accessor(klass, field_info) qmark_isset_method(klass, field_info) end end # get the symbol that indicates what the currently set field type is. def get_set_field @setfield end # get the current value of this union, regardless of what the set field is. # generally, you should only use this method when you don't know in advance # what field to expect. def get_value @value end def <=>(other) if self.class == other.class if get_set_field == other.get_set_field if get_set_field.nil? 0 else get_value <=> other.get_value end else if get_set_field && other.get_set_field.nil? -1 elsif get_set_field.nil? && other.get_set_field 1 elsif get_set_field.nil? && other.get_set_field.nil? 0 else name_to_id(get_set_field.to_s) <=> name_to_id(other.get_set_field.to_s) end end else self.class <=> other.class end end protected def handle_message(iprot, fid, ftype) field = struct_fields[fid] if field and field[:type] == ftype @value = read_field(iprot, field) name = field[:name].to_sym @setfield = name else iprot.skip(ftype) end end end end thrift-0.16.0/lib/rb/script/000077500000000000000000000000001420101504100155375ustar00rootroot00000000000000thrift-0.16.0/lib/rb/script/proto_benchmark.rb000066400000000000000000000071251420101504100212460ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require File.dirname(__FILE__) + "/../spec/spec_helper.rb" require "benchmark" # require "ruby-prof" obj = Fixtures::COMPACT_PROTOCOL_TEST_STRUCT HOW_MANY = 1_000 binser = Thrift::Serializer.new bin_data = binser.serialize(obj) bindeser = Thrift::Deserializer.new accel_bin_ser = Thrift::Serializer.new(Thrift::BinaryProtocolAcceleratedFactory.new) accel_bin_deser = Thrift::Deserializer.new(Thrift::BinaryProtocolAcceleratedFactory.new) compact_ser = Thrift::Serializer.new(Thrift::CompactProtocolFactory.new) compact_data = compact_ser.serialize(obj) compact_deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new) Benchmark.bm(60) do |reporter| reporter.report("binary protocol, write") do HOW_MANY.times do binser.serialize(obj) end end reporter.report("accelerated binary protocol, write") do HOW_MANY.times do accel_bin_ser.serialize(obj) end end reporter.report("compact protocol, write") do # RubyProf.start HOW_MANY.times do compact_ser.serialize(obj) end # result = RubyProf.stop # printer = RubyProf::GraphHtmlPrinter.new(result) # file = File.open("profile.html", "w+") # printer.print(file, 0) # file.close end reporter.report("binary protocol, read") do HOW_MANY.times do bindeser.deserialize(obj, bin_data) end end reporter.report("accelerated binary protocol, read") do HOW_MANY.times do accel_bin_deser.deserialize(obj, bin_data) end end reporter.report("compact protocol, read") do HOW_MANY.times do compact_deser.deserialize(obj, compact_data) end end # f = File.new("/tmp/testfile", "w") # proto = Thrift::BinaryProtocolAccelerated.new(Thrift::IOStreamTransport.new(Thrift::MemoryBufferTransport.new, f)) # reporter.report("accelerated binary protocol, write (to disk)") do # HOW_MANY.times do # obj.write(proto) # end # f.flush # end # f.close # # f = File.new("/tmp/testfile", "r") # proto = Thrift::BinaryProtocolAccelerated.new(Thrift::IOStreamTransport.new(f, Thrift::MemoryBufferTransport.new)) # reporter.report("accelerated binary protocol, read (from disk)") do # HOW_MANY.times do # obj.read(proto) # end # end # f.close # # f = File.new("/tmp/testfile", "w") # reporter.report("compact protocol, write (to disk)") do # proto = Thrift::CompactProtocol.new(Thrift::IOStreamTransport.new(Thrift::MemoryBufferTransport.new, f)) # HOW_MANY.times do # obj.write(proto) # end # f.flush # end # f.close # # f = File.new("/tmp/testfile", "r") # reporter.report("compact protocol, read (from disk)") do # proto = Thrift::CompactProtocol.new(Thrift::IOStreamTransport.new(f, Thrift::MemoryBufferTransport.new)) # HOW_MANY.times do # obj.read(proto) # end # end # f.close end thrift-0.16.0/lib/rb/script/read_struct.rb000066400000000000000000000025631420101504100204110ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require "spec/spec_helper" path, factory_class = ARGV factory = eval(factory_class).new deser = Thrift::Deserializer.new(factory) cpts = CompactProtoTestStruct.new CompactProtoTestStruct.constants.each do |const| cpts.instance_variable_set("@#{const}", nil) end data = File.read(path) deser.deserialize(cpts, data) if cpts == Fixtures::COMPACT_PROTOCOL_TEST_STRUCT puts "Object verified successfully!" else puts "Object failed verification! Expected #{Fixtures::COMPACT_PROTOCOL_TEST_STRUCT.inspect} but got #{cpts.inspect}" puts cpts.differences(Fixtures::COMPACT_PROTOCOL_TEST_STRUCT) end thrift-0.16.0/lib/rb/script/write_struct.rb000066400000000000000000000017721420101504100206310ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require "spec/spec_helper" path, factory_class = ARGV factory = eval(factory_class).new ser = Thrift::Serializer.new(factory) File.open(path, "w") do |file| file.write(ser.serialize(Fixtures::COMPACT_PROTOCOL_TEST_STRUCT)) endthrift-0.16.0/lib/rb/spec/000077500000000000000000000000001420101504100151655ustar00rootroot00000000000000thrift-0.16.0/lib/rb/spec/BaseService.thrift000066400000000000000000000016231420101504100206040ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # namespace rb Base struct Hello { 1: string greeting = "hello world" } service BaseService { Hello greeting(1:bool english) } thrift-0.16.0/lib/rb/spec/ExtendedService.thrift000066400000000000000000000016171420101504100214750ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # namespace rb Extended include "BaseService.thrift" service ExtendedService extends BaseService.BaseService { void ping() } thrift-0.16.0/lib/rb/spec/Referenced.thrift000066400000000000000000000031621420101504100204530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # namespace rb OtherNamespace enum SomeEnum { ONE TWO } thrift-0.16.0/lib/rb/spec/ThriftNamespacedSpec.thrift000066400000000000000000000035411420101504100224460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # namespace rb NamespacedSpecNamespace include "Referenced.thrift" struct Hello { 1: string greeting = "hello world" } service NamespacedNonblockingService { Hello greeting(1:bool english) bool block() oneway void unblock(1:i32 n) oneway void shutdown() void sleep(1:double seconds) } thrift-0.16.0/lib/rb/spec/ThriftSpec.thrift000066400000000000000000000077141420101504100204730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # namespace rb SpecNamespace struct Hello { 1: string greeting = "hello world" } enum SomeEnum { ONE TWO } struct StructWithSomeEnum { 1: SomeEnum some_enum; } union TestUnion { /** * A doc string */ 1: string string_field; 2: i32 i32_field; 3: i32 other_i32_field; 4: SomeEnum enum_field; 5: binary binary_field; } struct Foo { 1: i32 simple = 53, 2: string words = "words", 3: Hello hello = {'greeting' : "hello, world!"}, 4: list ints = [1, 2, 2, 3], 5: map> complex, 6: set shorts = [5, 17, 239], 7: optional string opt_string 8: bool my_bool } struct Foo2 { 1: binary my_binary } struct BoolStruct { 1: bool yesno = 1 } struct SimpleList { 1: list bools, 2: list bytes, 3: list i16s, 4: list i32s, 5: list i64s, 6: list doubles, 7: list strings, 8: list> maps, 9: list> lists, 10: list> sets, 11: list hellos } exception Xception { 1: string message, 2: i32 code = 1 } service NonblockingService { Hello greeting(1:bool english) bool block() oneway void unblock(1:i32 n) oneway void shutdown() void sleep(1:double seconds) } union My_union { 1: bool im_true, 2: byte a_bite, 3: i16 integer16, 4: i32 integer32, 5: i64 integer64, 6: double double_precision, 7: string some_characters, 8: i32 other_i32 9: SomeEnum some_enum; 10: map> my_map; } struct Struct_with_union { 1: My_union fun_union 2: i32 integer32 3: string some_characters } struct StructWithEnumMap { 1: map> my_map; } # Nested lists struct NestedListInList { 1: list> value } struct NestedListInSet { 1: set> value } struct NestedListInMapKey { 1: map, byte> value } struct NestedListInMapValue { 1: map> value } # Nested sets struct NestedSetInList { 1: list> value } struct NestedSetInSet { 1: set> value } struct NestedSetInMapKey { 1: map, byte> value } struct NestedSetInMapValue { 1: map> value } # Nested maps struct NestedMapInList { 1: list> value } struct NestedMapInSet { 1: set> value } struct NestedMapInMapKey { 2: map, byte> value } struct NestedMapInMapValue { 2: map> value } thrift-0.16.0/lib/rb/spec/base_protocol_spec.rb000066400000000000000000000243321420101504100213630ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'BaseProtocol' do before(:each) do @trans = double("MockTransport") @prot = Thrift::BaseProtocol.new(@trans) end describe Thrift::BaseProtocol do # most of the methods are stubs, so we can ignore them it "should provide a reasonable to_s" do expect(@trans).to receive(:to_s).once.and_return("trans") expect(@prot.to_s).to eq("trans") end it "should make trans accessible" do expect(@prot.trans).to eql(@trans) end it 'should write out a field nicely (deprecated write_field signature)' do expect(@prot).to receive(:write_field_begin).with('field', 'type', 'fid').ordered expect(@prot).to receive(:write_type).with({:name => 'field', :type => 'type'}, 'value').ordered expect(@prot).to receive(:write_field_end).ordered @prot.write_field('field', 'type', 'fid', 'value') end it 'should write out a field nicely' do expect(@prot).to receive(:write_field_begin).with('field', 'type', 'fid').ordered expect(@prot).to receive(:write_type).with({:name => 'field', :type => 'type', :binary => false}, 'value').ordered expect(@prot).to receive(:write_field_end).ordered @prot.write_field({:name => 'field', :type => 'type', :binary => false}, 'fid', 'value') end it 'should write out the different types (deprecated write_type signature)' do expect(@prot).to receive(:write_bool).with('bool').ordered expect(@prot).to receive(:write_byte).with('byte').ordered expect(@prot).to receive(:write_double).with('double').ordered expect(@prot).to receive(:write_i16).with('i16').ordered expect(@prot).to receive(:write_i32).with('i32').ordered expect(@prot).to receive(:write_i64).with('i64').ordered expect(@prot).to receive(:write_string).with('string').ordered struct = double('Struct') expect(struct).to receive(:write).with(@prot).ordered @prot.write_type(Thrift::Types::BOOL, 'bool') @prot.write_type(Thrift::Types::BYTE, 'byte') @prot.write_type(Thrift::Types::DOUBLE, 'double') @prot.write_type(Thrift::Types::I16, 'i16') @prot.write_type(Thrift::Types::I32, 'i32') @prot.write_type(Thrift::Types::I64, 'i64') @prot.write_type(Thrift::Types::STRING, 'string') @prot.write_type(Thrift::Types::STRUCT, struct) # all other types are not implemented [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST].each do |type| expect { @prot.write_type(type, type.to_s) }.to raise_error(NotImplementedError) end end it 'should write out the different types' do expect(@prot).to receive(:write_bool).with('bool').ordered expect(@prot).to receive(:write_byte).with('byte').ordered expect(@prot).to receive(:write_double).with('double').ordered expect(@prot).to receive(:write_i16).with('i16').ordered expect(@prot).to receive(:write_i32).with('i32').ordered expect(@prot).to receive(:write_i64).with('i64').ordered expect(@prot).to receive(:write_string).with('string').ordered expect(@prot).to receive(:write_binary).with('binary').ordered struct = double('Struct') expect(struct).to receive(:write).with(@prot).ordered @prot.write_type({:type => Thrift::Types::BOOL}, 'bool') @prot.write_type({:type => Thrift::Types::BYTE}, 'byte') @prot.write_type({:type => Thrift::Types::DOUBLE}, 'double') @prot.write_type({:type => Thrift::Types::I16}, 'i16') @prot.write_type({:type => Thrift::Types::I32}, 'i32') @prot.write_type({:type => Thrift::Types::I64}, 'i64') @prot.write_type({:type => Thrift::Types::STRING}, 'string') @prot.write_type({:type => Thrift::Types::STRING, :binary => true}, 'binary') @prot.write_type({:type => Thrift::Types::STRUCT}, struct) # all other types are not implemented [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST].each do |type| expect { @prot.write_type({:type => type}, type.to_s) }.to raise_error(NotImplementedError) end end it 'should read the different types (deprecated read_type signature)' do expect(@prot).to receive(:read_bool).ordered expect(@prot).to receive(:read_byte).ordered expect(@prot).to receive(:read_i16).ordered expect(@prot).to receive(:read_i32).ordered expect(@prot).to receive(:read_i64).ordered expect(@prot).to receive(:read_double).ordered expect(@prot).to receive(:read_string).ordered @prot.read_type(Thrift::Types::BOOL) @prot.read_type(Thrift::Types::BYTE) @prot.read_type(Thrift::Types::I16) @prot.read_type(Thrift::Types::I32) @prot.read_type(Thrift::Types::I64) @prot.read_type(Thrift::Types::DOUBLE) @prot.read_type(Thrift::Types::STRING) # all other types are not implemented [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST, Thrift::Types::STRUCT].each do |type| expect { @prot.read_type(type) }.to raise_error(NotImplementedError) end end it 'should read the different types' do expect(@prot).to receive(:read_bool).ordered expect(@prot).to receive(:read_byte).ordered expect(@prot).to receive(:read_i16).ordered expect(@prot).to receive(:read_i32).ordered expect(@prot).to receive(:read_i64).ordered expect(@prot).to receive(:read_double).ordered expect(@prot).to receive(:read_string).ordered expect(@prot).to receive(:read_binary).ordered @prot.read_type({:type => Thrift::Types::BOOL}) @prot.read_type({:type => Thrift::Types::BYTE}) @prot.read_type({:type => Thrift::Types::I16}) @prot.read_type({:type => Thrift::Types::I32}) @prot.read_type({:type => Thrift::Types::I64}) @prot.read_type({:type => Thrift::Types::DOUBLE}) @prot.read_type({:type => Thrift::Types::STRING}) @prot.read_type({:type => Thrift::Types::STRING, :binary => true}) # all other types are not implemented [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST, Thrift::Types::STRUCT].each do |type| expect { @prot.read_type({:type => type}) }.to raise_error(NotImplementedError) end end it "should skip the basic types" do expect(@prot).to receive(:read_bool).ordered expect(@prot).to receive(:read_byte).ordered expect(@prot).to receive(:read_i16).ordered expect(@prot).to receive(:read_i32).ordered expect(@prot).to receive(:read_i64).ordered expect(@prot).to receive(:read_double).ordered expect(@prot).to receive(:read_string).ordered @prot.skip(Thrift::Types::BOOL) @prot.skip(Thrift::Types::BYTE) @prot.skip(Thrift::Types::I16) @prot.skip(Thrift::Types::I32) @prot.skip(Thrift::Types::I64) @prot.skip(Thrift::Types::DOUBLE) @prot.skip(Thrift::Types::STRING) end it "should skip structs" do real_skip = @prot.method(:skip) expect(@prot).to receive(:read_struct_begin).ordered expect(@prot).to receive(:read_field_begin).exactly(4).times.and_return( ['field 1', Thrift::Types::STRING, 1], ['field 2', Thrift::Types::I32, 2], ['field 3', Thrift::Types::MAP, 3], [nil, Thrift::Types::STOP, 0] ) expect(@prot).to receive(:read_field_end).exactly(3).times expect(@prot).to receive(:read_string).exactly(3).times expect(@prot).to receive(:read_i32).ordered expect(@prot).to receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRING, 1]) # @prot.should_receive(:read_string).exactly(2).times expect(@prot).to receive(:read_map_end).ordered expect(@prot).to receive(:read_struct_end).ordered real_skip.call(Thrift::Types::STRUCT) end it "should skip maps" do real_skip = @prot.method(:skip) expect(@prot).to receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRUCT, 1]) expect(@prot).to receive(:read_string).ordered expect(@prot).to receive(:read_struct_begin).ordered.and_return(["some_struct"]) expect(@prot).to receive(:read_field_begin).ordered.and_return([nil, Thrift::Types::STOP, nil]); expect(@prot).to receive(:read_struct_end).ordered expect(@prot).to receive(:read_map_end).ordered real_skip.call(Thrift::Types::MAP) end it "should skip sets" do real_skip = @prot.method(:skip) expect(@prot).to receive(:read_set_begin).ordered.and_return([Thrift::Types::I64, 9]) expect(@prot).to receive(:read_i64).ordered.exactly(9).times expect(@prot).to receive(:read_set_end) real_skip.call(Thrift::Types::SET) end it "should skip lists" do real_skip = @prot.method(:skip) expect(@prot).to receive(:read_list_begin).ordered.and_return([Thrift::Types::DOUBLE, 11]) expect(@prot).to receive(:read_double).ordered.exactly(11).times expect(@prot).to receive(:read_list_end) real_skip.call(Thrift::Types::LIST) end end describe Thrift::BaseProtocolFactory do it "should raise NotImplementedError" do # returning nil since Protocol is just an abstract class expect {Thrift::BaseProtocolFactory.new.get_protocol(double("MockTransport"))}.to raise_error(NotImplementedError) end it "should provide a reasonable to_s" do expect(Thrift::BaseProtocolFactory.new.to_s).to eq("base") end end end thrift-0.16.0/lib/rb/spec/base_transport_spec.rb000066400000000000000000000336661420101504100215700ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'BaseTransport' do describe Thrift::TransportException do it "should make type accessible" do exc = Thrift::TransportException.new(Thrift::TransportException::ALREADY_OPEN, "msg") expect(exc.type).to eq(Thrift::TransportException::ALREADY_OPEN) expect(exc.message).to eq("msg") end end describe Thrift::BaseTransport do it "should read the specified size" do transport = Thrift::BaseTransport.new expect(transport).to receive(:read).with(40).ordered.and_return("10 letters") expect(transport).to receive(:read).with(30).ordered.and_return("fifteen letters") expect(transport).to receive(:read).with(15).ordered.and_return("more characters") expect(transport.read_all(40)).to eq("10 lettersfifteen lettersmore characters") end it "should stub out the rest of the methods" do # can't test for stubbiness, so just make sure they're defined [:open?, :open, :close, :read, :write, :flush].each do |sym| expect(Thrift::BaseTransport.method_defined?(sym)).to be_truthy end end it "should alias << to write" do expect(Thrift::BaseTransport.instance_method(:<<)).to eq(Thrift::BaseTransport.instance_method(:write)) end it "should provide a reasonable to_s" do expect(Thrift::BaseTransport.new.to_s).to eq("base") end end describe Thrift::BaseServerTransport do it "should stub out its methods" do [:listen, :accept, :close].each do |sym| expect(Thrift::BaseServerTransport.method_defined?(sym)).to be_truthy end end end describe Thrift::BaseTransportFactory do it "should return the transport it's given" do transport = double("Transport") expect(Thrift::BaseTransportFactory.new.get_transport(transport)).to eql(transport) end it "should provide a reasonable to_s" do expect(Thrift::BaseTransportFactory.new.to_s).to eq("base") end end describe Thrift::BufferedTransport do it "should provide a to_s that describes the encapsulation" do trans = double("Transport") expect(trans).to receive(:to_s).and_return("mock") expect(Thrift::BufferedTransport.new(trans).to_s).to eq("buffered(mock)") end it "should pass through everything but write/flush/read" do trans = double("Transport") expect(trans).to receive(:open?).ordered.and_return("+ open?") expect(trans).to receive(:open).ordered.and_return("+ open") expect(trans).to receive(:flush).ordered # from the close expect(trans).to receive(:close).ordered.and_return("+ close") btrans = Thrift::BufferedTransport.new(trans) expect(btrans.open?).to eq("+ open?") expect(btrans.open).to eq("+ open") expect(btrans.close).to eq("+ close") end it "should buffer reads in chunks of #{Thrift::BufferedTransport::DEFAULT_BUFFER}" do trans = double("Transport") expect(trans).to receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet") btrans = Thrift::BufferedTransport.new(trans) expect(btrans.read(6)).to eq("lorum ") expect(btrans.read(6)).to eq("ipsum ") expect(btrans.read(6)).to eq("dolor ") expect(btrans.read(6)).to eq("emet") end it "should buffer writes and send them on flush" do trans = double("Transport") btrans = Thrift::BufferedTransport.new(trans) btrans.write("one/") btrans.write("two/") btrans.write("three/") expect(trans).to receive(:write).with("one/two/three/").ordered expect(trans).to receive(:flush).ordered btrans.flush end it "should only send buffered data once" do trans = double("Transport") btrans = Thrift::BufferedTransport.new(trans) btrans.write("one/") btrans.write("two/") btrans.write("three/") expect(trans).to receive(:write).with("one/two/three/") allow(trans).to receive(:flush) btrans.flush # Nothing to flush with no data btrans.flush end it "should flush on close" do trans = double("Transport") expect(trans).to receive(:close) btrans = Thrift::BufferedTransport.new(trans) expect(btrans).to receive(:flush) btrans.close end it "should not write to socket if there's no data" do trans = double("Transport") expect(trans).to receive(:flush) btrans = Thrift::BufferedTransport.new(trans) btrans.flush end end describe Thrift::BufferedTransportFactory do it "should wrap the given transport in a BufferedTransport" do trans = double("Transport") btrans = double("BufferedTransport") expect(Thrift::BufferedTransport).to receive(:new).with(trans).and_return(btrans) expect(Thrift::BufferedTransportFactory.new.get_transport(trans)).to eq(btrans) end it "should provide a reasonable to_s" do expect(Thrift::BufferedTransportFactory.new.to_s).to eq("buffered") end end describe Thrift::FramedTransport do before(:each) do @trans = double("Transport") end it "should provide a to_s that describes the encapsulation" do trans = double("Transport") expect(trans).to receive(:to_s).and_return("mock") expect(Thrift::FramedTransport.new(trans).to_s).to eq("framed(mock)") end it "should pass through open?/open/close" do ftrans = Thrift::FramedTransport.new(@trans) expect(@trans).to receive(:open?).ordered.and_return("+ open?") expect(@trans).to receive(:open).ordered.and_return("+ open") expect(@trans).to receive(:close).ordered.and_return("+ close") expect(ftrans.open?).to eq("+ open?") expect(ftrans.open).to eq("+ open") expect(ftrans.close).to eq("+ close") end it "should pass through read when read is turned off" do ftrans = Thrift::FramedTransport.new(@trans, false, true) expect(@trans).to receive(:read).with(17).ordered.and_return("+ read") expect(ftrans.read(17)).to eq("+ read") end it "should pass through write/flush when write is turned off" do ftrans = Thrift::FramedTransport.new(@trans, true, false) expect(@trans).to receive(:write).with("foo").ordered.and_return("+ write") expect(@trans).to receive(:flush).ordered.and_return("+ flush") expect(ftrans.write("foo")).to eq("+ write") expect(ftrans.flush).to eq("+ flush") end it "should return a full frame if asked for >= the frame's length" do frame = "this is a frame" expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017") expect(@trans).to receive(:read_all).with(frame.length).and_return(frame) expect(Thrift::FramedTransport.new(@trans).read(frame.length + 10)).to eq(frame) end it "should return slices of the frame when asked for < the frame's length" do frame = "this is a frame" expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017") expect(@trans).to receive(:read_all).with(frame.length).and_return(frame) ftrans = Thrift::FramedTransport.new(@trans) expect(ftrans.read(4)).to eq("this") expect(ftrans.read(4)).to eq(" is ") expect(ftrans.read(16)).to eq("a frame") end it "should return nothing if asked for <= 0" do expect(Thrift::FramedTransport.new(@trans).read(-2)).to eq("") end it "should pull a new frame when the first is exhausted" do frame = "this is a frame" frame2 = "yet another frame" expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021") expect(@trans).to receive(:read_all).with(frame.length).and_return(frame) expect(@trans).to receive(:read_all).with(frame2.length).and_return(frame2) ftrans = Thrift::FramedTransport.new(@trans) expect(ftrans.read(4)).to eq("this") expect(ftrans.read(8)).to eq(" is a fr") expect(ftrans.read(6)).to eq("ame") expect(ftrans.read(4)).to eq("yet ") expect(ftrans.read(16)).to eq("another frame") end it "should buffer writes" do ftrans = Thrift::FramedTransport.new(@trans) expect(@trans).not_to receive(:write) ftrans.write("foo") ftrans.write("bar") ftrans.write("this is a frame") end it "should write slices of the buffer" do ftrans = Thrift::FramedTransport.new(@trans) ftrans.write("foobar", 3) ftrans.write("barfoo", 1) allow(@trans).to receive(:flush) expect(@trans).to receive(:write).with("\000\000\000\004foob") ftrans.flush end it "should flush frames with a 4-byte header" do ftrans = Thrift::FramedTransport.new(@trans) expect(@trans).to receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered expect(@trans).to receive(:flush).ordered ftrans.write("one/") ftrans.write("two/") ftrans.write("three/") ftrans.write("this is a frame") ftrans.flush end it "should not flush the same buffered data twice" do ftrans = Thrift::FramedTransport.new(@trans) expect(@trans).to receive(:write).with("\000\000\000\007foo/bar") allow(@trans).to receive(:flush) ftrans.write("foo") ftrans.write("/bar") ftrans.flush expect(@trans).to receive(:write).with("\000\000\000\000") ftrans.flush end end describe Thrift::FramedTransportFactory do it "should wrap the given transport in a FramedTransport" do trans = double("Transport") expect(Thrift::FramedTransport).to receive(:new).with(trans) Thrift::FramedTransportFactory.new.get_transport(trans) end it "should provide a reasonable to_s" do expect(Thrift::FramedTransportFactory.new.to_s).to eq("framed") end end describe Thrift::MemoryBufferTransport do before(:each) do @buffer = Thrift::MemoryBufferTransport.new end it "should provide a reasonable to_s" do expect(@buffer.to_s).to eq("memory") end it "should accept a buffer on input and use it directly" do s = "this is a test" @buffer = Thrift::MemoryBufferTransport.new(s) expect(@buffer.read(4)).to eq("this") s.slice!(-4..-1) expect(@buffer.read(@buffer.available)).to eq(" is a ") end it "should always remain open" do expect(@buffer).to be_open @buffer.close expect(@buffer).to be_open end it "should respond to peek and available" do @buffer.write "some data" expect(@buffer.peek).to be_truthy expect(@buffer.available).to eq(9) @buffer.read(4) expect(@buffer.peek).to be_truthy expect(@buffer.available).to eq(5) @buffer.read(5) expect(@buffer.peek).to be_falsey expect(@buffer.available).to eq(0) end it "should be able to reset the buffer" do @buffer.write "test data" @buffer.reset_buffer("foobar") expect(@buffer.available).to eq(6) expect(@buffer.read(@buffer.available)).to eq("foobar") @buffer.reset_buffer expect(@buffer.available).to eq(0) end it "should copy the given string when resetting the buffer" do s = "this is a test" @buffer.reset_buffer(s) expect(@buffer.available).to eq(14) @buffer.read(10) expect(@buffer.available).to eq(4) expect(s).to eq("this is a test") end it "should return from read what was given in write" do @buffer.write "test data" expect(@buffer.read(4)).to eq("test") expect(@buffer.read(@buffer.available)).to eq(" data") @buffer.write "foo" @buffer.write " bar" expect(@buffer.read(@buffer.available)).to eq("foo bar") end it "should throw an EOFError when there isn't enough data in the buffer" do @buffer.reset_buffer("") expect{@buffer.read(1)}.to raise_error(EOFError) @buffer.reset_buffer("1234") expect{@buffer.read(5)}.to raise_error(EOFError) end end describe Thrift::IOStreamTransport do before(:each) do @input = double("Input", :closed? => false) @output = double("Output", :closed? => false) @trans = Thrift::IOStreamTransport.new(@input, @output) end it "should provide a reasonable to_s" do expect(@input).to receive(:to_s).and_return("mock_input") expect(@output).to receive(:to_s).and_return("mock_output") expect(@trans.to_s).to eq("iostream(input=mock_input,output=mock_output)") end it "should be open as long as both input or output are open" do expect(@trans).to be_open allow(@input).to receive(:closed?).and_return(true) expect(@trans).to be_open allow(@input).to receive(:closed?).and_return(false) allow(@output).to receive(:closed?).and_return(true) expect(@trans).to be_open allow(@input).to receive(:closed?).and_return(true) expect(@trans).not_to be_open end it "should pass through read/write to input/output" do expect(@input).to receive(:read).with(17).and_return("+ read") expect(@output).to receive(:write).with("foobar").and_return("+ write") expect(@trans.read(17)).to eq("+ read") expect(@trans.write("foobar")).to eq("+ write") end it "should close both input and output when closed" do expect(@input).to receive(:close) expect(@output).to receive(:close) @trans.close end end end thrift-0.16.0/lib/rb/spec/binary_protocol_accelerated_spec.rb000066400000000000000000000033201420101504100242430ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require File.expand_path("#{File.dirname(__FILE__)}/binary_protocol_spec_shared") if defined? Thrift::BinaryProtocolAccelerated describe 'BinaryProtocolAccelerated' do # since BinaryProtocolAccelerated should be directly equivalent to # BinaryProtocol, we don't need any custom specs! it_should_behave_like 'a binary protocol' def protocol_class Thrift::BinaryProtocolAccelerated end describe Thrift::BinaryProtocolAcceleratedFactory do it "should create a BinaryProtocolAccelerated" do expect(Thrift::BinaryProtocolAcceleratedFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::BinaryProtocolAccelerated) end it "should provide a reasonable to_s" do expect(Thrift::BinaryProtocolAcceleratedFactory.new.to_s).to eq("binary-accel") end end end else puts "skipping BinaryProtocolAccelerated spec because it is not defined." end thrift-0.16.0/lib/rb/spec/binary_protocol_spec.rb000066400000000000000000000053151420101504100217350ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require File.expand_path("#{File.dirname(__FILE__)}/binary_protocol_spec_shared") describe 'BinaryProtocol' do it_should_behave_like 'a binary protocol' def protocol_class Thrift::BinaryProtocol end describe Thrift::BinaryProtocol do before(:each) do @trans = Thrift::MemoryBufferTransport.new @prot = protocol_class.new(@trans) end it "should read a message header" do @trans.write([protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::REPLY].pack('N')) @trans.write([42].pack('N')) expect(@prot).to receive(:read_string).and_return('testMessage') expect(@prot.read_message_begin).to eq(['testMessage', Thrift::MessageTypes::REPLY, 42]) end it "should raise an exception if the message header has the wrong version" do expect(@prot).to receive(:read_i32).and_return(-1) expect { @prot.read_message_begin }.to raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e| e.type == Thrift::ProtocolException::BAD_VERSION end end it "should raise an exception if the message header does not exist and strict_read is enabled" do expect(@prot).to receive(:read_i32).and_return(42) expect(@prot).to receive(:strict_read).and_return(true) expect { @prot.read_message_begin }.to raise_error(Thrift::ProtocolException, 'No version identifier, old protocol client?') do |e| e.type == Thrift::ProtocolException::BAD_VERSION end end it "should provide a reasonable to_s" do expect(@prot.to_s).to eq("binary(memory)") end end describe Thrift::BinaryProtocolFactory do it "should create a BinaryProtocol" do expect(Thrift::BinaryProtocolFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::BinaryProtocol) end it "should provide a reasonable to_s" do expect(Thrift::BinaryProtocolFactory.new.to_s).to eq("binary") end end end thrift-0.16.0/lib/rb/spec/binary_protocol_spec_shared.rb000066400000000000000000000360561420101504100232710ustar00rootroot00000000000000# encoding: ascii-8bit # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' shared_examples_for 'a binary protocol' do before(:each) do @trans = Thrift::MemoryBufferTransport.new @prot = protocol_class.new(@trans) end it "should define the proper VERSION_1, VERSION_MASK AND TYPE_MASK" do expect(protocol_class.const_get(:VERSION_MASK)).to eq(0xffff0000) expect(protocol_class.const_get(:VERSION_1)).to eq(0x80010000) expect(protocol_class.const_get(:TYPE_MASK)).to eq(0x000000ff) end it "should make strict_read readable" do expect(@prot.strict_read).to eql(true) end it "should make strict_write readable" do expect(@prot.strict_write).to eql(true) end it "should write the message header" do @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) expect(@trans.read(@trans.available)).to eq([protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N")) end it "should write the message header without version when writes are not strict" do @prot = protocol_class.new(@trans, true, false) # no strict write @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) expect(@trans.read(@trans.available)).to eq("\000\000\000\vtestMessage\001\000\000\000\021") end it "should write the message header with a version when writes are strict" do @prot = protocol_class.new(@trans) # strict write @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) expect(@trans.read(@trans.available)).to eq("\200\001\000\001\000\000\000\vtestMessage\000\000\000\021") end # message footer is a noop it "should write the field header" do @prot.write_field_begin('foo', Thrift::Types::DOUBLE, 3) expect(@trans.read(@trans.available)).to eq([Thrift::Types::DOUBLE, 3].pack("cn")) end # field footer is a noop it "should write the STOP field" do @prot.write_field_stop expect(@trans.read(1)).to eq("\000") end it "should write the map header" do @prot.write_map_begin(Thrift::Types::STRING, Thrift::Types::LIST, 17) expect(@trans.read(@trans.available)).to eq([Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN")); end # map footer is a noop it "should write the list header" do @prot.write_list_begin(Thrift::Types::I16, 42) expect(@trans.read(@trans.available)).to eq([Thrift::Types::I16, 42].pack("cN")) end # list footer is a noop it "should write the set header" do @prot.write_set_begin(Thrift::Types::I16, 42) expect(@trans.read(@trans.available)).to eq([Thrift::Types::I16, 42].pack("cN")) end it "should write a bool" do @prot.write_bool(true) @prot.write_bool(false) expect(@trans.read(@trans.available)).to eq("\001\000") end it "should treat a nil bool as false" do @prot.write_bool(nil) expect(@trans.read(1)).to eq("\000") end it "should write a byte" do # byte is small enough, let's check -128..127 (-128..127).each do |i| @prot.write_byte(i) expect(@trans.read(1)).to eq([i].pack('c')) end end it "should clip numbers out of signed range" do (128..255).each do |i| @prot.write_byte(i) expect(@trans.read(1)).to eq([i].pack('c')) end end it "errors out with a Bignum" do expect { @prot.write_byte(2**65) }.to raise_error(RangeError) end it "should error gracefully when trying to write a nil byte" do expect { @prot.write_byte(nil) }.to raise_error end it "should write an i16" do # try a random scattering of values # include the signed i16 minimum/maximum [-2**15, -1024, 17, 0, -10000, 1723, 2**15-1].each do |i| @prot.write_i16(i) end # and try something out of signed range, it should clip @prot.write_i16(2**15 + 5) expect(@trans.read(@trans.available)).to eq("\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005") # a Bignum should error # lambda { @prot.write_i16(2**65) }.should raise_error(RangeError) end it "should error gracefully when trying to write a nil i16" do expect { @prot.write_i16(nil) }.to raise_error end it "should write an i32" do # try a random scattering of values # include the signed i32 minimum/maximum [-2**31, -123123, -2532, -3, 0, 2351235, 12331, 2**31-1].each do |i| @prot.write_i32(i) end # try something out of signed range, it should clip expect(@trans.read(@trans.available)).to eq("\200\000\000\000" + "\377\376\037\r" + "\377\377\366\034" + "\377\377\377\375" + "\000\000\000\000" + "\000#\340\203" + "\000\0000+" + "\177\377\377\377") [2 ** 31 + 5, 2 ** 65 + 5].each do |i| expect { @prot.write_i32(i) }.to raise_error(RangeError) end end it "should error gracefully when trying to write a nil i32" do expect { @prot.write_i32(nil) }.to raise_error end it "should write an i64" do # try a random scattering of values # try the signed i64 minimum/maximum [-2**63, -12356123612323, -23512351, -234, 0, 1231, 2351236, 12361236213, 2**63-1].each do |i| @prot.write_i64(i) end # try something out of signed range, it should clip expect(@trans.read(@trans.available)).to eq(["\200\000\000\000\000\000\000\000", "\377\377\364\303\035\244+]", "\377\377\377\377\376\231:\341", "\377\377\377\377\377\377\377\026", "\000\000\000\000\000\000\000\000", "\000\000\000\000\000\000\004\317", "\000\000\000\000\000#\340\204", "\000\000\000\002\340\311~\365", "\177\377\377\377\377\377\377\377"].join("")) expect { @prot.write_i64(2 ** 65 + 5) }.to raise_error(RangeError) end it "should error gracefully when trying to write a nil i64" do expect { @prot.write_i64(nil) }.to raise_error end it "should write a double" do # try a random scattering of values, including min/max values = [Float::MIN,-1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX] values.each do |f| @prot.write_double(f) expect(@trans.read(@trans.available)).to eq([f].pack("G")) end end it "should error gracefully when trying to write a nil double" do expect { @prot.write_double(nil) }.to raise_error end if RUBY_VERSION >= '1.9' it 'should write a string' do str = 'abc' @prot.write_string(str) a = @trans.read(@trans.available) expect(a.encoding).to eq(Encoding::BINARY) expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63]) end it 'should write a string with unicode characters' do str = "abc \u20AC \u20AD".encode('UTF-8') @prot.write_string(str) a = @trans.read(@trans.available) expect(a.encoding).to eq(Encoding::BINARY) expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x0B, 0x61, 0x62, 0x63, 0x20, 0xE2, 0x82, 0xAC, 0x20, 0xE2, 0x82, 0xAD]) end it 'should write should write a string with unicode characters and transcoding' do str = "abc \u20AC".encode('ISO-8859-15') @prot.write_string(str) a = @trans.read(@trans.available) expect(a.encoding).to eq(Encoding::BINARY) expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x07, 0x61, 0x62, 0x63, 0x20, 0xE2, 0x82, 0xAC]) end it 'should write a binary string' do buffer = [0, 1, 2, 3].pack('C*') @prot.write_binary(buffer) a = @trans.read(@trans.available) expect(a.encoding).to eq(Encoding::BINARY) expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03]) end else it 'should write a string' do str = 'abc' @prot.write_string(str) a = @trans.read(@trans.available) expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63]) end it 'should write a binary string' do buffer = [0, 1, 2, 3].pack('C*') @prot.write_binary(buffer) a = @trans.read(@trans.available) expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03]) end end it "should error gracefully when trying to write a nil string" do expect { @prot.write_string(nil) }.to raise_error end it "should write the message header without version when writes are not strict" do @prot = protocol_class.new(@trans, true, false) # no strict write @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) expect(@trans.read(@trans.available)).to eq("\000\000\000\vtestMessage\001\000\000\000\021") end it "should write the message header with a version when writes are strict" do @prot = protocol_class.new(@trans) # strict write @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17) expect(@trans.read(@trans.available)).to eq("\200\001\000\001\000\000\000\vtestMessage\000\000\000\021") end # message footer is a noop it "should read a field header" do @trans.write([Thrift::Types::STRING, 3].pack("cn")) expect(@prot.read_field_begin).to eq([nil, Thrift::Types::STRING, 3]) end # field footer is a noop it "should read a stop field" do @trans.write([Thrift::Types::STOP].pack("c")); expect(@prot.read_field_begin).to eq([nil, Thrift::Types::STOP, 0]) end it "should read a map header" do @trans.write([Thrift::Types::DOUBLE, Thrift::Types::I64, 42].pack("ccN")) expect(@prot.read_map_begin).to eq([Thrift::Types::DOUBLE, Thrift::Types::I64, 42]) end # map footer is a noop it "should read a list header" do @trans.write([Thrift::Types::STRING, 17].pack("cN")) expect(@prot.read_list_begin).to eq([Thrift::Types::STRING, 17]) end # list footer is a noop it "should read a set header" do @trans.write([Thrift::Types::STRING, 17].pack("cN")) expect(@prot.read_set_begin).to eq([Thrift::Types::STRING, 17]) end # set footer is a noop it "should read a bool" do @trans.write("\001\000"); expect(@prot.read_bool).to eq(true) expect(@prot.read_bool).to eq(false) end it "should read a byte" do [-128, -57, -3, 0, 17, 24, 127].each do |i| @trans.write([i].pack("c")) expect(@prot.read_byte).to eq(i) end end it "should read an i16" do # try a scattering of values, including min/max [-2**15, -5237, -353, 0, 1527, 2234, 2**15-1].each do |i| @trans.write([i].pack("n")); expect(@prot.read_i16).to eq(i) end end it "should read an i32" do # try a scattering of values, including min/max [-2**31, -235125, -6236, 0, 2351, 123123, 2**31-1].each do |i| @trans.write([i].pack("N")) expect(@prot.read_i32).to eq(i) end end it "should read an i64" do # try a scattering of values, including min/max [-2**63, -123512312, -6346, 0, 32, 2346322323, 2**63-1].each do |i| @trans.write([i >> 32, i & 0xFFFFFFFF].pack("NN")) expect(@prot.read_i64).to eq(i) end end it "should read a double" do # try a random scattering of values, including min/max [Float::MIN, -231231.12351, -323.233513, 0, 123.2351235, 2351235.12351235, Float::MAX].each do |f| @trans.write([f].pack("G")); expect(@prot.read_double).to eq(f) end end if RUBY_VERSION >= '1.9' it 'should read a string' do # i32 of value 3, followed by three characters/UTF-8 bytes 'a', 'b', 'c' buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*') @trans.write(buffer) a = @prot.read_string expect(a).to eq('abc'.encode('UTF-8')) expect(a.encoding).to eq(Encoding::UTF_8) end it 'should read a string containing unicode characters from UTF-8 encoded buffer' do # i32 of value 3, followed by one character U+20AC made up of three bytes buffer = [0x00, 0x00, 0x00, 0x03, 0xE2, 0x82, 0xAC].pack('C*') @trans.write(buffer) a = @prot.read_string expect(a).to eq("\u20AC".encode('UTF-8')) expect(a.encoding).to eq(Encoding::UTF_8) end it 'should read a binary string' do buffer = [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03].pack('C*') @trans.write(buffer) a = @prot.read_binary expect(a).to eq([0x00, 0x01, 0x02, 0x03].pack('C*')) expect(a.encoding).to eq(Encoding::BINARY) end else it 'should read a string' do # i32 of value 3, followed by three characters/UTF-8 bytes 'a', 'b', 'c' buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*') @trans.write(buffer) expect(@prot.read_string).to eq('abc') end it 'should read a binary string' do buffer = [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03].pack('C*') @trans.write(buffer) a = @prot.read_binary expect(a).to eq([0x00, 0x01, 0x02, 0x03].pack('C*')) end end it "should perform a complete rpc with no args or return" do srv_test( proc {|client| client.send_voidMethod()}, proc {|client| expect(client.recv_voidMethod).to eq(nil)} ) end it "should perform a complete rpc with a primitive return type" do srv_test( proc {|client| client.send_primitiveMethod()}, proc {|client| expect(client.recv_primitiveMethod).to eq(1)} ) end it "should perform a complete rpc with a struct return type" do srv_test( proc {|client| client.send_structMethod()}, proc {|client| result = client.recv_structMethod result.set_byte_map = nil result.map_byte_map = nil expect(result).to eq(Fixtures::COMPACT_PROTOCOL_TEST_STRUCT) } ) end def get_socket_connection server = Thrift::ServerSocket.new("localhost", 9090) server.listen clientside = Thrift::Socket.new("localhost", 9090) clientside.open serverside = server.accept [clientside, serverside, server] end def srv_test(firstblock, secondblock) clientside, serverside, server = get_socket_connection clientproto = protocol_class.new(clientside) serverproto = protocol_class.new(serverside) processor = Thrift::Test::Srv::Processor.new(SrvHandler.new) client = Thrift::Test::Srv::Client.new(clientproto, clientproto) # first block firstblock.call(client) processor.process(serverproto, serverproto) # second block secondblock.call(client) ensure clientside.close serverside.close server.close end class SrvHandler def voidMethod() end def primitiveMethod 1 end def structMethod Fixtures::COMPACT_PROTOCOL_TEST_STRUCT end end end thrift-0.16.0/lib/rb/spec/bytes_spec.rb000066400000000000000000000116741420101504100176630ustar00rootroot00000000000000# encoding: UTF-8 # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe Thrift::Bytes do if RUBY_VERSION >= '1.9' describe '.empty_byte_buffer' do it 'should create an empty buffer' do b = Thrift::Bytes.empty_byte_buffer expect(b.length).to eq(0) expect(b.encoding).to eq(Encoding::BINARY) end it 'should create an empty buffer of given size' do b = Thrift::Bytes.empty_byte_buffer 2 expect(b.length).to eq(2) expect(b.getbyte(0)).to eq(0) expect(b.getbyte(1)).to eq(0) expect(b.encoding).to eq(Encoding::BINARY) end end describe '.force_binary_encoding' do it 'should change encoding' do e = 'STRING'.encode('UTF-8') expect(e.encoding).not_to eq(Encoding::BINARY) a = Thrift::Bytes.force_binary_encoding e expect(a.encoding).to eq(Encoding::BINARY) end end describe '.get_string_byte' do it 'should get the byte at index' do s = "\x41\x42" expect(Thrift::Bytes.get_string_byte(s, 0)).to eq(0x41) expect(Thrift::Bytes.get_string_byte(s, 1)).to eq(0x42) end end describe '.set_string_byte' do it 'should set byte value at index' do s = "\x41\x42" Thrift::Bytes.set_string_byte(s, 0, 0x43) expect(s.getbyte(0)).to eq(0x43) expect(s).to eq('CB') end end describe '.convert_to_utf8_byte_buffer' do it 'should convert UTF-8 String to byte buffer' do e = "\u20AC".encode('UTF-8') # a string with euro sign character U+20AC expect(e.length).to eq(1) a = Thrift::Bytes.convert_to_utf8_byte_buffer e expect(a.encoding).to eq(Encoding::BINARY) expect(a.length).to eq(3) expect(a.unpack('C*')).to eq([0xE2, 0x82, 0xAC]) end it 'should convert ISO-8859-15 String to UTF-8 byte buffer' do # Assumptions e = "\u20AC".encode('ISO-8859-15') # a string with euro sign character U+20AC, then converted to ISO-8859-15 expect(e.length).to eq(1) expect(e.unpack('C*')).to eq([0xA4]) # euro sign is a different code point in ISO-8859-15 a = Thrift::Bytes.convert_to_utf8_byte_buffer e expect(a.encoding).to eq(Encoding::BINARY) expect(a.length).to eq(3) expect(a.unpack('C*')).to eq([0xE2, 0x82, 0xAC]) end end describe '.convert_to_string' do it 'should convert UTF-8 byte buffer to a UTF-8 String' do e = [0xE2, 0x82, 0xAC].pack("C*") expect(e.encoding).to eq(Encoding::BINARY) a = Thrift::Bytes.convert_to_string e expect(a.encoding).to eq(Encoding::UTF_8) expect(a).to eq("\u20AC") end end else # RUBY_VERSION describe '.empty_byte_buffer' do it 'should create an empty buffer' do b = Thrift::Bytes.empty_byte_buffer expect(b.length).to eq(0) end it 'should create an empty buffer of given size' do b = Thrift::Bytes.empty_byte_buffer 2 expect(b.length).to eq(2) expect(b[0]).to eq(0) expect(b[1]).to eq(0) end end describe '.force_binary_encoding' do it 'should be a no-op' do e = 'STRING' a = Thrift::Bytes.force_binary_encoding e expect(a).to eq(e) expect(a).to be(e) end end describe '.get_string_byte' do it 'should get the byte at index' do s = "\x41\x42" expect(Thrift::Bytes.get_string_byte(s, 0)).to eq(0x41) expect(Thrift::Bytes.get_string_byte(s, 1)).to eq(0x42) end end describe '.set_string_byte' do it 'should set byte value at index' do s = "\x41\x42" Thrift::Bytes.set_string_byte(s, 0, 0x43) expect(s[0]).to eq(0x43) expect(s).to eq('CB') end end describe '.convert_to_utf8_byte_buffer' do it 'should be a no-op' do e = 'STRING' a = Thrift::Bytes.convert_to_utf8_byte_buffer e expect(a).to eq(e) expect(a).to be(e) end end describe '.convert_to_string' do it 'should be a no-op' do e = 'STRING' a = Thrift::Bytes.convert_to_string e expect(a).to eq(e) expect(a).to be(e) end end end end thrift-0.16.0/lib/rb/spec/client_spec.rb000066400000000000000000000101341420101504100200010ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Client' do class ClientSpec include Thrift::Client end before(:each) do @prot = double("MockProtocol") @client = ClientSpec.new(@prot) end describe Thrift::Client do it "should re-use iprot for oprot if not otherwise specified" do expect(@client.instance_variable_get(:'@iprot')).to eql(@prot) expect(@client.instance_variable_get(:'@oprot')).to eql(@prot) end it "should send a test message" do expect(@prot).to receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::CALL, 0) mock_args = double('#') expect(mock_args).to receive(:foo=).with('foo') expect(mock_args).to receive(:bar=).with(42) expect(mock_args).to receive(:write).with(@prot) expect(@prot).to receive(:write_message_end) expect(@prot).to receive(:trans) do double('trans').tap do |trans| expect(trans).to receive(:flush) end end klass = double("TestMessage_args", :new => mock_args) @client.send_message('testMessage', klass, :foo => 'foo', :bar => 42) end it "should increment the sequence id when sending messages" do pending "it seems sequence ids are completely ignored right now" @prot.expect(:write_message_begin).with('testMessage', Thrift::MessageTypes::CALL, 0).ordered @prot.expect(:write_message_begin).with('testMessage2', Thrift::MessageTypes::CALL, 1).ordered @prot.expect(:write_message_begin).with('testMessage3', Thrift::MessageTypes::CALL, 2).ordered @prot.stub!(:write_message_end) @prot.stub!(:trans).and_return double("trans").as_null_object @client.send_message('testMessage', double("args class").as_null_object) @client.send_message('testMessage2', double("args class").as_null_object) @client.send_message('testMessage3', double("args class").as_null_object) end it "should receive a test message" do expect(@prot).to receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::CALL, 0] expect(@prot).to receive(:read_message_end) mock_klass = double("#") expect(mock_klass).to receive(:read).with(@prot) @client.receive_message(double("MockClass", :new => mock_klass)) end it "should handle received exceptions" do expect(@prot).to receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::EXCEPTION, 0] expect(@prot).to receive(:read_message_end) expect(Thrift::ApplicationException).to receive(:new) do StandardError.new.tap do |mock_exc| expect(mock_exc).to receive(:read).with(@prot) end end expect { @client.receive_message(nil) }.to raise_error(StandardError) end it "should close the transport if an error occurs while sending a message" do allow(@prot).to receive(:write_message_begin) expect(@prot).not_to receive(:write_message_end) mock_args = double("#") expect(mock_args).to receive(:write).with(@prot).and_raise(StandardError) trans = double("MockTransport") allow(@prot).to receive(:trans).and_return(trans) expect(trans).to receive(:close) klass = double("TestMessage_args", :new => mock_args) expect { @client.send_message("testMessage", klass) }.to raise_error(StandardError) end end end thrift-0.16.0/lib/rb/spec/compact_protocol_spec.rb000066400000000000000000000131021420101504100220700ustar00rootroot00000000000000# encoding: UTF-8 # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe Thrift::CompactProtocol do TESTS = { :byte => (-127..127).to_a, :i16 => (0..14).map {|shift| [1 << shift, -(1 << shift)]}.flatten.sort, :i32 => (0..30).map {|shift| [1 << shift, -(1 << shift)]}.flatten.sort, :i64 => (0..62).map {|shift| [1 << shift, -(1 << shift)]}.flatten.sort, :string => ["", "1", "short", "fourteen123456", "fifteen12345678", "unicode characters: \u20AC \u20AD", "1" * 127, "1" * 3000], :binary => ["", "\001", "\001" * 5, "\001" * 14, "\001" * 15, "\001" * 127, "\001" * 3000], :double => [0.0, 1.0, -1.0, 1.1, -1.1, 10000000.1, 1.0/0.0, -1.0/0.0], :bool => [true, false] } it "should encode and decode naked primitives correctly" do TESTS.each_pair do |primitive_type, test_values| test_values.each do |value| # puts "testing #{value}" if primitive_type == :i64 trans = Thrift::MemoryBufferTransport.new proto = Thrift::CompactProtocol.new(trans) proto.send(writer(primitive_type), value) # puts "buf: #{trans.inspect_buffer}" if primitive_type == :i64 read_back = proto.send(reader(primitive_type)) expect(read_back).to eq(value) end end end it "should encode and decode primitives in fields correctly" do TESTS.each_pair do |primitive_type, test_values| final_primitive_type = primitive_type == :binary ? :string : primitive_type thrift_type = Thrift::Types.const_get(final_primitive_type.to_s.upcase) # puts primitive_type test_values.each do |value| trans = Thrift::MemoryBufferTransport.new proto = Thrift::CompactProtocol.new(trans) proto.write_field_begin(nil, thrift_type, 15) proto.send(writer(primitive_type), value) proto.write_field_end proto = Thrift::CompactProtocol.new(trans) name, type, id = proto.read_field_begin expect(type).to eq(thrift_type) expect(id).to eq(15) read_back = proto.send(reader(primitive_type)) expect(read_back).to eq(value) proto.read_field_end end end end it "should encode and decode a monster struct correctly" do trans = Thrift::MemoryBufferTransport.new proto = Thrift::CompactProtocol.new(trans) struct = Thrift::Test::CompactProtoTestStruct.new # sets and maps don't hash well... not sure what to do here. struct.write(proto) struct2 = Thrift::Test::CompactProtoTestStruct.new struct2.read(proto) expect(struct2).to eq(struct) end it "should make method calls correctly" do client_out_trans = Thrift::MemoryBufferTransport.new client_out_proto = Thrift::CompactProtocol.new(client_out_trans) client_in_trans = Thrift::MemoryBufferTransport.new client_in_proto = Thrift::CompactProtocol.new(client_in_trans) processor = Thrift::Test::Srv::Processor.new(JankyHandler.new) client = Thrift::Test::Srv::Client.new(client_in_proto, client_out_proto) client.send_Janky(1) # puts client_out_trans.inspect_buffer processor.process(client_out_proto, client_in_proto) expect(client.recv_Janky).to eq(2) end it "should deal with fields following fields that have non-delta ids" do brcp = Thrift::Test::BreaksRubyCompactProtocol.new( :field1 => "blah", :field2 => Thrift::Test::BigFieldIdStruct.new( :field1 => "string1", :field2 => "string2"), :field3 => 3) ser = Thrift::Serializer.new(Thrift::CompactProtocolFactory.new) bytes = ser.serialize(brcp) deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new) brcp2 = Thrift::Test::BreaksRubyCompactProtocol.new deser.deserialize(brcp2, bytes) expect(brcp2).to eq(brcp) end it "should deserialize an empty map to an empty hash" do struct = Thrift::Test::SingleMapTestStruct.new(:i32_map => {}) ser = Thrift::Serializer.new(Thrift::CompactProtocolFactory.new) bytes = ser.serialize(struct) deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new) struct2 = Thrift::Test::SingleMapTestStruct.new deser.deserialize(struct2, bytes) expect(struct).to eq(struct2) end it "should provide a reasonable to_s" do trans = Thrift::MemoryBufferTransport.new expect(Thrift::CompactProtocol.new(trans).to_s).to eq("compact(memory)") end class JankyHandler def Janky(i32arg) i32arg * 2 end end def writer(sym) "write_#{sym.to_s}" end def reader(sym) "read_#{sym.to_s}" end end describe Thrift::CompactProtocolFactory do it "should create a CompactProtocol" do expect(Thrift::CompactProtocolFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::CompactProtocol) end it "should provide a reasonable to_s" do expect(Thrift::CompactProtocolFactory.new.to_s).to eq("compact") end end thrift-0.16.0/lib/rb/spec/exception_spec.rb000066400000000000000000000141241420101504100205240ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Exception' do describe Thrift::Exception do it "should have an accessible message" do e = Thrift::Exception.new("test message") expect(e.message).to eq("test message") end end describe Thrift::ApplicationException do it "should inherit from Thrift::Exception" do expect(Thrift::ApplicationException.superclass).to eq(Thrift::Exception) end it "should have an accessible type and message" do e = Thrift::ApplicationException.new expect(e.type).to eq(Thrift::ApplicationException::UNKNOWN) expect(e.message).to be_nil e = Thrift::ApplicationException.new(Thrift::ApplicationException::UNKNOWN_METHOD, "test message") expect(e.type).to eq(Thrift::ApplicationException::UNKNOWN_METHOD) expect(e.message).to eq("test message") end it "should read a struct off of a protocol" do prot = double("MockProtocol") expect(prot).to receive(:read_struct_begin).ordered expect(prot).to receive(:read_field_begin).exactly(3).times.and_return( ["message", Thrift::Types::STRING, 1], ["type", Thrift::Types::I32, 2], [nil, Thrift::Types::STOP, 0] ) expect(prot).to receive(:read_string).ordered.and_return "test message" expect(prot).to receive(:read_i32).ordered.and_return Thrift::ApplicationException::BAD_SEQUENCE_ID expect(prot).to receive(:read_field_end).exactly(2).times expect(prot).to receive(:read_struct_end).ordered e = Thrift::ApplicationException.new e.read(prot) expect(e.message).to eq("test message") expect(e.type).to eq(Thrift::ApplicationException::BAD_SEQUENCE_ID) end it "should skip bad fields when reading a struct" do prot = double("MockProtocol") expect(prot).to receive(:read_struct_begin).ordered expect(prot).to receive(:read_field_begin).exactly(5).times.and_return( ["type", Thrift::Types::I32, 2], ["type", Thrift::Types::STRING, 2], ["message", Thrift::Types::MAP, 1], ["message", Thrift::Types::STRING, 3], [nil, Thrift::Types::STOP, 0] ) expect(prot).to receive(:read_i32).and_return Thrift::ApplicationException::INVALID_MESSAGE_TYPE expect(prot).to receive(:skip).with(Thrift::Types::STRING).twice expect(prot).to receive(:skip).with(Thrift::Types::MAP) expect(prot).to receive(:read_field_end).exactly(4).times expect(prot).to receive(:read_struct_end).ordered e = Thrift::ApplicationException.new e.read(prot) expect(e.message).to be_nil expect(e.type).to eq(Thrift::ApplicationException::INVALID_MESSAGE_TYPE) end it "should write a Thrift::ApplicationException struct to the oprot" do prot = double("MockProtocol") expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered expect(prot).to receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered expect(prot).to receive(:write_string).with("test message").ordered expect(prot).to receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered expect(prot).to receive(:write_i32).with(Thrift::ApplicationException::UNKNOWN_METHOD).ordered expect(prot).to receive(:write_field_end).twice expect(prot).to receive(:write_field_stop).ordered expect(prot).to receive(:write_struct_end).ordered e = Thrift::ApplicationException.new(Thrift::ApplicationException::UNKNOWN_METHOD, "test message") e.write(prot) end it "should skip nil fields when writing to the oprot" do prot = double("MockProtocol") expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered expect(prot).to receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered expect(prot).to receive(:write_string).with("test message").ordered expect(prot).to receive(:write_field_end).ordered expect(prot).to receive(:write_field_stop).ordered expect(prot).to receive(:write_struct_end).ordered e = Thrift::ApplicationException.new(nil, "test message") e.write(prot) prot = double("MockProtocol") expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered expect(prot).to receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered expect(prot).to receive(:write_i32).with(Thrift::ApplicationException::BAD_SEQUENCE_ID).ordered expect(prot).to receive(:write_field_end).ordered expect(prot).to receive(:write_field_stop).ordered expect(prot).to receive(:write_struct_end).ordered e = Thrift::ApplicationException.new(Thrift::ApplicationException::BAD_SEQUENCE_ID) e.write(prot) prot = double("MockProtocol") expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered expect(prot).to receive(:write_field_stop).ordered expect(prot).to receive(:write_struct_end).ordered e = Thrift::ApplicationException.new(nil) e.write(prot) end end describe Thrift::ProtocolException do it "should have an accessible type" do prot = Thrift::ProtocolException.new(Thrift::ProtocolException::SIZE_LIMIT, "message") expect(prot.type).to eq(Thrift::ProtocolException::SIZE_LIMIT) expect(prot.message).to eq("message") end end end thrift-0.16.0/lib/rb/spec/flat_spec.rb000066400000000000000000000041371420101504100174570ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'generation' do before do require 'namespaced_nonblocking_service' end it "did not generate the wrong files" do prefix = File.expand_path("../gen-rb/flat", __FILE__) ["namespaced_spec_namespace/namespaced_nonblocking_service.rb", "namespaced_spec_namespace/thrift_namespaced_spec_constants.rb", "namespaced_spec_namespace/thrift_namespaced_spec_types.rb", "other_namespace/referenced_constants.rb", "other_namespace/referenced_types.rb" ].each do |name| expect(File.exist?(File.join(prefix, name))).not_to be_truthy end end it "generated the right files" do prefix = File.expand_path("../gen-rb/flat", __FILE__) ["namespaced_nonblocking_service.rb", "thrift_namespaced_spec_constants.rb", "thrift_namespaced_spec_types.rb", "referenced_constants.rb", "referenced_types.rb" ].each do |name| expect(File.exist?(File.join(prefix, name))).to be_truthy end end it "has a service class in the right place" do expect(defined?(NamespacedSpecNamespace::NamespacedNonblockingService)).to be_truthy end it "has a struct in the right place" do expect(defined?(NamespacedSpecNamespace::Hello)).to be_truthy end it "required an included file" do expect(defined?(OtherNamespace::SomeEnum)).to be_truthy end end thrift-0.16.0/lib/rb/spec/http_client_spec.rb000066400000000000000000000135161420101504100210470ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Thrift::HTTPClientTransport' do describe Thrift::HTTPClientTransport do before(:each) do @client = Thrift::HTTPClientTransport.new("http://my.domain.com/path/to/service?param=value") end it "should provide a reasonable to_s" do @client.to_s == "http://my.domain.com/path/to/service?param=value" end it "should always be open" do expect(@client).to be_open @client.close expect(@client).to be_open end it "should post via HTTP and return the results" do @client.write "a test" @client.write " frame" expect(Net::HTTP).to receive(:new).with("my.domain.com", 80) do double("Net::HTTP").tap do |http| expect(http).to receive(:use_ssl=).with(false) expect(http).to receive(:post).with("/path/to/service?param=value", "a test frame", {"Content-Type"=>"application/x-thrift"}) do double("Net::HTTPOK").tap do |response| expect(response).to receive(:body).and_return "data" expect(response).to receive(:code).and_return "200" end end end end @client.flush expect(@client.read(10)).to eq("data") end it "should send custom headers if defined" do @client.write "test" custom_headers = {"Cookie" => "Foo"} headers = {"Content-Type"=>"application/x-thrift"}.merge(custom_headers) @client.add_headers(custom_headers) expect(Net::HTTP).to receive(:new).with("my.domain.com", 80) do double("Net::HTTP").tap do |http| expect(http).to receive(:use_ssl=).with(false) expect(http).to receive(:post).with("/path/to/service?param=value", "test", headers) do double("Net::HTTPOK").tap do |response| expect(response).to receive(:body).and_return "data" expect(response).to receive(:code).and_return "200" end end end end @client.flush end it 'should reset the outbuf on HTTP failures' do @client.write "test" expect(Net::HTTP).to receive(:new).with("my.domain.com", 80) do double("Net::HTTP").tap do |http| expect(http).to receive(:use_ssl=).with(false) expect(http).to receive(:post).with("/path/to/service?param=value", "test", {"Content-Type"=>"application/x-thrift"}) { raise Net::ReadTimeout } end end @client.flush rescue expect(@client.instance_variable_get(:@outbuf)).to eq(Thrift::Bytes.empty_byte_buffer) end it 'should raise TransportError on HTTP failures' do @client.write "test" expect(Net::HTTP).to receive(:new).with("my.domain.com", 80) do double("Net::HTTP").tap do |http| expect(http).to receive(:use_ssl=).with(false) expect(http).to receive(:post).with("/path/to/service?param=value", "test", {"Content-Type"=>"application/x-thrift"}) do double("Net::HTTPOK").tap do |response| expect(response).not_to receive(:body) expect(response).to receive(:code).at_least(:once).and_return "503" end end end end expect { @client.flush }.to raise_error(Thrift::TransportException) end end describe 'ssl enabled' do before(:each) do @service_path = "/path/to/service?param=value" @server_uri = "https://my.domain.com" end it "should use SSL for https" do client = Thrift::HTTPClientTransport.new("#{@server_uri}#{@service_path}") client.write "test" expect(Net::HTTP).to receive(:new).with("my.domain.com", 443) do double("Net::HTTP").tap do |http| expect(http).to receive(:use_ssl=).with(true) expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER) expect(http).to receive(:post).with(@service_path, "test", "Content-Type" => "application/x-thrift") do double("Net::HTTPOK").tap do |response| expect(response).to receive(:body).and_return "data" expect(response).to receive(:code).and_return "200" end end end end client.flush expect(client.read(4)).to eq("data") end it "should set SSL verify mode when specified" do client = Thrift::HTTPClientTransport.new("#{@server_uri}#{@service_path}", :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE) client.write "test" expect(Net::HTTP).to receive(:new).with("my.domain.com", 443) do double("Net::HTTP").tap do |http| expect(http).to receive(:use_ssl=).with(true) expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE) expect(http).to receive(:post).with(@service_path, "test", "Content-Type" => "application/x-thrift") do double("Net::HTTPOK").tap do |response| expect(response).to receive(:body).and_return "data" expect(response).to receive(:code).and_return "200" end end end end client.flush expect(client.read(4)).to eq("data") end end end thrift-0.16.0/lib/rb/spec/json_protocol_spec.rb000066400000000000000000000445421420101504100214270ustar00rootroot00000000000000# encoding: UTF-8 # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'JsonProtocol' do describe Thrift::JsonProtocol do before(:each) do @trans = Thrift::MemoryBufferTransport.new @prot = Thrift::JsonProtocol.new(@trans) end it "should write json escaped char" do @prot.write_json_escape_char("\n") expect(@trans.read(@trans.available)).to eq('\u000a') @prot.write_json_escape_char(" ") expect(@trans.read(@trans.available)).to eq('\u0020') end it "should write json char" do @prot.write_json_char("\n") expect(@trans.read(@trans.available)).to eq('\\n') @prot.write_json_char(" ") expect(@trans.read(@trans.available)).to eq(' ') @prot.write_json_char("\\") expect(@trans.read(@trans.available)).to eq("\\\\") @prot.write_json_char("@") expect(@trans.read(@trans.available)).to eq('@') end it "should write json string" do @prot.write_json_string("this is a \\ json\nstring") expect(@trans.read(@trans.available)).to eq("\"this is a \\\\ json\\nstring\"") end it "should write json base64" do @prot.write_json_base64("this is a base64 string") expect(@trans.read(@trans.available)).to eq("\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"") end it "should write json integer" do @prot.write_json_integer(45) expect(@trans.read(@trans.available)).to eq("45") @prot.write_json_integer(33000) expect(@trans.read(@trans.available)).to eq("33000") @prot.write_json_integer(3000000000) expect(@trans.read(@trans.available)).to eq("3000000000") @prot.write_json_integer(6000000000) expect(@trans.read(@trans.available)).to eq("6000000000") end it "should write json double" do @prot.write_json_double(12.3) expect(@trans.read(@trans.available)).to eq("12.3") @prot.write_json_double(-3.21) expect(@trans.read(@trans.available)).to eq("-3.21") @prot.write_json_double(((+1.0/0.0)/(+1.0/0.0))) expect(@trans.read(@trans.available)).to eq("\"NaN\"") @prot.write_json_double((+1.0/0.0)) expect(@trans.read(@trans.available)).to eq("\"Infinity\"") @prot.write_json_double((-1.0/0.0)) expect(@trans.read(@trans.available)).to eq("\"-Infinity\"") end it "should write json object start" do @prot.write_json_object_start expect(@trans.read(@trans.available)).to eq("{") end it "should write json object end" do @prot.write_json_object_end expect(@trans.read(@trans.available)).to eq("}") end it "should write json array start" do @prot.write_json_array_start expect(@trans.read(@trans.available)).to eq("[") end it "should write json array end" do @prot.write_json_array_end expect(@trans.read(@trans.available)).to eq("]") end it "should write message begin" do @prot.write_message_begin("name", 12, 32) expect(@trans.read(@trans.available)).to eq("[1,\"name\",12,32") end it "should write message end" do @prot.write_message_end expect(@trans.read(@trans.available)).to eq("]") end it "should write struct begin" do @prot.write_struct_begin("name") expect(@trans.read(@trans.available)).to eq("{") end it "should write struct end" do @prot.write_struct_end expect(@trans.read(@trans.available)).to eq("}") end it "should write field begin" do @prot.write_field_begin("name", Thrift::Types::STRUCT, 32) expect(@trans.read(@trans.available)).to eq("32{\"rec\"") end it "should write field end" do @prot.write_field_end expect(@trans.read(@trans.available)).to eq("}") end it "should write field stop" do @prot.write_field_stop expect(@trans.read(@trans.available)).to eq("") end it "should write map begin" do @prot.write_map_begin(Thrift::Types::STRUCT, Thrift::Types::LIST, 32) expect(@trans.read(@trans.available)).to eq("[\"rec\",\"lst\",32,{") end it "should write map end" do @prot.write_map_end expect(@trans.read(@trans.available)).to eq("}]") end it "should write list begin" do @prot.write_list_begin(Thrift::Types::STRUCT, 32) expect(@trans.read(@trans.available)).to eq("[\"rec\",32") end it "should write list end" do @prot.write_list_end expect(@trans.read(@trans.available)).to eq("]") end it "should write set begin" do @prot.write_set_begin(Thrift::Types::STRUCT, 32) expect(@trans.read(@trans.available)).to eq("[\"rec\",32") end it "should write set end" do @prot.write_set_end expect(@trans.read(@trans.available)).to eq("]") end it "should write bool" do @prot.write_bool(true) expect(@trans.read(@trans.available)).to eq("1") @prot.write_bool(false) expect(@trans.read(@trans.available)).to eq("0") end it "should write byte" do @prot.write_byte(100) expect(@trans.read(@trans.available)).to eq("100") end it "should write i16" do @prot.write_i16(1000) expect(@trans.read(@trans.available)).to eq("1000") end it "should write i32" do @prot.write_i32(3000000000) expect(@trans.read(@trans.available)).to eq("3000000000") end it "should write i64" do @prot.write_i64(6000000000) expect(@trans.read(@trans.available)).to eq("6000000000") end it "should write double" do @prot.write_double(1.23) expect(@trans.read(@trans.available)).to eq("1.23") @prot.write_double(-32.1) expect(@trans.read(@trans.available)).to eq("-32.1") @prot.write_double(((+1.0/0.0)/(+1.0/0.0))) expect(@trans.read(@trans.available)).to eq("\"NaN\"") @prot.write_double((+1.0/0.0)) expect(@trans.read(@trans.available)).to eq("\"Infinity\"") @prot.write_double((-1.0/0.0)) expect(@trans.read(@trans.available)).to eq("\"-Infinity\"") end if RUBY_VERSION >= '1.9' it 'should write string' do @prot.write_string('this is a test string') a = @trans.read(@trans.available) expect(a).to eq('"this is a test string"'.force_encoding(Encoding::BINARY)) expect(a.encoding).to eq(Encoding::BINARY) end it 'should write string with unicode characters' do @prot.write_string("this is a test string with unicode characters: \u20AC \u20AD") a = @trans.read(@trans.available) expect(a).to eq("\"this is a test string with unicode characters: \u20AC \u20AD\"".force_encoding(Encoding::BINARY)) expect(a.encoding).to eq(Encoding::BINARY) end else it 'should write string' do @prot.write_string('this is a test string') expect(@trans.read(@trans.available)).to eq('"this is a test string"') end end it "should write binary" do @prot.write_binary("this is a base64 string") expect(@trans.read(@trans.available)).to eq("\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"") end it "should write long binary" do @prot.write_binary((0...256).to_a.pack('C*')) expect(@trans.read(@trans.available)).to eq("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"") end it "should get type name for type id" do expect {@prot.get_type_name_for_type_id(Thrift::Types::STOP)}.to raise_error(NotImplementedError) expect {@prot.get_type_name_for_type_id(Thrift::Types::VOID)}.to raise_error(NotImplementedError) expect(@prot.get_type_name_for_type_id(Thrift::Types::BOOL)).to eq("tf") expect(@prot.get_type_name_for_type_id(Thrift::Types::BYTE)).to eq("i8") expect(@prot.get_type_name_for_type_id(Thrift::Types::DOUBLE)).to eq("dbl") expect(@prot.get_type_name_for_type_id(Thrift::Types::I16)).to eq("i16") expect(@prot.get_type_name_for_type_id(Thrift::Types::I32)).to eq("i32") expect(@prot.get_type_name_for_type_id(Thrift::Types::I64)).to eq("i64") expect(@prot.get_type_name_for_type_id(Thrift::Types::STRING)).to eq("str") expect(@prot.get_type_name_for_type_id(Thrift::Types::STRUCT)).to eq("rec") expect(@prot.get_type_name_for_type_id(Thrift::Types::MAP)).to eq("map") expect(@prot.get_type_name_for_type_id(Thrift::Types::SET)).to eq("set") expect(@prot.get_type_name_for_type_id(Thrift::Types::LIST)).to eq("lst") end it "should get type id for type name" do expect {@prot.get_type_id_for_type_name("pp")}.to raise_error(NotImplementedError) expect(@prot.get_type_id_for_type_name("tf")).to eq(Thrift::Types::BOOL) expect(@prot.get_type_id_for_type_name("i8")).to eq(Thrift::Types::BYTE) expect(@prot.get_type_id_for_type_name("dbl")).to eq(Thrift::Types::DOUBLE) expect(@prot.get_type_id_for_type_name("i16")).to eq(Thrift::Types::I16) expect(@prot.get_type_id_for_type_name("i32")).to eq(Thrift::Types::I32) expect(@prot.get_type_id_for_type_name("i64")).to eq(Thrift::Types::I64) expect(@prot.get_type_id_for_type_name("str")).to eq(Thrift::Types::STRING) expect(@prot.get_type_id_for_type_name("rec")).to eq(Thrift::Types::STRUCT) expect(@prot.get_type_id_for_type_name("map")).to eq(Thrift::Types::MAP) expect(@prot.get_type_id_for_type_name("set")).to eq(Thrift::Types::SET) expect(@prot.get_type_id_for_type_name("lst")).to eq(Thrift::Types::LIST) end it "should read json syntax char" do @trans.write('F') expect {@prot.read_json_syntax_char('G')}.to raise_error(Thrift::ProtocolException) @trans.write('H') @prot.read_json_syntax_char('H') end it "should read json escape char" do @trans.write('0054') expect(@prot.read_json_escape_char).to eq('T') @trans.write("\"\\\"\"") expect(@prot.read_json_string(false)).to eq("\"") @trans.write("\"\\\\\"") expect(@prot.read_json_string(false)).to eq("\\") @trans.write("\"\\/\"") expect(@prot.read_json_string(false)).to eq("\/") @trans.write("\"\\b\"") expect(@prot.read_json_string(false)).to eq("\b") @trans.write("\"\\f\"") expect(@prot.read_json_string(false)).to eq("\f") @trans.write("\"\\n\"") expect(@prot.read_json_string(false)).to eq("\n") @trans.write("\"\\r\"") expect(@prot.read_json_string(false)).to eq("\r") @trans.write("\"\\t\"") expect(@prot.read_json_string(false)).to eq("\t") end it "should read json string" do @trans.write("\"\\P") expect {@prot.read_json_string(false)}.to raise_error(Thrift::ProtocolException) @trans.write("\"this is a test string\"") expect(@prot.read_json_string).to eq("this is a test string") end it "should read json base64" do @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"") expect(@prot.read_json_base64).to eq("this is a test string") end it "should is json numeric" do expect(@prot.is_json_numeric("A")).to eq(false) expect(@prot.is_json_numeric("+")).to eq(true) expect(@prot.is_json_numeric("-")).to eq(true) expect(@prot.is_json_numeric(".")).to eq(true) expect(@prot.is_json_numeric("0")).to eq(true) expect(@prot.is_json_numeric("1")).to eq(true) expect(@prot.is_json_numeric("2")).to eq(true) expect(@prot.is_json_numeric("3")).to eq(true) expect(@prot.is_json_numeric("4")).to eq(true) expect(@prot.is_json_numeric("5")).to eq(true) expect(@prot.is_json_numeric("6")).to eq(true) expect(@prot.is_json_numeric("7")).to eq(true) expect(@prot.is_json_numeric("8")).to eq(true) expect(@prot.is_json_numeric("9")).to eq(true) expect(@prot.is_json_numeric("E")).to eq(true) expect(@prot.is_json_numeric("e")).to eq(true) end it "should read json numeric chars" do @trans.write("1.453E45T") expect(@prot.read_json_numeric_chars).to eq("1.453E45") end it "should read json integer" do @trans.write("1.45\"\"") expect {@prot.read_json_integer}.to raise_error(Thrift::ProtocolException) @prot.read_string @trans.write("1453T") expect(@prot.read_json_integer).to eq(1453) end it "should read json double" do @trans.write("1.45e3e01\"\"") expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException) @prot.read_string @trans.write("\"1.453e01\"") expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException) @trans.write("1.453e01\"\"") expect(@prot.read_json_double).to eq(14.53) @prot.read_string @trans.write("\"NaN\"") expect(@prot.read_json_double.nan?).to eq(true) @trans.write("\"Infinity\"") expect(@prot.read_json_double).to eq(+1.0/0.0) @trans.write("\"-Infinity\"") expect(@prot.read_json_double).to eq(-1.0/0.0) end it "should read json object start" do @trans.write("{") expect(@prot.read_json_object_start).to eq(nil) end it "should read json object end" do @trans.write("}") expect(@prot.read_json_object_end).to eq(nil) end it "should read json array start" do @trans.write("[") expect(@prot.read_json_array_start).to eq(nil) end it "should read json array end" do @trans.write("]") expect(@prot.read_json_array_end).to eq(nil) end it "should read_message_begin" do @trans.write("[2,") expect {@prot.read_message_begin}.to raise_error(Thrift::ProtocolException) @trans.write("[1,\"name\",12,32\"\"") expect(@prot.read_message_begin).to eq(["name", 12, 32]) end it "should read message end" do @trans.write("]") expect(@prot.read_message_end).to eq(nil) end it "should read struct begin" do @trans.write("{") expect(@prot.read_struct_begin).to eq(nil) end it "should read struct end" do @trans.write("}") expect(@prot.read_struct_end).to eq(nil) end it "should read field begin" do @trans.write("1{\"rec\"") expect(@prot.read_field_begin).to eq([nil, 12, 1]) end it "should read field end" do @trans.write("}") expect(@prot.read_field_end).to eq(nil) end it "should read map begin" do @trans.write("[\"rec\",\"lst\",2,{") expect(@prot.read_map_begin).to eq([12, 15, 2]) end it "should read map end" do @trans.write("}]") expect(@prot.read_map_end).to eq(nil) end it "should read list begin" do @trans.write("[\"rec\",2\"\"") expect(@prot.read_list_begin).to eq([12, 2]) end it "should read list end" do @trans.write("]") expect(@prot.read_list_end).to eq(nil) end it "should read set begin" do @trans.write("[\"rec\",2\"\"") expect(@prot.read_set_begin).to eq([12, 2]) end it "should read set end" do @trans.write("]") expect(@prot.read_set_end).to eq(nil) end it "should read bool" do @trans.write("0\"\"") expect(@prot.read_bool).to eq(false) @prot.read_string @trans.write("1\"\"") expect(@prot.read_bool).to eq(true) end it "should read byte" do @trans.write("60\"\"") expect(@prot.read_byte).to eq(60) end it "should read i16" do @trans.write("1000\"\"") expect(@prot.read_i16).to eq(1000) end it "should read i32" do @trans.write("3000000000\"\"") expect(@prot.read_i32).to eq(3000000000) end it "should read i64" do @trans.write("6000000000\"\"") expect(@prot.read_i64).to eq(6000000000) end it "should read double" do @trans.write("12.23\"\"") expect(@prot.read_double).to eq(12.23) end if RUBY_VERSION >= '1.9' it 'should read string' do @trans.write('"this is a test string"'.force_encoding(Encoding::BINARY)) a = @prot.read_string expect(a).to eq('this is a test string') expect(a.encoding).to eq(Encoding::UTF_8) end it 'should read string with unicode characters' do @trans.write('"this is a test string with unicode characters: \u20AC \u20AD"'.force_encoding(Encoding::BINARY)) a = @prot.read_string expect(a).to eq("this is a test string with unicode characters: \u20AC \u20AD") expect(a.encoding).to eq(Encoding::UTF_8) end else it 'should read string' do @trans.write('"this is a test string"') expect(@prot.read_string).to eq('this is a test string') end end it "should read binary" do @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"") expect(@prot.read_binary).to eq("this is a test string") end it "should read long binary" do @trans.write("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"") expect(@prot.read_binary.bytes.to_a).to eq((0...256).to_a) end it "should provide a reasonable to_s" do expect(@prot.to_s).to eq("json(memory)") end end describe Thrift::JsonProtocolFactory do it "should create a JsonProtocol" do expect(Thrift::JsonProtocolFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::JsonProtocol) end it "should provide a reasonable to_s" do expect(Thrift::JsonProtocolFactory.new.to_s).to eq("json") end end end thrift-0.16.0/lib/rb/spec/namespaced_spec.rb000066400000000000000000000043071420101504100206300ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'namespaced generation' do before do require 'namespaced_spec_namespace/namespaced_nonblocking_service' end it "generated the right files" do prefix = File.expand_path("../gen-rb", __FILE__) ["namespaced_spec_namespace/namespaced_nonblocking_service.rb", "namespaced_spec_namespace/thrift_namespaced_spec_constants.rb", "namespaced_spec_namespace/thrift_namespaced_spec_types.rb", "other_namespace/referenced_constants.rb", "other_namespace/referenced_types.rb" ].each do |name| expect(File.exist?(File.join(prefix, name))).to be_truthy end end it "did not generate the wrong files" do prefix = File.expand_path("../gen-rb", __FILE__) ["namespaced_nonblocking_service.rb", "thrift_namespaced_spec_constants.rb", "thrift_namespaced_spec_types.rb", "referenced_constants.rb", "referenced_types.rb" ].each do |name| expect(File.exist?(File.join(prefix, name))).not_to be_truthy end end it "has a service class in the right place" do expect(defined?(NamespacedSpecNamespace::NamespacedNonblockingService)).to be_truthy end it "has a struct in the right place" do expect(defined?(NamespacedSpecNamespace::Hello)).to be_truthy end it "required an included file" do expect(defined?(OtherNamespace::SomeEnum)).to be_truthy end it "extended a service" do require "extended/extended_service" end end thrift-0.16.0/lib/rb/spec/nonblocking_server_spec.rb000066400000000000000000000162301420101504100224170ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'NonblockingServer' do class Handler def initialize @queue = Queue.new end attr_accessor :server def greeting(english) if english SpecNamespace::Hello.new else SpecNamespace::Hello.new(:greeting => "Aloha!") end end def block @queue.pop end def unblock(n) n.times { @queue.push true } end def sleep(time) Kernel.sleep time end def shutdown @server.shutdown(0, false) end end class SpecTransport < Thrift::BaseTransport def initialize(transport, queue) @transport = transport @queue = queue @flushed = false end def open? @transport.open? end def open @transport.open end def close @transport.close end def read(sz) @transport.read(sz) end def write(buf,sz=nil) @transport.write(buf, sz) end def flush @queue.push :flushed unless @flushed or @queue.nil? @flushed = true @transport.flush end end class SpecServerSocket < Thrift::ServerSocket def initialize(host, port, queue) super(host, port) @queue = queue end def listen super @queue.push :listen end end describe Thrift::NonblockingServer do before(:each) do @port = 43251 handler = Handler.new processor = SpecNamespace::NonblockingService::Processor.new(handler) queue = Queue.new @transport = SpecServerSocket.new('localhost', @port, queue) transport_factory = Thrift::FramedTransportFactory.new logger = Logger.new(STDERR) logger.level = Logger::WARN @server = Thrift::NonblockingServer.new(processor, @transport, transport_factory, nil, 5, logger) handler.server = @server @server_thread = Thread.new(Thread.current) do |master_thread| begin @server.serve rescue => e p e puts e.backtrace * "\n" master_thread.raise e end end queue.pop @clients = [] @catch_exceptions = false end after(:each) do @clients.each { |client, trans| trans.close } # @server.shutdown(1) @server_thread.kill @transport.close end def setup_client(queue = nil) transport = SpecTransport.new(Thrift::FramedTransport.new(Thrift::Socket.new('localhost', @port)), queue) protocol = Thrift::BinaryProtocol.new(transport) client = SpecNamespace::NonblockingService::Client.new(protocol) transport.open @clients << [client, transport] client end def setup_client_thread(result) queue = Queue.new Thread.new do begin client = setup_client while (cmd = queue.pop) msg, *args = cmd case msg when :block result << client.block when :unblock client.unblock(args.first) when :hello result << client.greeting(true) # ignore result when :sleep client.sleep(args[0] || 0.5) result << :slept when :shutdown client.shutdown when :exit result << :done break end end @clients.each { |c,t| t.close and break if c == client } #close the transport rescue => e raise e unless @catch_exceptions end end queue end it "should handle basic message passing" do client = setup_client expect(client.greeting(true)).to eq(SpecNamespace::Hello.new) expect(client.greeting(false)).to eq(SpecNamespace::Hello.new(:greeting => 'Aloha!')) @server.shutdown end it "should handle concurrent clients" do queue = Queue.new trans_queue = Queue.new 4.times do Thread.new(Thread.current) do |main_thread| begin queue.push setup_client(trans_queue).block rescue => e main_thread.raise e end end end 4.times { trans_queue.pop } setup_client.unblock(4) 4.times { expect(queue.pop).to be_truthy } @server.shutdown end it "should handle messages from more than 5 long-lived connections" do queues = [] result = Queue.new 7.times do |i| queues << setup_client_thread(result) Thread.pass if i == 4 # give the server time to accept connections end client = setup_client # block 4 connections 4.times { |i| queues[i] << :block } queues[4] << :hello queues[5] << :hello queues[6] << :hello 3.times { expect(result.pop).to eq(SpecNamespace::Hello.new) } expect(client.greeting(true)).to eq(SpecNamespace::Hello.new) queues[5] << [:unblock, 4] 4.times { expect(result.pop).to be_truthy } queues[2] << :hello expect(result.pop).to eq(SpecNamespace::Hello.new) expect(client.greeting(false)).to eq(SpecNamespace::Hello.new(:greeting => 'Aloha!')) 7.times { queues.shift << :exit } expect(client.greeting(true)).to eq(SpecNamespace::Hello.new) @server.shutdown end it "should shut down when asked" do # connect first to ensure it's running client = setup_client client.greeting(false) # force a message pass @server.shutdown expect(@server_thread.join(2)).to be_an_instance_of(Thread) end it "should continue processing active messages when shutting down" do result = Queue.new client = setup_client_thread(result) client << :sleep sleep 0.1 # give the server time to start processing the client's message @server.shutdown expect(@server_thread.join(2)).to be_an_instance_of(Thread) expect(result.pop).to eq(:slept) end it "should kill active messages when they don't expire while shutting down" do result = Queue.new client = setup_client_thread(result) client << [:sleep, 10] sleep 0.1 # start processing the client's message @server.shutdown(1) @catch_exceptions = true expect(@server_thread.join(3)).not_to be_nil expect(result).to be_empty end it "should allow shutting down in response to a message" do client = setup_client expect(client.greeting(true)).to eq(SpecNamespace::Hello.new) client.shutdown expect(@server_thread.join(2)).not_to be_nil end end end thrift-0.16.0/lib/rb/spec/processor_spec.rb000066400000000000000000000063221420101504100205460ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Processor' do class ProcessorSpec include Thrift::Processor end describe Thrift::Processor do before(:each) do @processor = ProcessorSpec.new(double("MockHandler")) @prot = double("MockProtocol") end def mock_trans(obj) expect(obj).to receive(:trans).ordered do double("trans").tap do |trans| expect(trans).to receive(:flush).ordered end end end it "should call process_ when it receives that message" do expect(@prot).to receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 17] expect(@processor).to receive(:process_testMessage).with(17, @prot, @prot).ordered expect(@processor.process(@prot, @prot)).to eq(true) end it "should raise an ApplicationException when the received message cannot be processed" do expect(@prot).to receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 4] expect(@prot).to receive(:skip).with(Thrift::Types::STRUCT).ordered expect(@prot).to receive(:read_message_end).ordered expect(@prot).to receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::EXCEPTION, 4).ordered e = double(Thrift::ApplicationException) expect(e).to receive(:write).with(@prot).ordered expect(Thrift::ApplicationException).to receive(:new).with(Thrift::ApplicationException::UNKNOWN_METHOD, "Unknown function testMessage").and_return(e) expect(@prot).to receive(:write_message_end).ordered mock_trans(@prot) @processor.process(@prot, @prot) end it "should pass args off to the args class" do args_class = double("MockArgsClass") args = double("#").tap do |args| expect(args).to receive(:read).with(@prot).ordered end expect(args_class).to receive(:new).and_return args expect(@prot).to receive(:read_message_end).ordered expect(@processor.read_args(@prot, args_class)).to eql(args) end it "should write out a reply when asked" do expect(@prot).to receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::REPLY, 23).ordered result = double("MockResult") expect(result).to receive(:write).with(@prot).ordered expect(@prot).to receive(:write_message_end).ordered mock_trans(@prot) @processor.write_result(result, @prot, 'testMessage', 23) end end end thrift-0.16.0/lib/rb/spec/serializer_spec.rb000066400000000000000000000063011420101504100206750ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Serializer' do describe Thrift::Serializer do it "should serialize structs to binary by default" do serializer = Thrift::Serializer.new(Thrift::BinaryProtocolAcceleratedFactory.new) data = serializer.serialize(SpecNamespace::Hello.new(:greeting => "'Ello guv'nor!")) expect(data).to eq("\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00") end it "should serialize structs to the given protocol" do protocol = Thrift::BaseProtocol.new(double("transport")) expect(protocol).to receive(:write_struct_begin).with("SpecNamespace::Hello") expect(protocol).to receive(:write_field_begin).with("greeting", Thrift::Types::STRING, 1) expect(protocol).to receive(:write_string).with("Good day") expect(protocol).to receive(:write_field_end) expect(protocol).to receive(:write_field_stop) expect(protocol).to receive(:write_struct_end) protocol_factory = double("ProtocolFactory") allow(protocol_factory).to receive(:get_protocol).and_return(protocol) serializer = Thrift::Serializer.new(protocol_factory) serializer.serialize(SpecNamespace::Hello.new(:greeting => "Good day")) end end describe Thrift::Deserializer do it "should deserialize structs from binary by default" do deserializer = Thrift::Deserializer.new data = "\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00" expect(deserializer.deserialize(SpecNamespace::Hello.new, data)).to eq(SpecNamespace::Hello.new(:greeting => "'Ello guv'nor!")) end it "should deserialize structs from the given protocol" do protocol = Thrift::BaseProtocol.new(double("transport")) expect(protocol).to receive(:read_struct_begin).and_return("SpecNamespace::Hello") expect(protocol).to receive(:read_field_begin).and_return(["greeting", Thrift::Types::STRING, 1], [nil, Thrift::Types::STOP, 0]) expect(protocol).to receive(:read_string).and_return("Good day") expect(protocol).to receive(:read_field_end) expect(protocol).to receive(:read_struct_end) protocol_factory = double("ProtocolFactory") allow(protocol_factory).to receive(:get_protocol).and_return(protocol) deserializer = Thrift::Deserializer.new(protocol_factory) expect(deserializer.deserialize(SpecNamespace::Hello.new, "")).to eq(SpecNamespace::Hello.new(:greeting => "Good day")) end end end thrift-0.16.0/lib/rb/spec/server_socket_spec.rb000066400000000000000000000055171420101504100214120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") describe 'Thrift::ServerSocket' do describe Thrift::ServerSocket do before(:each) do @socket = Thrift::ServerSocket.new(1234) end it "should create a handle when calling listen" do expect(TCPServer).to receive(:new).with(nil, 1234) @socket.listen end it "should accept an optional host argument" do @socket = Thrift::ServerSocket.new('localhost', 1234) expect(TCPServer).to receive(:new).with('localhost', 1234) @socket.to_s == "server(localhost:1234)" @socket.listen end it "should create a Thrift::Socket to wrap accepted sockets" do handle = double("TCPServer") expect(TCPServer).to receive(:new).with(nil, 1234).and_return(handle) @socket.listen sock = double("sock") expect(handle).to receive(:accept).and_return(sock) trans = double("Socket") expect(Thrift::Socket).to receive(:new).and_return(trans) expect(trans).to receive(:handle=).with(sock) expect(@socket.accept).to eq(trans) end it "should close the handle when closed" do handle = double("TCPServer", :closed? => false) expect(TCPServer).to receive(:new).with(nil, 1234).and_return(handle) @socket.listen expect(handle).to receive(:close) @socket.close end it "should return nil when accepting if there is no handle" do expect(@socket.accept).to be_nil end it "should return true for closed? when appropriate" do handle = double("TCPServer", :closed? => false) allow(TCPServer).to receive(:new).and_return(handle) @socket.listen expect(@socket).not_to be_closed allow(handle).to receive(:close) @socket.close expect(@socket).to be_closed @socket.listen expect(@socket).not_to be_closed allow(handle).to receive(:closed?).and_return(true) expect(@socket).to be_closed end it "should provide a reasonable to_s" do expect(@socket.to_s).to eq("socket(:1234)") end end end thrift-0.16.0/lib/rb/spec/server_spec.rb000066400000000000000000000173241420101504100200410ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Server' do describe Thrift::BaseServer do before(:each) do @processor = double("Processor") @serverTrans = double("ServerTransport") @trans = double("BaseTransport") @prot = double("BaseProtocol") @server = described_class.new(@processor, @serverTrans, @trans, @prot) end it "should default to BaseTransportFactory and BinaryProtocolFactory when not specified" do @server = Thrift::BaseServer.new(double("Processor"), double("BaseServerTransport")) expect(@server.instance_variable_get(:'@transport_factory')).to be_an_instance_of(Thrift::BaseTransportFactory) expect(@server.instance_variable_get(:'@protocol_factory')).to be_an_instance_of(Thrift::BinaryProtocolFactory) end it "should not serve" do expect { @server.serve()}.to raise_error(NotImplementedError) end it "should provide a reasonable to_s" do expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans") expect(@trans).to receive(:to_s).once.and_return("trans") expect(@prot).to receive(:to_s).once.and_return("prot") expect(@server.to_s).to eq("server(prot(trans(serverTrans)))") end end describe Thrift::SimpleServer do before(:each) do @processor = double("Processor") @serverTrans = double("ServerTransport") @trans = double("BaseTransport") @prot = double("BaseProtocol") @client = double("Client") @server = described_class.new(@processor, @serverTrans, @trans, @prot) end it "should provide a reasonable to_s" do expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans") expect(@trans).to receive(:to_s).once.and_return("trans") expect(@prot).to receive(:to_s).once.and_return("prot") expect(@server.to_s).to eq("simple(server(prot(trans(serverTrans))))") end it "should serve in the main thread" do expect(@serverTrans).to receive(:listen).ordered expect(@serverTrans).to receive(:accept).exactly(3).times.and_return(@client) expect(@trans).to receive(:get_transport).exactly(3).times.with(@client).and_return(@trans) expect(@prot).to receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot) x = 0 expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do case (x += 1) when 1 then raise Thrift::TransportException when 2 then raise Thrift::ProtocolException when 3 then throw :stop end end expect(@trans).to receive(:close).exactly(3).times expect(@serverTrans).to receive(:close).ordered expect { @server.serve }.to throw_symbol(:stop) end end describe Thrift::ThreadedServer do before(:each) do @processor = double("Processor") @serverTrans = double("ServerTransport") @trans = double("BaseTransport") @prot = double("BaseProtocol") @client = double("Client") @server = described_class.new(@processor, @serverTrans, @trans, @prot) end it "should provide a reasonable to_s" do expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans") expect(@trans).to receive(:to_s).once.and_return("trans") expect(@prot).to receive(:to_s).once.and_return("prot") expect(@server.to_s).to eq("threaded(server(prot(trans(serverTrans))))") end it "should serve using threads" do expect(@serverTrans).to receive(:listen).ordered expect(@serverTrans).to receive(:accept).exactly(3).times.and_return(@client) expect(@trans).to receive(:get_transport).exactly(3).times.with(@client).and_return(@trans) expect(@prot).to receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot) expect(Thread).to receive(:new).with(@prot, @trans).exactly(3).times.and_yield(@prot, @trans) x = 0 expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do case (x += 1) when 1 then raise Thrift::TransportException when 2 then raise Thrift::ProtocolException when 3 then throw :stop end end expect(@trans).to receive(:close).exactly(3).times expect(@serverTrans).to receive(:close).ordered expect { @server.serve }.to throw_symbol(:stop) end end describe Thrift::ThreadPoolServer do before(:each) do @processor = double("Processor") @server_trans = double("ServerTransport") @trans = double("BaseTransport") @prot = double("BaseProtocol") @client = double("Client") @server = described_class.new(@processor, @server_trans, @trans, @prot) sleep(0.15) end it "should provide a reasonable to_s" do expect(@server_trans).to receive(:to_s).once.and_return("server_trans") expect(@trans).to receive(:to_s).once.and_return("trans") expect(@prot).to receive(:to_s).once.and_return("prot") expect(@server.to_s).to eq("threadpool(server(prot(trans(server_trans))))") end it "should serve inside a thread" do exception_q = @server.instance_variable_get(:@exception_q) expect_any_instance_of(described_class).to receive(:serve) do exception_q.push(StandardError.new('ERROR')) end expect { @server.rescuable_serve }.to(raise_error('ERROR')) sleep(0.15) end it "should avoid running the server twice when retrying rescuable_serve" do exception_q = @server.instance_variable_get(:@exception_q) expect_any_instance_of(described_class).to receive(:serve) do exception_q.push(StandardError.new('ERROR1')) exception_q.push(StandardError.new('ERROR2')) end expect { @server.rescuable_serve }.to(raise_error('ERROR1')) expect { @server.rescuable_serve }.to(raise_error('ERROR2')) end it "should serve using a thread pool" do thread_q = double("SizedQueue") exception_q = double("Queue") @server.instance_variable_set(:@thread_q, thread_q) @server.instance_variable_set(:@exception_q, exception_q) expect(@server_trans).to receive(:listen).ordered expect(thread_q).to receive(:push).with(:token) expect(thread_q).to receive(:pop) expect(Thread).to receive(:new).and_yield expect(@server_trans).to receive(:accept).exactly(3).times.and_return(@client) expect(@trans).to receive(:get_transport).exactly(3).times.and_return(@trans) expect(@prot).to receive(:get_protocol).exactly(3).times.and_return(@prot) x = 0 error = RuntimeError.new("Stopped") expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do case (x += 1) when 1 then raise Thrift::TransportException when 2 then raise Thrift::ProtocolException when 3 then raise error end end expect(@trans).to receive(:close).exactly(3).times expect(exception_q).to receive(:push).with(error).and_throw(:stop) expect(@server_trans).to receive(:close) expect { @server.serve }.to(throw_symbol(:stop)) end end end thrift-0.16.0/lib/rb/spec/socket_spec.rb000066400000000000000000000054101420101504100200140ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") describe 'Socket' do describe Thrift::Socket do before(:each) do @socket = Thrift::Socket.new @handle = double("Handle", :closed? => false) allow(@handle).to receive(:close) allow(@handle).to receive(:connect_nonblock) allow(@handle).to receive(:setsockopt) allow(::Socket).to receive(:new).and_return(@handle) end it_should_behave_like "a socket" it "should raise a TransportException when it cannot open a socket" do expect(::Socket).to receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]]) expect { @socket.open }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) } end it "should open a ::Socket with default args" do expect(::Socket).to receive(:new).and_return(double("Handle", :connect_nonblock => true, :setsockopt => nil)) expect(::Socket).to receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]]) expect(::Socket).to receive(:sockaddr_in) @socket.to_s == "socket(localhost:9090)" @socket.open end it "should accept host/port options" do expect(::Socket).to receive(:new).and_return(double("Handle", :connect_nonblock => true, :setsockopt => nil)) expect(::Socket).to receive(:getaddrinfo).with("my.domain", 1234, nil, ::Socket::SOCK_STREAM).and_return([[]]) expect(::Socket).to receive(:sockaddr_in) @socket = Thrift::Socket.new('my.domain', 1234).open @socket.to_s == "socket(my.domain:1234)" end it "should accept an optional timeout" do allow(::Socket).to receive(:new) expect(Thrift::Socket.new('localhost', 8080, 5).timeout).to eq(5) end it "should provide a reasonable to_s" do allow(::Socket).to receive(:new) expect(Thrift::Socket.new('myhost', 8090).to_s).to eq("socket(myhost:8090)") end end end thrift-0.16.0/lib/rb/spec/socket_spec_shared.rb000066400000000000000000000101371420101504100213440ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' shared_examples_for "a socket" do it "should open a socket" do expect(@socket.open).to eq(@handle) end it "should be open whenever it has a handle" do expect(@socket).not_to be_open @socket.open expect(@socket).to be_open @socket.handle = nil expect(@socket).not_to be_open @socket.handle = @handle @socket.close expect(@socket).not_to be_open end it "should write data to the handle" do @socket.open expect(@handle).to receive(:write).with("foobar") @socket.write("foobar") expect(@handle).to receive(:write).with("fail").and_raise(StandardError) expect { @socket.write("fail") }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) } end it "should raise an error when it cannot read from the handle" do @socket.open expect(@handle).to receive(:readpartial).with(17).and_raise(StandardError) expect { @socket.read(17) }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) } end it "should return the data read when reading from the handle works" do @socket.open expect(@handle).to receive(:readpartial).with(17).and_return("test data") expect(@socket.read(17)).to eq("test data") end it "should declare itself as closed when it has an error" do @socket.open expect(@handle).to receive(:write).with("fail").and_raise(StandardError) expect(@socket).to be_open expect { @socket.write("fail") }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) } expect(@socket).not_to be_open end it "should raise an error when the stream is closed" do @socket.open allow(@handle).to receive(:closed?).and_return(true) expect(@socket).not_to be_open expect { @socket.write("fail") }.to raise_error(IOError, "closed stream") expect { @socket.read(10) }.to raise_error(IOError, "closed stream") end it "should support the timeout accessor for read" do @socket.timeout = 3 @socket.open expect(IO).to receive(:select).with([@handle], nil, nil, 3).and_return([[@handle], [], []]) expect(@handle).to receive(:readpartial).with(17).and_return("test data") expect(@socket.read(17)).to eq("test data") end it "should support the timeout accessor for write" do @socket.timeout = 3 @socket.open expect(IO).to receive(:select).with(nil, [@handle], nil, 3).twice.and_return([[], [@handle], []]) expect(@handle).to receive(:write_nonblock).with("test data").and_return(4) expect(@handle).to receive(:write_nonblock).with(" data").and_return(5) expect(@socket.write("test data")).to eq(9) end it "should raise an error when read times out" do @socket.timeout = 0.5 @socket.open expect(IO).to receive(:select).once {sleep(0.5); nil} expect { @socket.read(17) }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::TIMED_OUT) } end it "should raise an error when write times out" do @socket.timeout = 0.5 @socket.open allow(IO).to receive(:select).with(nil, [@handle], nil, 0.5).and_return(nil) expect { @socket.write("test data") }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::TIMED_OUT) } end end thrift-0.16.0/lib/rb/spec/spec_helper.rb000066400000000000000000000042341420101504100200060ustar00rootroot00000000000000# encoding: UTF-8 # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'rubygems' require 'rspec' $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext]) # pretend we already loaded fastthread, otherwise the nonblocking_server_spec # will get screwed up # $" << 'fastthread.bundle' require 'thrift' unless Object.method_defined? :tap # if Object#tap isn't defined, then add it; this should only happen in Ruby < 1.8.7 class Object def tap(&block) block.call(self) self end end end RSpec.configure do |configuration| configuration.before(:each) do Thrift.type_checking = true end end $:.unshift File.join(File.dirname(__FILE__), *%w[.. test debug_proto gen-rb]) require 'srv' require 'debug_proto_test_constants' $:.unshift File.join(File.dirname(__FILE__), *%w[gen-rb]) require 'thrift_spec_types' require 'nonblocking_service' module Fixtures COMPACT_PROTOCOL_TEST_STRUCT = Thrift::Test::COMPACT_TEST.dup COMPACT_PROTOCOL_TEST_STRUCT.a_binary = [0,1,2,3,4,5,6,7,8].pack('c*') COMPACT_PROTOCOL_TEST_STRUCT.set_byte_map = nil COMPACT_PROTOCOL_TEST_STRUCT.map_byte_map = nil end $:.unshift File.join(File.dirname(__FILE__), *%w[gen-rb/flat]) if defined?(GC.verify_compaction_references) == 'method' # This method was added in Ruby 3.0.0. Calling it this way asks the GC to # move objects around, helping to find object movement bugs. GC.verify_compaction_references(double_heap: true, toward: :empty) end thrift-0.16.0/lib/rb/spec/ssl_server_socket_spec.rb000066400000000000000000000021751420101504100222700ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") describe 'SSLServerSocket' do describe Thrift::SSLServerSocket do before(:each) do @socket = Thrift::SSLServerSocket.new(1234) end it "should provide a reasonable to_s" do expect(@socket.to_s).to eq("ssl(socket(:1234))") end end end thrift-0.16.0/lib/rb/spec/ssl_socket_spec.rb000066400000000000000000000064671420101504100207120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") describe 'SSLSocket' do describe Thrift::SSLSocket do before(:each) do @context = OpenSSL::SSL::SSLContext.new @socket = Thrift::SSLSocket.new @simple_socket_handle = double("Handle", :closed? => false) allow(@simple_socket_handle).to receive(:close) allow(@simple_socket_handle).to receive(:connect_nonblock) allow(@simple_socket_handle).to receive(:setsockopt) @handle = double(double("SSLHandle", :connect_nonblock => true, :post_connection_check => true), :closed? => false) allow(@handle).to receive(:connect_nonblock) allow(@handle).to receive(:close) allow(@handle).to receive(:post_connection_check) allow(::Socket).to receive(:new).and_return(@simple_socket_handle) allow(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(@handle) end it_should_behave_like "a socket" it "should raise a TransportException when it cannot open a ssl socket" do expect(::Socket).to receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]]) expect { @socket.open }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) } end it "should open a ::Socket with default args" do expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(@simple_socket_handle, nil).and_return(@handle) expect(@handle).to receive(:post_connection_check).with('localhost') @socket.open end it "should accept host/port options" do handle = double("Handle", :connect_nonblock => true, :setsockopt => nil) allow(::Socket).to receive(:new).and_return(handle) expect(::Socket).to receive(:getaddrinfo).with("my.domain", 1234, nil, ::Socket::SOCK_STREAM).and_return([[]]) expect(::Socket).to receive(:sockaddr_in) expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(handle, nil).and_return(@handle) expect(@handle).to receive(:post_connection_check).with('my.domain') Thrift::SSLSocket.new('my.domain', 1234, 6000, nil).open end it "should accept an optional timeout" do expect(Thrift::SSLSocket.new('localhost', 8080, 5).timeout).to eq(5) end it "should accept an optional context" do expect(Thrift::SSLSocket.new('localhost', 8080, 5, @context).ssl_context).to eq(@context) end it "should provide a reasonable to_s" do expect(Thrift::SSLSocket.new('myhost', 8090).to_s).to eq("ssl(socket(myhost:8090))") end end end thrift-0.16.0/lib/rb/spec/struct_nested_containers_spec.rb000066400000000000000000000144061420101504100236440ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'StructNestedContainers' do def with_type_checking saved_type_checking, Thrift.type_checking = Thrift.type_checking, true begin yield ensure Thrift.type_checking = saved_type_checking end end describe Thrift::Struct do # Nested container tests, see THRIFT-369. it "should support nested lists inside lists" do with_type_checking do a, b = SpecNamespace::NestedListInList.new, SpecNamespace::NestedListInList.new [a, b].each do |thrift_struct| thrift_struct.value = [ [1, 2, 3], [2, 3, 4] ] thrift_struct.validate end expect(a).to eq(b) b.value.push [3, 4, 5] expect(a).not_to eq(b) end end it "should support nested lists inside sets" do with_type_checking do a, b = SpecNamespace::NestedListInSet.new, SpecNamespace::NestedListInSet.new [a, b].each do |thrift_struct| thrift_struct.value = [ [1, 2, 3], [2, 3, 4] ].to_set thrift_struct.validate end expect(a).to eq(b) b.value.add [3, 4, 5] expect(a).not_to eq(b) end end it "should support nested lists in map keys" do with_type_checking do a, b = SpecNamespace::NestedListInMapKey.new, SpecNamespace::NestedListInMapKey.new [a, b].each do |thrift_struct| thrift_struct.value = { [1, 2, 3] => 1, [2, 3, 4] => 2 } thrift_struct.validate end expect(a).to eq(b) b.value[[3, 4, 5]] = 3 expect(a).not_to eq(b) end end it "should support nested lists in map values" do with_type_checking do a, b = SpecNamespace::NestedListInMapValue.new, SpecNamespace::NestedListInMapValue.new [a, b].each do |thrift_struct| thrift_struct.value = { 1 => [1, 2, 3], 2 => [2, 3, 4] } thrift_struct.validate end expect(a).to eq(b) b.value[3] = [3, 4, 5] expect(a).not_to eq(b) end end it "should support nested sets inside lists" do with_type_checking do a, b = SpecNamespace::NestedSetInList.new, SpecNamespace::NestedSetInList.new [a, b].each do |thrift_struct| thrift_struct.value = [ [1, 2, 3].to_set, [2, 3, 4].to_set ] thrift_struct.validate end expect(a).to eq(b) b.value.push([3, 4, 5].to_set) expect(a).not_to eq(b) end end it "should support nested sets inside sets" do with_type_checking do a, b = SpecNamespace::NestedSetInSet.new, SpecNamespace::NestedSetInSet.new [a, b].each do |thrift_struct| thrift_struct.value = [ [1, 2, 3].to_set, [2, 3, 4].to_set ].to_set thrift_struct.validate end expect(a).to eq(b) b.value.add([3, 4, 5].to_set) expect(a).not_to eq(b) end end it "should support nested sets in map keys" do with_type_checking do a, b = SpecNamespace::NestedSetInMapKey.new, SpecNamespace::NestedSetInMapKey.new [a, b].each do |thrift_struct| thrift_struct.value = { [1, 2, 3].to_set => 1, [2, 3, 4].to_set => 2 } thrift_struct.validate end expect(a).to eq(b) b.value[[3, 4, 5].to_set] = 3 expect(a).not_to eq(b) end end it "should support nested sets in map values" do with_type_checking do a, b = SpecNamespace::NestedSetInMapValue.new, SpecNamespace::NestedSetInMapValue.new [a, b].each do |thrift_struct| thrift_struct.value = { 1 => [1, 2, 3].to_set, 2 => [2, 3, 4].to_set } thrift_struct.validate end expect(a).to eq(b) b.value[3] = [3, 4, 5].to_set expect(a).not_to eq(b) end end it "should support nested maps inside lists" do with_type_checking do a, b = SpecNamespace::NestedMapInList.new, SpecNamespace::NestedMapInList.new [a, b].each do |thrift_struct| thrift_struct.value = [ {1 => 2, 3 => 4}, {2 => 3, 4 => 5} ] thrift_struct.validate end expect(a).to eq(b) b.value.push({ 3 => 4, 5 => 6 }) expect(a).not_to eq(b) end end it "should support nested maps inside sets" do with_type_checking do a, b = SpecNamespace::NestedMapInSet.new, SpecNamespace::NestedMapInSet.new [a, b].each do |thrift_struct| thrift_struct.value = [ {1 => 2, 3 => 4}, {2 => 3, 4 => 5} ].to_set thrift_struct.validate end expect(a).to eq(b) b.value.add({ 3 => 4, 5 => 6 }) expect(a).not_to eq(b) end end it "should support nested maps in map keys" do with_type_checking do a, b = SpecNamespace::NestedMapInMapKey.new, SpecNamespace::NestedMapInMapKey.new [a, b].each do |thrift_struct| thrift_struct.value = { { 1 => 2, 3 => 4} => 1, {2 => 3, 4 => 5} => 2 } thrift_struct.validate end expect(a).to eq(b) b.value[{3 => 4, 5 => 6}] = 3 expect(a).not_to eq(b) end end it "should support nested maps in map values" do with_type_checking do a, b = SpecNamespace::NestedMapInMapValue.new, SpecNamespace::NestedMapInMapValue.new [a, b].each do |thrift_struct| thrift_struct.value = { 1 => { 1 => 2, 3 => 4}, 2 => {2 => 3, 4 => 5} } thrift_struct.validate end expect(a).to eq(b) b.value[3] = { 3 => 4, 5 => 6 } expect(a).not_to eq(b) end end end end thrift-0.16.0/lib/rb/spec/struct_spec.rb000066400000000000000000000323461420101504100200600ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Struct' do describe Thrift::Struct do it "should iterate over all fields properly" do fields = {} SpecNamespace::Foo.new.each_field { |fid,field_info| fields[fid] = field_info } expect(fields).to eq(SpecNamespace::Foo::FIELDS) end it "should initialize all fields to defaults" do validate_default_arguments(SpecNamespace::Foo.new) end it "should initialize all fields to defaults and accept a block argument" do SpecNamespace::Foo.new do |f| validate_default_arguments(f) end end def validate_default_arguments(object) expect(object.simple).to eq(53) expect(object.words).to eq("words") expect(object.hello).to eq(SpecNamespace::Hello.new(:greeting => 'hello, world!')) expect(object.ints).to eq([1, 2, 2, 3]) expect(object.complex).to be_nil expect(object.shorts).to eq(Set.new([5, 17, 239])) end it "should not share default values between instances" do begin struct = SpecNamespace::Foo.new struct.ints << 17 expect(SpecNamespace::Foo.new.ints).to eq([1,2,2,3]) ensure # ensure no leakage to other tests SpecNamespace::Foo::FIELDS[4][:default] = [1,2,2,3] end end it "should properly initialize boolean values" do struct = SpecNamespace::BoolStruct.new(:yesno => false) expect(struct.yesno).to be_falsey end it "should have proper == semantics" do expect(SpecNamespace::Foo.new).not_to eq(SpecNamespace::Hello.new) expect(SpecNamespace::Foo.new).to eq(SpecNamespace::Foo.new) expect(SpecNamespace::Foo.new(:simple => 52)).not_to eq(SpecNamespace::Foo.new) end it "should print enum value names in inspect" do expect(SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect).to eq("") expect(SpecNamespace::StructWithEnumMap.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect).to eq("") end it "should pretty print binary fields" do expect(SpecNamespace::Foo2.new(:my_binary => "\001\002\003").inspect).to eq("") end it "should offer field? methods" do expect(SpecNamespace::Foo.new.opt_string?).to be_falsey expect(SpecNamespace::Foo.new(:simple => 52).simple?).to be_truthy expect(SpecNamespace::Foo.new(:my_bool => false).my_bool?).to be_truthy expect(SpecNamespace::Foo.new(:my_bool => true).my_bool?).to be_truthy end it "should be comparable" do s1 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE) s2 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::TWO) expect(s1 <=> s2).to eq(-1) expect(s2 <=> s1).to eq(1) expect(s1 <=> s1).to eq(0) expect(s1 <=> SpecNamespace::StructWithSomeEnum.new()).to eq(-1) end it "should read itself off the wire" do struct = SpecNamespace::Foo.new prot = Thrift::BaseProtocol.new(double("transport")) expect(prot).to receive(:read_struct_begin).twice expect(prot).to receive(:read_struct_end).twice expect(prot).to receive(:read_field_begin).and_return( ['complex', Thrift::Types::MAP, 5], # Foo ['words', Thrift::Types::STRING, 2], # Foo ['hello', Thrift::Types::STRUCT, 3], # Foo ['greeting', Thrift::Types::STRING, 1], # Hello [nil, Thrift::Types::STOP, 0], # Hello ['simple', Thrift::Types::I32, 1], # Foo ['ints', Thrift::Types::LIST, 4], # Foo ['shorts', Thrift::Types::SET, 6], # Foo [nil, Thrift::Types::STOP, 0] # Hello ) expect(prot).to receive(:read_field_end).exactly(7).times expect(prot).to receive(:read_map_begin).and_return( [Thrift::Types::I32, Thrift::Types::MAP, 2], # complex [Thrift::Types::STRING, Thrift::Types::DOUBLE, 2], # complex/1/value [Thrift::Types::STRING, Thrift::Types::DOUBLE, 1] # complex/2/value ) expect(prot).to receive(:read_map_end).exactly(3).times expect(prot).to receive(:read_list_begin).and_return([Thrift::Types::I32, 4]) expect(prot).to receive(:read_list_end) expect(prot).to receive(:read_set_begin).and_return([Thrift::Types::I16, 2]) expect(prot).to receive(:read_set_end) expect(prot).to receive(:read_i32).and_return( 1, 14, # complex keys 42, # simple 4, 23, 4, 29 # ints ) expect(prot).to receive(:read_string).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?") expect(prot).to receive(:read_double).and_return(Math::PI, Math::E, 4.669201609) expect(prot).to receive(:read_i16).and_return(2, 3) expect(prot).not_to receive(:skip) struct.read(prot) expect(struct.simple).to eq(42) expect(struct.complex).to eq({1 => {"pi" => Math::PI, "e" => Math::E}, 14 => {"feigenbaum" => 4.669201609}}) expect(struct.hello).to eq(SpecNamespace::Hello.new(:greeting => "what's up?")) expect(struct.words).to eq("apple banana") expect(struct.ints).to eq([4, 23, 4, 29]) expect(struct.shorts).to eq(Set.new([3, 2])) end it "should serialize false boolean fields correctly" do b = SpecNamespace::BoolStruct.new(:yesno => false) prot = Thrift::BinaryProtocol.new(Thrift::MemoryBufferTransport.new) expect(prot).to receive(:write_bool).with(false) b.write(prot) end it "should skip unexpected fields in structs and use default values" do struct = SpecNamespace::Foo.new prot = Thrift::BaseProtocol.new(double("transport")) expect(prot).to receive(:read_struct_begin) expect(prot).to receive(:read_struct_end) expect(prot).to receive(:read_field_begin).and_return( ['simple', Thrift::Types::I32, 1], ['complex', Thrift::Types::STRUCT, 5], ['thinz', Thrift::Types::MAP, 7], ['foobar', Thrift::Types::I32, 3], ['words', Thrift::Types::STRING, 2], [nil, Thrift::Types::STOP, 0] ) expect(prot).to receive(:read_field_end).exactly(5).times expect(prot).to receive(:read_i32).and_return(42) expect(prot).to receive(:read_string).and_return("foobar") expect(prot).to receive(:skip).with(Thrift::Types::STRUCT) expect(prot).to receive(:skip).with(Thrift::Types::MAP) # prot.should_receive(:read_map_begin).and_return([Thrift::Types::I32, Thrift::Types::I32, 0]) # prot.should_receive(:read_map_end) expect(prot).to receive(:skip).with(Thrift::Types::I32) struct.read(prot) expect(struct.simple).to eq(42) expect(struct.complex).to be_nil expect(struct.words).to eq("foobar") expect(struct.hello).to eq(SpecNamespace::Hello.new(:greeting => 'hello, world!')) expect(struct.ints).to eq([1, 2, 2, 3]) expect(struct.shorts).to eq(Set.new([5, 17, 239])) end it "should write itself to the wire" do prot = Thrift::BaseProtocol.new(double("transport")) #mock("Protocol") expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Foo") expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Hello") expect(prot).to receive(:write_struct_end).twice expect(prot).to receive(:write_field_begin).with('ints', Thrift::Types::LIST, 4) expect(prot).to receive(:write_i32).with(1) expect(prot).to receive(:write_i32).with(2).twice expect(prot).to receive(:write_i32).with(3) expect(prot).to receive(:write_field_begin).with('complex', Thrift::Types::MAP, 5) expect(prot).to receive(:write_i32).with(5) expect(prot).to receive(:write_string).with('foo') expect(prot).to receive(:write_double).with(1.23) expect(prot).to receive(:write_field_begin).with('shorts', Thrift::Types::SET, 6) expect(prot).to receive(:write_i16).with(5) expect(prot).to receive(:write_i16).with(17) expect(prot).to receive(:write_i16).with(239) expect(prot).to receive(:write_field_stop).twice expect(prot).to receive(:write_field_end).exactly(6).times expect(prot).to receive(:write_field_begin).with('simple', Thrift::Types::I32, 1) expect(prot).to receive(:write_i32).with(53) expect(prot).to receive(:write_field_begin).with('hello', Thrift::Types::STRUCT, 3) expect(prot).to receive(:write_field_begin).with('greeting', Thrift::Types::STRING, 1) expect(prot).to receive(:write_string).with('hello, world!') expect(prot).to receive(:write_map_begin).with(Thrift::Types::I32, Thrift::Types::MAP, 1) expect(prot).to receive(:write_map_begin).with(Thrift::Types::STRING, Thrift::Types::DOUBLE, 1) expect(prot).to receive(:write_map_end).twice expect(prot).to receive(:write_list_begin).with(Thrift::Types::I32, 4) expect(prot).to receive(:write_list_end) expect(prot).to receive(:write_set_begin).with(Thrift::Types::I16, 3) expect(prot).to receive(:write_set_end) struct = SpecNamespace::Foo.new struct.words = nil struct.complex = {5 => {"foo" => 1.23}} struct.write(prot) end it "should raise an exception if presented with an unknown container" do # yeah this is silly, but I'm going for code coverage here struct = SpecNamespace::Foo.new expect { struct.send :write_container, nil, nil, {:type => "foo"} }.to raise_error(StandardError, "Not a container type: foo") end it "should support optional type-checking in Thrift::Struct.new" do Thrift.type_checking = true begin expect { SpecNamespace::Hello.new(:greeting => 3) }.to raise_error(Thrift::TypeError, /Expected Types::STRING, received (Integer|Fixnum) for field greeting/) ensure Thrift.type_checking = false end expect { SpecNamespace::Hello.new(:greeting => 3) }.not_to raise_error end it "should support optional type-checking in field accessors" do Thrift.type_checking = true begin hello = SpecNamespace::Hello.new expect { hello.greeting = 3 }.to raise_error(Thrift::TypeError, /Expected Types::STRING, received (Integer|Fixnum) for field greeting/) ensure Thrift.type_checking = false end expect { hello.greeting = 3 }.not_to raise_error end it "should raise an exception when unknown types are given to Thrift::Struct.new" do expect { SpecNamespace::Hello.new(:fish => 'salmon') }.to raise_error(Exception, "Unknown key given to SpecNamespace::Hello.new: fish") end it "should support `raise Xception, 'message'` for Exception structs" do begin raise SpecNamespace::Xception, "something happened" rescue Thrift::Exception => e expect(e.message).to eq("something happened") expect(e.code).to eq(1) # ensure it gets serialized properly, this is the really important part prot = Thrift::BaseProtocol.new(double("trans")) expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Xception") expect(prot).to receive(:write_struct_end) expect(prot).to receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)#, "something happened") expect(prot).to receive(:write_string).with("something happened") expect(prot).to receive(:write_field_begin).with('code', Thrift::Types::I32, 2)#, 1) expect(prot).to receive(:write_i32).with(1) expect(prot).to receive(:write_field_stop) expect(prot).to receive(:write_field_end).twice e.write(prot) end end it "should support the regular initializer for exception structs" do begin raise SpecNamespace::Xception, :message => "something happened", :code => 5 rescue Thrift::Exception => e expect(e.message).to eq("something happened") expect(e.code).to eq(5) prot = Thrift::BaseProtocol.new(double("trans")) expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Xception") expect(prot).to receive(:write_struct_end) expect(prot).to receive(:write_field_begin).with('message', Thrift::Types::STRING, 1) expect(prot).to receive(:write_string).with("something happened") expect(prot).to receive(:write_field_begin).with('code', Thrift::Types::I32, 2) expect(prot).to receive(:write_i32).with(5) expect(prot).to receive(:write_field_stop) expect(prot).to receive(:write_field_end).twice e.write(prot) end end end end thrift-0.16.0/lib/rb/spec/thin_http_server_spec.rb000066400000000000000000000104221420101504100221120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require 'rack/test' require 'thrift/server/thin_http_server' describe Thrift::ThinHTTPServer do let(:processor) { double('processor') } describe "#initialize" do context "when using the defaults" do it "binds to port 80, with host 0.0.0.0, a path of '/'" do expect(Thin::Server).to receive(:new).with('0.0.0.0', 80, an_instance_of(Rack::Builder)) Thrift::ThinHTTPServer.new(processor) end it 'creates a ThinHTTPServer::RackApplicationContext' do expect(Thrift::ThinHTTPServer::RackApplication).to receive(:for).with("/", processor, an_instance_of(Thrift::BinaryProtocolFactory)).and_return(anything) Thrift::ThinHTTPServer.new(processor) end it "uses the BinaryProtocolFactory" do expect(Thrift::BinaryProtocolFactory).to receive(:new) Thrift::ThinHTTPServer.new(processor) end end context "when using the options" do it 'accepts :ip, :port, :path' do ip = "192.168.0.1" port = 3000 path = "/thin" expect(Thin::Server).to receive(:new).with(ip, port, an_instance_of(Rack::Builder)) Thrift::ThinHTTPServer.new(processor, :ip => ip, :port => port, :path => path) end it 'creates a ThinHTTPServer::RackApplicationContext with a different protocol factory' do expect(Thrift::ThinHTTPServer::RackApplication).to receive(:for).with("/", processor, an_instance_of(Thrift::JsonProtocolFactory)).and_return(anything) Thrift::ThinHTTPServer.new(processor, :protocol_factory => Thrift::JsonProtocolFactory.new) end end end describe "#serve" do it 'starts the Thin server' do underlying_thin_server = double('thin server', :start => true) allow(Thin::Server).to receive(:new).and_return(underlying_thin_server) thin_thrift_server = Thrift::ThinHTTPServer.new(processor) expect(underlying_thin_server).to receive(:start) thin_thrift_server.serve end end end describe Thrift::ThinHTTPServer::RackApplication do include Rack::Test::Methods let(:processor) { double('processor') } let(:protocol_factory) { double('protocol factory') } def app Thrift::ThinHTTPServer::RackApplication.for("/", processor, protocol_factory) end context "404 response" do it 'receives a non-POST' do header('Content-Type', "application/x-thrift") get "/" expect(last_response.status).to be 404 end it 'receives a header other than application/x-thrift' do header('Content-Type', "application/json") post "/" expect(last_response.status).to be 404 end end context "200 response" do before do allow(protocol_factory).to receive(:get_protocol) allow(processor).to receive(:process) end it 'creates an IOStreamTransport' do header('Content-Type', "application/x-thrift") expect(Thrift::IOStreamTransport).to receive(:new).with(an_instance_of(Rack::Lint::InputWrapper), an_instance_of(Rack::Response)) post "/" end it 'fetches the right protocol based on the Transport' do header('Content-Type', "application/x-thrift") expect(protocol_factory).to receive(:get_protocol).with(an_instance_of(Thrift::IOStreamTransport)) post "/" end it 'status code 200' do header('Content-Type', "application/x-thrift") post "/" expect(last_response.ok?).to be_truthy end end end thrift-0.16.0/lib/rb/spec/types_spec.rb000066400000000000000000000203301420101504100176660ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe Thrift::Types do before(:each) do Thrift.type_checking = true end after(:each) do Thrift.type_checking = false end context 'type checking' do it "should return the proper name for each type" do expect(Thrift.type_name(Thrift::Types::I16)).to eq("Types::I16") expect(Thrift.type_name(Thrift::Types::VOID)).to eq("Types::VOID") expect(Thrift.type_name(Thrift::Types::LIST)).to eq("Types::LIST") expect(Thrift.type_name(42)).to be_nil end it "should check types properly" do # lambda { Thrift.check_type(nil, Thrift::Types::STOP) }.should raise_error(Thrift::TypeError) expect { Thrift.check_type(3, {:type => Thrift::Types::STOP}, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::VOID}, :foo) }.not_to raise_error expect { Thrift.check_type(3, {:type => Thrift::Types::VOID}, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(true, {:type => Thrift::Types::BOOL}, :foo) }.not_to raise_error expect { Thrift.check_type(3, {:type => Thrift::Types::BOOL}, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(42, {:type => Thrift::Types::BYTE}, :foo) }.not_to raise_error expect { Thrift.check_type(42, {:type => Thrift::Types::I16}, :foo) }.not_to raise_error expect { Thrift.check_type(42, {:type => Thrift::Types::I32}, :foo) }.not_to raise_error expect { Thrift.check_type(42, {:type => Thrift::Types::I64}, :foo) }.not_to raise_error expect { Thrift.check_type(3.14, {:type => Thrift::Types::I32}, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(3.14, {:type => Thrift::Types::DOUBLE}, :foo) }.not_to raise_error expect { Thrift.check_type(3, {:type => Thrift::Types::DOUBLE}, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type("3", {:type => Thrift::Types::STRING}, :foo) }.not_to raise_error expect { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.to raise_error(Thrift::TypeError) hello = SpecNamespace::Hello.new expect { Thrift.check_type(hello, {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}, :foo) }.not_to raise_error expect { Thrift.check_type("foo", {:type => Thrift::Types::STRUCT}, :foo) }.to raise_error(Thrift::TypeError) field = {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRING}} expect { Thrift.check_type({1 => "one"}, field, :foo) }.not_to raise_error expect { Thrift.check_type([1], field, :foo) }.to raise_error(Thrift::TypeError) field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::I32}} expect { Thrift.check_type([1], field, :foo) }.not_to raise_error expect { Thrift.check_type({:foo => 1}, field, :foo) }.to raise_error(Thrift::TypeError) field = {:type => Thrift::Types::SET, :element => {:type => Thrift::Types::I32}} expect { Thrift.check_type(Set.new([1,2]), field, :foo) }.not_to raise_error expect { Thrift.check_type([1,2], field, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type({:foo => true}, field, :foo) }.to raise_error(Thrift::TypeError) end it "should error out if nil is passed and skip_types is false" do expect { Thrift.check_type(nil, {:type => Thrift::Types::BOOL}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::BYTE}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::I16}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::I32}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::I64}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::DOUBLE}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::STRING}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::STRUCT}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::LIST}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::SET}, :foo, false) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(nil, {:type => Thrift::Types::MAP}, :foo, false) }.to raise_error(Thrift::TypeError) end it "should check element types on containers" do field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::I32}} expect { Thrift.check_type([1, 2], field, :foo) }.not_to raise_error expect { Thrift.check_type([1, nil, 2], field, :foo) }.to raise_error(Thrift::TypeError) field = {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRING}} expect { Thrift.check_type({1 => "one", 2 => "two"}, field, :foo) }.not_to raise_error expect { Thrift.check_type({1 => "one", nil => "nil"}, field, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type({1 => nil, 2 => "two"}, field, :foo) }.to raise_error(Thrift::TypeError) field = {:type => Thrift::Types::SET, :element => {:type => Thrift::Types::I32}} expect { Thrift.check_type(Set.new([1, 2]), field, :foo) }.not_to raise_error expect { Thrift.check_type(Set.new([1, nil, 2]), field, :foo) }.to raise_error(Thrift::TypeError) expect { Thrift.check_type(Set.new([1, 2.3, 2]), field, :foo) }.to raise_error(Thrift::TypeError) field = {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello} expect { Thrift.check_type(SpecNamespace::BoolStruct, field, :foo) }.to raise_error(Thrift::TypeError) end it "should give the Thrift::TypeError a readable message" do msg = /Expected Types::STRING, received (Integer|Fixnum) for field foo/ expect { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.to raise_error(Thrift::TypeError, msg) msg = /Expected Types::STRING, received (Integer|Fixnum) for field foo.element/ field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::STRING}} expect { Thrift.check_type([3], field, :foo) }.to raise_error(Thrift::TypeError, msg) msg = "Expected Types::I32, received NilClass for field foo.element.key" field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::I32}}} expect { Thrift.check_type([{nil => 3}], field, :foo) }.to raise_error(Thrift::TypeError, msg) msg = "Expected Types::I32, received NilClass for field foo.element.value" expect { Thrift.check_type([{1 => nil}], field, :foo) }.to raise_error(Thrift::TypeError, msg) end end end thrift-0.16.0/lib/rb/spec/union_spec.rb000066400000000000000000000177761420101504100176760ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' describe 'Union' do describe Thrift::Union do it "should return nil value in unset union" do union = SpecNamespace::My_union.new expect(union.get_set_field).to eq(nil) expect(union.get_value).to eq(nil) end it "should set a field and be accessible through get_value and the named field accessor" do union = SpecNamespace::My_union.new union.integer32 = 25 expect(union.get_set_field).to eq(:integer32) expect(union.get_value).to eq(25) expect(union.integer32).to eq(25) end it "should work correctly when instantiated with static field constructors" do union = SpecNamespace::My_union.integer32(5) expect(union.get_set_field).to eq(:integer32) expect(union.integer32).to eq(5) end it "should raise for wrong set field" do union = SpecNamespace::My_union.new union.integer32 = 25 expect { union.some_characters }.to raise_error(RuntimeError, "some_characters is not union's set field.") end it "should raise for wrong set field when hash initialized and type checking is off" do Thrift.type_checking = false union = SpecNamespace::My_union.new({incorrect_field: :incorrect}) expect { Thrift::Serializer.new.serialize(union) }.to raise_error(RuntimeError, "set_field is not valid for this union!") end it "should not be equal to nil" do union = SpecNamespace::My_union.new expect(union).not_to eq(nil) end it "should not be equal with an empty String" do union = SpecNamespace::My_union.new expect(union).not_to eq('') end it "should not equate two different unions, i32 vs. string" do union = SpecNamespace::My_union.new(:integer32, 25) other_union = SpecNamespace::My_union.new(:some_characters, "blah!") expect(union).not_to eq(other_union) end it "should properly reset setfield and setvalue" do union = SpecNamespace::My_union.new(:integer32, 25) expect(union.get_set_field).to eq(:integer32) union.some_characters = "blah!" expect(union.get_set_field).to eq(:some_characters) expect(union.get_value).to eq("blah!") expect { union.integer32 }.to raise_error(RuntimeError, "integer32 is not union's set field.") end it "should not equate two different unions with different values" do union = SpecNamespace::My_union.new(:integer32, 25) other_union = SpecNamespace::My_union.new(:integer32, 400) expect(union).not_to eq(other_union) end it "should not equate two different unions with different fields" do union = SpecNamespace::My_union.new(:integer32, 25) other_union = SpecNamespace::My_union.new(:other_i32, 25) expect(union).not_to eq(other_union) end it "should inspect properly" do union = SpecNamespace::My_union.new(:integer32, 25) expect(union.inspect).to eq("") end it "should not allow setting with instance_variable_set" do union = SpecNamespace::My_union.new(:integer32, 27) union.instance_variable_set(:@some_characters, "hallo!") expect(union.get_set_field).to eq(:integer32) expect(union.get_value).to eq(27) expect { union.some_characters }.to raise_error(RuntimeError, "some_characters is not union's set field.") end it "should serialize to binary correctly" do trans = Thrift::MemoryBufferTransport.new proto = Thrift::BinaryProtocol.new(trans) union = SpecNamespace::My_union.new(:integer32, 25) union.write(proto) other_union = SpecNamespace::My_union.new(:integer32, 25) other_union.read(proto) expect(other_union).to eq(union) end it "should serialize to json correctly" do trans = Thrift::MemoryBufferTransport.new proto = Thrift::JsonProtocol.new(trans) union = SpecNamespace::My_union.new(:integer32, 25) union.write(proto) other_union = SpecNamespace::My_union.new(:integer32, 25) other_union.read(proto) expect(other_union).to eq(union) end it "should raise when validating unset union" do union = SpecNamespace::My_union.new expect { union.validate }.to raise_error(StandardError, "Union fields are not set.") other_union = SpecNamespace::My_union.new(:integer32, 1) expect { other_union.validate }.not_to raise_error end it "should validate an enum field properly" do union = SpecNamespace::TestUnion.new(:enum_field, 3) expect(union.get_set_field).to eq(:enum_field) expect { union.validate }.to raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!") other_union = SpecNamespace::TestUnion.new(:enum_field, 1) expect { other_union.validate }.not_to raise_error end it "should properly serialize and match structs with a union" do union = SpecNamespace::My_union.new(:integer32, 26) swu = SpecNamespace::Struct_with_union.new(:fun_union => union) trans = Thrift::MemoryBufferTransport.new proto = Thrift::CompactProtocol.new(trans) swu.write(proto) other_union = SpecNamespace::My_union.new(:some_characters, "hello there") swu2 = SpecNamespace::Struct_with_union.new(:fun_union => other_union) expect(swu2).not_to eq(swu) swu2.read(proto) expect(swu2).to eq(swu) end it "should support old style constructor" do union = SpecNamespace::My_union.new(:integer32 => 26) expect(union.get_set_field).to eq(:integer32) expect(union.get_value).to eq(26) end it "should not throw an error when inspected and unset" do expect{SpecNamespace::TestUnion.new().inspect}.not_to raise_error end it "should print enum value name when inspected" do expect(SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect).to eq("") expect(SpecNamespace::My_union.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect).to eq("") end it "should offer field? methods" do expect(SpecNamespace::My_union.new.some_enum?).to be_falsey expect(SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).some_enum?).to be_truthy expect(SpecNamespace::My_union.new(:im_true => false).im_true?).to be_truthy expect(SpecNamespace::My_union.new(:im_true => true).im_true?).to be_truthy end it "should pretty print binary fields" do expect(SpecNamespace::TestUnion.new(:binary_field => "\001\002\003").inspect).to eq("") end it "should be comparable" do relationships = [ [0, -1, -1, -1], [1, 0, -1, -1], [1, 1, 0, -1], [1, 1, 1, 0]] objs = [ SpecNamespace::TestUnion.new(:string_field, "blah"), SpecNamespace::TestUnion.new(:string_field, "blahblah"), SpecNamespace::TestUnion.new(:i32_field, 1), SpecNamespace::TestUnion.new()] for y in 0..3 for x in 0..3 # puts "#{objs[y].inspect} <=> #{objs[x].inspect} should == #{relationships[y][x]}" expect(objs[y] <=> objs[x]).to eq(relationships[y][x]) end end end end end thrift-0.16.0/lib/rb/spec/unix_socket_spec.rb000066400000000000000000000077361420101504100210740ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'spec_helper' require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared") describe 'UNIXSocket' do describe Thrift::UNIXSocket do before(:each) do @path = '/tmp/thrift_spec_socket' @socket = Thrift::UNIXSocket.new(@path) @handle = double("Handle", :closed? => false) allow(@handle).to receive(:close) allow(::UNIXSocket).to receive(:new).and_return(@handle) end it_should_behave_like "a socket" it "should raise a TransportException when it cannot open a socket" do expect(::UNIXSocket).to receive(:new).and_raise(StandardError) expect { @socket.open }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) } end it "should accept an optional timeout" do allow(::UNIXSocket).to receive(:new) expect(Thrift::UNIXSocket.new(@path, 5).timeout).to eq(5) end it "should provide a reasonable to_s" do allow(::UNIXSocket).to receive(:new) expect(Thrift::UNIXSocket.new(@path).to_s).to eq("domain(#{@path})") end end describe Thrift::UNIXServerSocket do before(:each) do @path = '/tmp/thrift_spec_socket' @socket = Thrift::UNIXServerSocket.new(@path) end it "should create a handle when calling listen" do expect(UNIXServer).to receive(:new).with(@path) @socket.listen end it "should create a Thrift::UNIXSocket to wrap accepted sockets" do handle = double("UNIXServer") expect(UNIXServer).to receive(:new).with(@path).and_return(handle) @socket.listen sock = double("sock") expect(handle).to receive(:accept).and_return(sock) trans = double("UNIXSocket") expect(Thrift::UNIXSocket).to receive(:new).and_return(trans) expect(trans).to receive(:handle=).with(sock) expect(@socket.accept).to eq(trans) end it "should close the handle when closed" do handle = double("UNIXServer", :closed? => false) expect(UNIXServer).to receive(:new).with(@path).and_return(handle) @socket.listen expect(handle).to receive(:close) allow(File).to receive(:delete) @socket.close end it "should delete the socket when closed" do handle = double("UNIXServer", :closed? => false) expect(UNIXServer).to receive(:new).with(@path).and_return(handle) @socket.listen allow(handle).to receive(:close) expect(File).to receive(:delete).with(@path) @socket.close end it "should return nil when accepting if there is no handle" do expect(@socket.accept).to be_nil end it "should return true for closed? when appropriate" do handle = double("UNIXServer", :closed? => false) allow(UNIXServer).to receive(:new).and_return(handle) allow(File).to receive(:delete) @socket.listen expect(@socket).not_to be_closed allow(handle).to receive(:close) @socket.close expect(@socket).to be_closed @socket.listen expect(@socket).not_to be_closed allow(handle).to receive(:closed?).and_return(true) expect(@socket).to be_closed end it "should provide a reasonable to_s" do expect(@socket.to_s).to eq("domain(#{@path})") end end end thrift-0.16.0/lib/rb/thrift.gemspec000066400000000000000000000030351420101504100171010ustar00rootroot00000000000000# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) Gem::Specification.new do |s| s.name = 'thrift' s.version = '0.16.0' s.authors = ['Apache Thrift Developers'] s.email = ['dev@thrift.apache.org'] s.homepage = 'http://thrift.apache.org' s.summary = %q{Ruby bindings for Apache Thrift} s.description = %q{Ruby bindings for the Apache Thrift RPC system} s.license = 'Apache-2.0' s.extensions = ['ext/extconf.rb'] s.has_rdoc = true s.rdoc_options = %w[--line-numbers --inline-source --title Thrift --main README] s.rubyforge_project = 'thrift' dir = File.expand_path(File.dirname(__FILE__)) s.files = Dir.glob("{lib,spec}/**/*") s.test_files = Dir.glob("{test,spec,benchmark}/**/*") s.executables = Dir.glob("{bin}/**/*") s.extra_rdoc_files = %w[README.md] + Dir.glob("{ext,lib}/**/*.{c,h,rb}") s.require_paths = %w[lib ext] s.add_development_dependency 'bundler', '>= 1.11' s.add_development_dependency 'pry', '~> 0.11.3' s.add_development_dependency 'pry-byebug', '~> 3.6' s.add_development_dependency 'pry-stack_explorer', '~> 0.4.9.2' s.add_development_dependency 'rack', '= 2.0.8' s.add_development_dependency 'rack-test', '~> 0.8.3' s.add_development_dependency 'rake', '~> 12.3' s.add_development_dependency 'rspec', '~> 3.7' s.add_development_dependency 'srv', '~> 1.0' s.add_development_dependency 'thin', '~> 1.7' end thrift-0.16.0/lib/rs/000077500000000000000000000000001420101504100142545ustar00rootroot00000000000000thrift-0.16.0/lib/rs/Cargo.toml000066400000000000000000000012461420101504100162070ustar00rootroot00000000000000[package] name = "thrift" description = "Rust bindings for the Apache Thrift RPC system" edition = "2018" version = "0.16.0" license = "Apache-2.0" authors = ["Apache Thrift Developers "] homepage = "http://thrift.apache.org" documentation = "https://docs.rs/thrift" repository = "https://github.com/apache/thrift/tree/master/lib/rs" readme = "README.md" exclude = ["Makefile*", "test/**", "*.iml"] keywords = ["thrift"] [dependencies] byteorder = "1.3" integer-encoding = "3.0" log = {version = "0.4", optional = true} ordered-float = "1.0" threadpool = {version = "1.7", optional = true} [features] default = ["server"] server = ["threadpool", "log"] thrift-0.16.0/lib/rs/Makefile.am000066400000000000000000000030721420101504100163120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . if WITH_TESTS SUBDIRS += test SUBDIRS += test_recursive endif install: @echo '##############################################################' @echo '##############################################################' @echo 'The Rust client library should be installed via a Cargo.toml dependency - please see /lib/rs/README.md' @echo '##############################################################' @echo '##############################################################' check-local: $(CARGO) fmt --all -- --check $(CARGO) clippy --all -- -D warnings $(CARGO) test all-local: $(CARGO) fmt --all -- --check $(CARGO) clippy --all -- -D warnings $(CARGO) build clean-local: $(CARGO) clean -$(RM) Cargo.lock EXTRA_DIST = \ src \ Cargo.toml \ README.md \ release.sh \ RELEASING.md thrift-0.16.0/lib/rs/README.md000066400000000000000000000147611420101504100155440ustar00rootroot00000000000000# Rust Thrift library ## Overview This crate implements the components required to build a working Thrift server and client. It is divided into the following modules: 1. errors 2. protocol 3. transport 4. server 5. autogen The modules are layered as shown. The `generated` layer is code generated by the Thrift compiler's Rust plugin. It uses the components defined in this crate to serialize and deserialize types and implement RPC. Users interact with these types and services by writing their own code on top. ```text +-----------+ | app dev | +-----------+ | generated | <-> errors/results +-----------+ | protocol | +-----------+ | transport | +-----------+ ``` ## Using this crate Add `thrift = "x.y.z"` to your `Cargo.toml`, where `x.y.z` is the version of the Thrift compiler you're using. ## API Documentation Full [Rustdoc](https://docs.rs/thrift/) ## Compatibility The Rust library and auto-generated code targets Rust versions 1.28+. It does not currently use any Rust 2018 features. ### Breaking Changes Breaking changes are minimized. When they are made they will be outlined below with transition guidelines. ##### Thrift 0.15.0 * **[THRIFT-5360]** - No longer define OR generate `description()` methods for `Error` types. `Error.description()` was soft-deprecated in 1.27, and deprecated as of 1.41. Library error types also do not implement `Error.description()`. Also, as a result of this change the generated Rust representation of an Error no longer implements the `Error.description()` method. Instead, it generates a `Display` impl with the same information. For example: ```thrift exception Xception { 1: i32 errorCode, 2: string message } ``` used to generate: ```rust use std::error::Error; use std::fmt; use std::fmt::{Display, Formatter}; // auto-generated by the Thrift compiler #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct Xception { pub error_code: Option, pub message: Option, } // auto-generated by the Thrift compiler impl Error for Xception { fn description(&self) -> &str { "remote service threw Xception" } } // auto-generated by the Thrift compiler impl From for thrift::Error { fn from(e: Xception) -> Self { thrift::Error::User(Box::new(e)) } } // auto-generated by the Thrift compiler impl Display for Xception { fn fmt(&self, f: &mut Formatter) -> fmt::Result { self.description().format(f) } } ``` It *now* generates: ```rust use std::error::Error; use std::fmt; use std::fmt::{Display, Formatter}; // auto-generated by the Thrift compiler #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct Xception { pub error_code: Option, pub message: Option, } // auto-generated by the Thrift compiler impl Error for Xception { } // auto-generated by the Thrift compiler impl From for thrift::Error { fn from(e: Xception) -> Self { thrift::Error::User(Box::new(e)) } } // auto-generated by the Thrift compiler impl Display for Xception { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "remote service threw Xception") } } ``` * **[THRIFT-5314]** - Generate enums implementations that are forward compatible (i.e. don't error on unknown values) As a result of this change the Rust representation of an enum changes from a standard Rust enum into a newtype struct with associated constants. For example: ```thrift // THRIFT enum Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE, } ``` used to generate: ```rust // OLD AUTO-GENERATED RUST pub enum Operation { Add, Subtract, Multiply, Divide, } ``` It *now* generates: ```rust // NEW AUTO-GENERATED RUST pub struct Operation(pub i32); impl Operation { pub const ADD: Operation = Operation(0); pub const SUBTRACT: Operation = Operation(1); pub const MULTIPLY: Operation = Operation(2); pub const DIVIDE: Operation = Operation(3); } ``` ##### Thrift 0.14.0 * **[THRIFT-5158]** - Rust library and generator now support Rust 2018 only. Required rust 1.40.0 or higher The Rust `thrift` library was updated to Rust 2018 via `cargo fix --edition`. All test code in the repo was updated as well. The code generator was also updated to support Rust 2018 only. ##### Thrift 0.13.0 * **[THRIFT-4536]** - Use TryFrom from std, required rust 1.34.0 or higher Previously TryFrom was from try_from crate, it is now from the std library, but this functionality is only available in rust 1.34.0. Additionally, ordered-float is now re-exported under the thrift module to reduce possible dependency mismatches. ##### Thrift 0.12.0 * **[THRIFT-4529]** - Rust enum variants are now camel-cased instead of uppercased to conform to Rust naming conventions Previously, enum variants were uppercased in the auto-generated code. For example, the following thrift enum: ```thrift // THRIFT enum Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE, } ``` used to generate: ```rust // OLD AUTO-GENERATED RUST pub enum Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE, } ``` It *now* generates: ```rust // NEW AUTO-GENERATED RUST pub enum Operation { Add, Subtract, Multiply, Divide, } ``` You will have to change all enum variants in your code to use camel-cased names. This should be a search and replace. ## Contributing Bug reports and PRs are always welcome! Please see the [Thrift website](https://thrift.apache.org/) for more details. Thrift Rust support requires code in several directories: * `compiler/cpp/src/thrift/generate/t_rs_generator.cc`: binding code generator * `lib/rs`: runtime library * `lib/rs/test`: supplemental tests * `tutorial/rs`: tutorial client and server * `test/rs`: cross-language test client and server All library code, test code and auto-generated code compiles and passes clippy without warnings. All new code must do the same! When making changes ensure that: * `rustc` does does output any warnings * `clippy` with default settings does not output any warnings (includes auto-generated code) * `cargo test` is successful * `make precross` and `make check` are successful * `tutorial/bin/tutorial_client` and `tutorial/bin/tutorial_server` communicate thrift-0.16.0/lib/rs/RELEASING.md000066400000000000000000000035431420101504100161140ustar00rootroot00000000000000# Publishing the thrift crate Publishing the Rust thrift crate is straightforward, and involves two major steps: 1. Setting up your [crates.io](https://www.crates.io) account _(one-time)_ 2. Packaging/publishing the Rust thrift crate itself ## Set up your crates.io account (one-time) 1. Go to [crates.io](https://www.crates.io) and click the `Log In` button at the top right. Log in **as the Github user with write permissions to the thrift repo!** 2. Click your user icon button at the top right and select `Account Settings`. 3. Click `New Token` next to `API Access`. This generates a new API key that cargo uses to publish packages to crates.io. Store this API key somewhere safe. If you will only use this Github account to publish crates to crates.io you can follow the instructions to save the generated key to `~/.cargo/credentials`. ## Package and Publish You can use the automated script or run the release steps manually. **Important**: `cargo` expects that version numbers follow the semantic versioning format. This means that `THRIFT_RELEASE_VERSION` must have a major, minor and patch number, i.e., must be in the form `#.##.##`. #### Automated Run `./release.sh [THRIFT_RELEASE_VERSION]`. _Requires you to have stored your credentials in `~/.cargo/credentials`._ #### Manual 1. Edit `Cargo.toml` and update the `version = 1.0` key to `version = [THRIFT_RELEASE_VERSION]` 2. `git add Cargo.toml` 3. `git commit -m "Update thrift crate version to [THRIFT_RELEASE_VERSION]" -m "Client: rs"` 4. `cargo login` _(not required if you have stored your credentials in `~/.cargo/credentials`)_ 5. `cargo clean` 6. `cargo package` This step fails if there are any uncommitted or ignored files. Do **not** use the `--allow-dirty` flag! Instead, add the highlighted files as entries in the `Cargo.toml` `exclude` key. 7. `cargo publish` thrift-0.16.0/lib/rs/release.sh000077500000000000000000000013751420101504100162410ustar00rootroot00000000000000#!/bin/bash set -o errexit set -o pipefail set -o nounset if ! [[ $# -eq 1 && $1 =~ ^[0-9](\.[0-9][0-9]*){2}$ ]]; then (>&2 echo "Usage: ./publish-crate.sh [THRIFT_RELEASE_VERSION] ") (>&2 echo " THRIFT_RELEASE_VERSION is in semantic versioning format, i.e. #.##.##") exit 1 fi THRIFT_RELEASE_VERSION=${1:-} echo "Updating Cargo.toml to ${THRIFT_RELEASE_VERSION}" sed -i.old -e "s/^version = .*$/version = \"${THRIFT_RELEASE_VERSION}\"/g" Cargo.toml rm Cargo.toml.old echo "Committing updated Cargo.toml" git add Cargo.toml git commit -m "Update thrift crate version to ${THRIFT_RELEASE_VERSION}" -m "Client: rs" echo "Packaging and releasing rust thrift crate with version ${THRIFT_RELEASE_VERSION}" cargo clean cargo package cargo publish thrift-0.16.0/lib/rs/src/000077500000000000000000000000001420101504100150435ustar00rootroot00000000000000thrift-0.16.0/lib/rs/src/autogen.rs000066400000000000000000000041411420101504100170530ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. //! Thrift compiler auto-generated support. //! //! //! Types and functions used internally by the Thrift compiler's Rust plugin //! to implement required functionality. Users should never have to use code //! in this module directly. use crate::protocol::{TInputProtocol, TOutputProtocol}; /// Specifies the minimum functionality an auto-generated client should provide /// to communicate with a Thrift server. pub trait TThriftClient { /// Returns the input protocol used to read serialized Thrift messages /// from the Thrift server. fn i_prot_mut(&mut self) -> &mut dyn TInputProtocol; /// Returns the output protocol used to write serialized Thrift messages /// to the Thrift server. fn o_prot_mut(&mut self) -> &mut dyn TOutputProtocol; /// Returns the sequence number of the last message written to the Thrift /// server. Returns `0` if no messages have been written. Sequence /// numbers should *never* be negative, and this method returns an `i32` /// simply because the Thrift protocol encodes sequence numbers as `i32` on /// the wire. fn sequence_number(&self) -> i32; // FIXME: consider returning a u32 /// Increments the sequence number, indicating that a message with that /// number has been sent to the Thrift server. fn increment_sequence_number(&mut self) -> i32; } thrift-0.16.0/lib/rs/src/errors.rs000066400000000000000000000525211420101504100167320ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::convert::TryFrom; use std::convert::{From, Into}; use std::fmt::{Debug, Display, Formatter}; use std::{error, fmt, io, string}; use crate::protocol::{ TFieldIdentifier, TInputProtocol, TOutputProtocol, TStructIdentifier, TType, }; // FIXME: should all my error structs impl error::Error as well? // FIXME: should all fields in TransportError, ProtocolError and ApplicationError be optional? /// Error type returned by all runtime library functions. /// /// `thrift::Error` is used throughout this crate as well as in auto-generated /// Rust code. It consists of four variants defined by convention across Thrift /// implementations: /// /// 1. `Transport`: errors encountered while operating on I/O channels /// 2. `Protocol`: errors encountered during runtime-library processing /// 3. `Application`: errors encountered within auto-generated code /// 4. `User`: IDL-defined exception structs /// /// The `Application` variant also functions as a catch-all: all handler errors /// are automatically turned into application errors. /// /// All error variants except `Error::User` take an eponymous struct with two /// required fields: /// /// 1. `kind`: variant-specific enum identifying the error sub-type /// 2. `message`: human-readable error info string /// /// `kind` is defined by convention while `message` is freeform. If none of the /// enumerated kinds are suitable use `Unknown`. /// /// To simplify error creation convenience constructors are defined for all /// variants, and conversions from their structs (`thrift::TransportError`, /// `thrift::ProtocolError` and `thrift::ApplicationError` into `thrift::Error`. /// /// # Examples /// /// Create a `TransportError`. /// /// ``` /// use thrift::{TransportError, TransportErrorKind}; /// /// // explicit /// let err0: thrift::Result<()> = Err( /// thrift::Error::Transport( /// TransportError { /// kind: TransportErrorKind::TimedOut, /// message: format!("connection to server timed out") /// } /// ) /// ); /// /// // use conversion /// let err1: thrift::Result<()> = Err( /// thrift::Error::from( /// TransportError { /// kind: TransportErrorKind::TimedOut, /// message: format!("connection to server timed out") /// } /// ) /// ); /// /// // use struct constructor /// let err2: thrift::Result<()> = Err( /// thrift::Error::Transport( /// TransportError::new( /// TransportErrorKind::TimedOut, /// "connection to server timed out" /// ) /// ) /// ); /// /// /// // use error variant constructor /// let err3: thrift::Result<()> = Err( /// thrift::new_transport_error( /// TransportErrorKind::TimedOut, /// "connection to server timed out" /// ) /// ); /// ``` /// /// Create an error from a string. /// /// ``` /// use thrift::{ApplicationError, ApplicationErrorKind}; /// /// // we just use `From::from` to convert a `String` into a `thrift::Error` /// let err0: thrift::Result<()> = Err( /// thrift::Error::from("This is an error") /// ); /// /// // err0 is equivalent to... /// let err1: thrift::Result<()> = Err( /// thrift::Error::Application( /// ApplicationError { /// kind: ApplicationErrorKind::Unknown, /// message: format!("This is an error") /// } /// ) /// ); /// ``` /// /// Return an IDL-defined exception. /// /// ```text /// // Thrift IDL exception definition. /// exception Xception { /// 1: i32 errorCode, /// 2: string message /// } /// ``` /// /// ``` /// use std::error::Error; /// use std::fmt; /// use std::fmt::{Display, Formatter}; /// /// // auto-generated by the Thrift compiler /// #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] /// pub struct Xception { /// pub error_code: Option, /// pub message: Option, /// } /// /// // auto-generated by the Thrift compiler /// impl Error for Xception { } /// /// // auto-generated by the Thrift compiler /// impl From for thrift::Error { /// fn from(e: Xception) -> Self { /// thrift::Error::User(Box::new(e)) /// } /// } /// /// // auto-generated by the Thrift compiler /// impl Display for Xception { /// fn fmt(&self, f: &mut Formatter) -> fmt::Result { /// write!(f, "remote service threw Xception") /// } /// } /// /// // in user code... /// let err: thrift::Result<()> = Err( /// thrift::Error::from(Xception { error_code: Some(1), message: None }) /// ); /// ``` pub enum Error { /// Errors encountered while operating on I/O channels. /// /// These include *connection closed* and *bind failure*. Transport(TransportError), /// Errors encountered during runtime-library processing. /// /// These include *message too large* and *unsupported protocol version*. Protocol(ProtocolError), /// Errors encountered within auto-generated code, or when incoming /// or outgoing messages violate the Thrift spec. /// /// These include *out-of-order messages* and *missing required struct /// fields*. /// /// This variant also functions as a catch-all: errors from handler /// functions are automatically returned as an `ApplicationError`. Application(ApplicationError), /// IDL-defined exception structs. User(Box), } impl Error { /// Create an `ApplicationError` from its wire representation. /// /// Application code **should never** call this method directly. pub fn read_application_error_from_in_protocol( i: &mut dyn TInputProtocol, ) -> crate::Result { let mut message = "general remote error".to_owned(); let mut kind = ApplicationErrorKind::Unknown; i.read_struct_begin()?; loop { let field_ident = i.read_field_begin()?; if field_ident.field_type == TType::Stop { break; } let id = field_ident .id .expect("sender should always specify id for non-STOP field"); match id { 1 => { let remote_message = i.read_string()?; i.read_field_end()?; message = remote_message; } 2 => { let remote_type_as_int = i.read_i32()?; let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int) .unwrap_or(ApplicationErrorKind::Unknown); i.read_field_end()?; kind = remote_kind; } _ => { i.skip(field_ident.field_type)?; } } } i.read_struct_end()?; Ok(ApplicationError { kind, message }) } /// Convert an `ApplicationError` into its wire representation and write /// it to the remote. /// /// Application code **should never** call this method directly. pub fn write_application_error_to_out_protocol( e: &ApplicationError, o: &mut dyn TOutputProtocol, ) -> crate::Result<()> { o.write_struct_begin(&TStructIdentifier { name: "TApplicationException".to_owned(), })?; let message_field = TFieldIdentifier::new("message", TType::String, 1); let type_field = TFieldIdentifier::new("type", TType::I32, 2); o.write_field_begin(&message_field)?; o.write_string(&e.message)?; o.write_field_end()?; o.write_field_begin(&type_field)?; o.write_i32(e.kind as i32)?; o.write_field_end()?; o.write_field_stop()?; o.write_struct_end()?; o.flush() } } impl error::Error for Error {} impl Debug for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match *self { Error::Transport(ref e) => Debug::fmt(e, f), Error::Protocol(ref e) => Debug::fmt(e, f), Error::Application(ref e) => Debug::fmt(e, f), Error::User(ref e) => Debug::fmt(e, f), } } } impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match *self { Error::Transport(ref e) => Display::fmt(e, f), Error::Protocol(ref e) => Display::fmt(e, f), Error::Application(ref e) => Display::fmt(e, f), Error::User(ref e) => Display::fmt(e, f), } } } impl From for Error { fn from(s: String) -> Self { Error::Application(ApplicationError { kind: ApplicationErrorKind::Unknown, message: s, }) } } impl<'a> From<&'a str> for Error { fn from(s: &'a str) -> Self { Error::Application(ApplicationError { kind: ApplicationErrorKind::Unknown, message: String::from(s), }) } } impl From for Error { fn from(e: TransportError) -> Self { Error::Transport(e) } } impl From for Error { fn from(e: ProtocolError) -> Self { Error::Protocol(e) } } impl From for Error { fn from(e: ApplicationError) -> Self { Error::Application(e) } } /// Create a new `Error` instance of type `Transport` that wraps a /// `TransportError`. pub fn new_transport_error>(kind: TransportErrorKind, message: S) -> Error { Error::Transport(TransportError::new(kind, message)) } /// Information about I/O errors. #[derive(Debug, Eq, PartialEq)] pub struct TransportError { /// I/O error variant. /// /// If a specific `TransportErrorKind` does not apply use /// `TransportErrorKind::Unknown`. pub kind: TransportErrorKind, /// Human-readable error message. pub message: String, } impl TransportError { /// Create a new `TransportError`. pub fn new>(kind: TransportErrorKind, message: S) -> TransportError { TransportError { kind, message: message.into(), } } } /// I/O error categories. /// /// This list may grow, and it is not recommended to match against it. #[non_exhaustive] #[derive(Clone, Copy, Eq, Debug, PartialEq)] pub enum TransportErrorKind { /// Catch-all I/O error. Unknown = 0, /// An I/O operation was attempted when the transport channel was not open. NotOpen = 1, /// The transport channel cannot be opened because it was opened previously. AlreadyOpen = 2, /// An I/O operation timed out. TimedOut = 3, /// A read could not complete because no bytes were available. EndOfFile = 4, /// An invalid (buffer/message) size was requested or received. NegativeSize = 5, /// Too large a buffer or message size was requested or received. SizeLimit = 6, } impl Display for TransportError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let error_text = match self.kind { TransportErrorKind::Unknown => "transport error", TransportErrorKind::NotOpen => "not open", TransportErrorKind::AlreadyOpen => "already open", TransportErrorKind::TimedOut => "timed out", TransportErrorKind::EndOfFile => "end of file", TransportErrorKind::NegativeSize => "negative size message", TransportErrorKind::SizeLimit => "message too long", }; write!(f, "{}", error_text) } } impl TryFrom for TransportErrorKind { type Error = Error; fn try_from(from: i32) -> Result { match from { 0 => Ok(TransportErrorKind::Unknown), 1 => Ok(TransportErrorKind::NotOpen), 2 => Ok(TransportErrorKind::AlreadyOpen), 3 => Ok(TransportErrorKind::TimedOut), 4 => Ok(TransportErrorKind::EndOfFile), 5 => Ok(TransportErrorKind::NegativeSize), 6 => Ok(TransportErrorKind::SizeLimit), _ => Err(Error::Protocol(ProtocolError { kind: ProtocolErrorKind::Unknown, message: format!("cannot convert {} to TransportErrorKind", from), })), } } } impl From for Error { fn from(err: io::Error) -> Self { match err.kind() { io::ErrorKind::ConnectionReset | io::ErrorKind::ConnectionRefused | io::ErrorKind::NotConnected => Error::Transport(TransportError { kind: TransportErrorKind::NotOpen, message: err.to_string(), }), io::ErrorKind::AlreadyExists => Error::Transport(TransportError { kind: TransportErrorKind::AlreadyOpen, message: err.to_string(), }), io::ErrorKind::TimedOut => Error::Transport(TransportError { kind: TransportErrorKind::TimedOut, message: err.to_string(), }), io::ErrorKind::UnexpectedEof => Error::Transport(TransportError { kind: TransportErrorKind::EndOfFile, message: err.to_string(), }), _ => { Error::Transport(TransportError { kind: TransportErrorKind::Unknown, message: err.to_string(), // FIXME: use io error's debug string }) } } } } impl From for Error { fn from(err: string::FromUtf8Error) -> Self { Error::Protocol(ProtocolError { kind: ProtocolErrorKind::InvalidData, message: err.to_string(), // FIXME: use fmt::Error's debug string }) } } /// Create a new `Error` instance of type `Protocol` that wraps a /// `ProtocolError`. pub fn new_protocol_error>(kind: ProtocolErrorKind, message: S) -> Error { Error::Protocol(ProtocolError::new(kind, message)) } /// Information about errors that occur in the runtime library. #[derive(Debug, Eq, PartialEq)] pub struct ProtocolError { /// Protocol error variant. /// /// If a specific `ProtocolErrorKind` does not apply use /// `ProtocolErrorKind::Unknown`. pub kind: ProtocolErrorKind, /// Human-readable error message. pub message: String, } impl ProtocolError { /// Create a new `ProtocolError`. pub fn new>(kind: ProtocolErrorKind, message: S) -> ProtocolError { ProtocolError { kind, message: message.into(), } } } /// Runtime library error categories. /// /// This list may grow, and it is not recommended to match against it. #[non_exhaustive] #[derive(Clone, Copy, Eq, Debug, PartialEq)] pub enum ProtocolErrorKind { /// Catch-all runtime-library error. Unknown = 0, /// An invalid argument was supplied to a library function, or invalid data /// was received from a Thrift endpoint. InvalidData = 1, /// An invalid size was received in an encoded field. NegativeSize = 2, /// Thrift message or field was too long. SizeLimit = 3, /// Unsupported or unknown Thrift protocol version. BadVersion = 4, /// Unsupported Thrift protocol, server or field type. NotImplemented = 5, /// Reached the maximum nested depth to which an encoded Thrift field could /// be skipped. DepthLimit = 6, } impl Display for ProtocolError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let error_text = match self.kind { ProtocolErrorKind::Unknown => "protocol error", ProtocolErrorKind::InvalidData => "bad data", ProtocolErrorKind::NegativeSize => "negative message size", ProtocolErrorKind::SizeLimit => "message too long", ProtocolErrorKind::BadVersion => "invalid thrift version", ProtocolErrorKind::NotImplemented => "not implemented", ProtocolErrorKind::DepthLimit => "maximum skip depth reached", }; write!(f, "{}", error_text) } } impl TryFrom for ProtocolErrorKind { type Error = Error; fn try_from(from: i32) -> Result { match from { 0 => Ok(ProtocolErrorKind::Unknown), 1 => Ok(ProtocolErrorKind::InvalidData), 2 => Ok(ProtocolErrorKind::NegativeSize), 3 => Ok(ProtocolErrorKind::SizeLimit), 4 => Ok(ProtocolErrorKind::BadVersion), 5 => Ok(ProtocolErrorKind::NotImplemented), 6 => Ok(ProtocolErrorKind::DepthLimit), _ => Err(Error::Protocol(ProtocolError { kind: ProtocolErrorKind::Unknown, message: format!("cannot convert {} to ProtocolErrorKind", from), })), } } } /// Create a new `Error` instance of type `Application` that wraps an /// `ApplicationError`. pub fn new_application_error>(kind: ApplicationErrorKind, message: S) -> Error { Error::Application(ApplicationError::new(kind, message)) } /// Information about errors in auto-generated code or in user-implemented /// service handlers. #[derive(Debug, Eq, PartialEq)] pub struct ApplicationError { /// Application error variant. /// /// If a specific `ApplicationErrorKind` does not apply use /// `ApplicationErrorKind::Unknown`. pub kind: ApplicationErrorKind, /// Human-readable error message. pub message: String, } impl ApplicationError { /// Create a new `ApplicationError`. pub fn new>(kind: ApplicationErrorKind, message: S) -> ApplicationError { ApplicationError { kind, message: message.into(), } } } /// Auto-generated or user-implemented code error categories. /// /// This list may grow, and it is not recommended to match against it. #[non_exhaustive] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ApplicationErrorKind { /// Catch-all application error. Unknown = 0, /// Made service call to an unknown service method. UnknownMethod = 1, /// Received an unknown Thrift message type. That is, not one of the /// `thrift::protocol::TMessageType` variants. InvalidMessageType = 2, /// Method name in a service reply does not match the name of the /// receiving service method. WrongMethodName = 3, /// Received an out-of-order Thrift message. BadSequenceId = 4, /// Service reply is missing required fields. MissingResult = 5, /// Auto-generated code failed unexpectedly. InternalError = 6, /// Thrift protocol error. When possible use `Error::ProtocolError` with a /// specific `ProtocolErrorKind` instead. ProtocolError = 7, /// *Unknown*. Included only for compatibility with existing Thrift implementations. InvalidTransform = 8, // ?? /// Thrift endpoint requested, or is using, an unsupported encoding. InvalidProtocol = 9, // ?? /// Thrift endpoint requested, or is using, an unsupported auto-generated client type. UnsupportedClientType = 10, // ?? } impl Display for ApplicationError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let error_text = match self.kind { ApplicationErrorKind::Unknown => "service error", ApplicationErrorKind::UnknownMethod => "unknown service method", ApplicationErrorKind::InvalidMessageType => "wrong message type received", ApplicationErrorKind::WrongMethodName => "unknown method reply received", ApplicationErrorKind::BadSequenceId => "out of order sequence id", ApplicationErrorKind::MissingResult => "missing method result", ApplicationErrorKind::InternalError => "remote service threw exception", ApplicationErrorKind::ProtocolError => "protocol error", ApplicationErrorKind::InvalidTransform => "invalid transform", ApplicationErrorKind::InvalidProtocol => "invalid protocol requested", ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client", }; write!(f, "{}", error_text) } } impl TryFrom for ApplicationErrorKind { type Error = Error; fn try_from(from: i32) -> Result { match from { 0 => Ok(ApplicationErrorKind::Unknown), 1 => Ok(ApplicationErrorKind::UnknownMethod), 2 => Ok(ApplicationErrorKind::InvalidMessageType), 3 => Ok(ApplicationErrorKind::WrongMethodName), 4 => Ok(ApplicationErrorKind::BadSequenceId), 5 => Ok(ApplicationErrorKind::MissingResult), 6 => Ok(ApplicationErrorKind::InternalError), 7 => Ok(ApplicationErrorKind::ProtocolError), 8 => Ok(ApplicationErrorKind::InvalidTransform), 9 => Ok(ApplicationErrorKind::InvalidProtocol), 10 => Ok(ApplicationErrorKind::UnsupportedClientType), _ => Err(Error::Application(ApplicationError { kind: ApplicationErrorKind::Unknown, message: format!("cannot convert {} to ApplicationErrorKind", from), })), } } } thrift-0.16.0/lib/rs/src/lib.rs000066400000000000000000000056411420101504100161650ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. //! Rust runtime library for the Apache Thrift RPC system. //! //! This crate implements the components required to build a working //! Thrift server and client. It is divided into the following modules: //! //! 1. errors //! 2. protocol //! 3. transport //! 4. server //! 5. autogen //! //! The modules are layered as shown in the diagram below. The `autogen'd` //! layer is generated by the Thrift compiler's Rust plugin. It uses the //! types and functions defined in this crate to serialize and deserialize //! messages and implement RPC. Users interact with these types and services //! by writing their own code that uses the auto-generated clients and //! servers. //! //! ```text //! +-----------+ //! | user app | //! +-----------+ //! | autogen'd | (uses errors, autogen) //! +-----------+ //! | protocol | //! +-----------+ //! | transport | //! +-----------+ //! ``` //! //! # Tutorial //! //! For an example of how to setup a simple client and server using this crate //! see the [tutorial]. //! //! [tutorial]: https://github.com/apache/thrift/tree/master/tutorial/rs #![crate_type = "lib"] #![doc(test(attr(allow(unused_variables), deny(warnings))))] #![deny(bare_trait_objects)] // NOTE: this macro has to be defined before any modules. See: // https://danielkeep.github.io/quick-intro-to-macros.html#some-more-gotchas /// Assert that an expression returning a `Result` is a success. If it is, /// return the value contained in the result, i.e. `expr.unwrap()`. #[cfg(test)] macro_rules! assert_success { ($e: expr) => {{ let res = $e; assert!(res.is_ok()); res.unwrap() }}; } pub mod protocol; #[cfg(feature = "server")] pub mod server; pub mod transport; mod errors; pub use crate::errors::*; mod autogen; pub use crate::autogen::*; /// Result type returned by all runtime library functions. /// /// As is convention this is a typedef of `std::result::Result` /// with `E` defined as the `thrift::Error` type. pub type Result = std::result::Result; // Re-export ordered-float, since it is used by the generator // FIXME: check the guidance around type reexports pub use ordered_float::OrderedFloat; thrift-0.16.0/lib/rs/src/protocol/000077500000000000000000000000001420101504100167045ustar00rootroot00000000000000thrift-0.16.0/lib/rs/src/protocol/binary.rs000066400000000000000000000675131420101504100205520ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; use std::convert::{From, TryFrom}; use super::{ TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, }; use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType}; use crate::transport::{TReadTransport, TWriteTransport}; use crate::{ProtocolError, ProtocolErrorKind}; const BINARY_PROTOCOL_VERSION_1: u32 = 0x8001_0000; /// Read messages encoded in the Thrift simple binary encoding. /// /// There are two available modes: `strict` and `non-strict`, where the /// `non-strict` version does not check for the protocol version in the /// received message header. /// /// # Examples /// /// Create and use a `TBinaryInputProtocol`. /// /// ```no_run /// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("localhost:9090").unwrap(); /// /// let mut protocol = TBinaryInputProtocol::new(channel, true); /// /// let recvd_bool = protocol.read_bool().unwrap(); /// let recvd_string = protocol.read_string().unwrap(); /// ``` #[derive(Debug)] pub struct TBinaryInputProtocol where T: TReadTransport, { strict: bool, pub transport: T, // FIXME: shouldn't be public } impl<'a, T> TBinaryInputProtocol where T: TReadTransport, { /// Create a `TBinaryInputProtocol` that reads bytes from `transport`. /// /// Set `strict` to `true` if all incoming messages contain the protocol /// version number in the protocol header. pub fn new(transport: T, strict: bool) -> TBinaryInputProtocol { TBinaryInputProtocol { strict, transport } } } impl TInputProtocol for TBinaryInputProtocol where T: TReadTransport, { #[allow(clippy::collapsible_if)] fn read_message_begin(&mut self) -> crate::Result { let mut first_bytes = vec![0; 4]; self.transport.read_exact(&mut first_bytes[..])?; // the thrift version header is intentionally negative // so the first check we'll do is see if the sign bit is set // and if so - assume it's the protocol-version header if first_bytes[0] >= 8 { // apparently we got a protocol-version header - check // it, and if it matches, read the rest of the fields if first_bytes[0..2] != [0x80, 0x01] { Err(crate::Error::Protocol(ProtocolError { kind: ProtocolErrorKind::BadVersion, message: format!("received bad version: {:?}", &first_bytes[0..2]), })) } else { let message_type: TMessageType = TryFrom::try_from(first_bytes[3])?; let name = self.read_string()?; let sequence_number = self.read_i32()?; Ok(TMessageIdentifier::new(name, message_type, sequence_number)) } } else { // apparently we didn't get a protocol-version header, // which happens if the sender is not using the strict protocol if self.strict { // we're in strict mode however, and that always // requires the protocol-version header to be written first Err(crate::Error::Protocol(ProtocolError { kind: ProtocolErrorKind::BadVersion, message: format!("received bad version: {:?}", &first_bytes[0..2]), })) } else { // in the non-strict version the first message field // is the message name. strings (byte arrays) are length-prefixed, // so we've just read the length in the first 4 bytes let name_size = BigEndian::read_i32(&first_bytes) as usize; let mut name_buf: Vec = vec![0; name_size]; self.transport.read_exact(&mut name_buf)?; let name = String::from_utf8(name_buf)?; // read the rest of the fields let message_type: TMessageType = self.read_byte().and_then(TryFrom::try_from)?; let sequence_number = self.read_i32()?; Ok(TMessageIdentifier::new(name, message_type, sequence_number)) } } } fn read_message_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_struct_begin(&mut self) -> crate::Result> { Ok(None) } fn read_struct_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_field_begin(&mut self) -> crate::Result { let field_type_byte = self.read_byte()?; let field_type = field_type_from_u8(field_type_byte)?; let id = match field_type { TType::Stop => Ok(0), _ => self.read_i16(), }?; Ok(TFieldIdentifier::new::, String, i16>( None, field_type, id, )) } fn read_field_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_bytes(&mut self) -> crate::Result> { let num_bytes = self.transport.read_i32::()? as usize; let mut buf = vec![0u8; num_bytes]; self.transport .read_exact(&mut buf) .map(|_| buf) .map_err(From::from) } fn read_bool(&mut self) -> crate::Result { let b = self.read_i8()?; match b { 0 => Ok(false), _ => Ok(true), } } fn read_i8(&mut self) -> crate::Result { self.transport.read_i8().map_err(From::from) } fn read_i16(&mut self) -> crate::Result { self.transport.read_i16::().map_err(From::from) } fn read_i32(&mut self) -> crate::Result { self.transport.read_i32::().map_err(From::from) } fn read_i64(&mut self) -> crate::Result { self.transport.read_i64::().map_err(From::from) } fn read_double(&mut self) -> crate::Result { self.transport.read_f64::().map_err(From::from) } fn read_string(&mut self) -> crate::Result { let bytes = self.read_bytes()?; String::from_utf8(bytes).map_err(From::from) } fn read_list_begin(&mut self) -> crate::Result { let element_type: TType = self.read_byte().and_then(field_type_from_u8)?; let size = self.read_i32()?; Ok(TListIdentifier::new(element_type, size)) } fn read_list_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_set_begin(&mut self) -> crate::Result { let element_type: TType = self.read_byte().and_then(field_type_from_u8)?; let size = self.read_i32()?; Ok(TSetIdentifier::new(element_type, size)) } fn read_set_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_map_begin(&mut self) -> crate::Result { let key_type: TType = self.read_byte().and_then(field_type_from_u8)?; let value_type: TType = self.read_byte().and_then(field_type_from_u8)?; let size = self.read_i32()?; Ok(TMapIdentifier::new(key_type, value_type, size)) } fn read_map_end(&mut self) -> crate::Result<()> { Ok(()) } // utility // fn read_byte(&mut self) -> crate::Result { self.transport.read_u8().map_err(From::from) } } /// Factory for creating instances of `TBinaryInputProtocol`. #[derive(Default)] pub struct TBinaryInputProtocolFactory; impl TBinaryInputProtocolFactory { /// Create a `TBinaryInputProtocolFactory`. pub fn new() -> TBinaryInputProtocolFactory { TBinaryInputProtocolFactory {} } } impl TInputProtocolFactory for TBinaryInputProtocolFactory { fn create(&self, transport: Box) -> Box { Box::new(TBinaryInputProtocol::new(transport, true)) } } /// Write messages using the Thrift simple binary encoding. /// /// There are two available modes: `strict` and `non-strict`, where the /// `strict` version writes the protocol version number in the outgoing message /// header and the `non-strict` version does not. /// /// # Examples /// /// Create and use a `TBinaryOutputProtocol`. /// /// ```no_run /// use thrift::protocol::{TBinaryOutputProtocol, TOutputProtocol}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("localhost:9090").unwrap(); /// /// let mut protocol = TBinaryOutputProtocol::new(channel, true); /// /// protocol.write_bool(true).unwrap(); /// protocol.write_string("test_string").unwrap(); /// ``` #[derive(Debug)] pub struct TBinaryOutputProtocol where T: TWriteTransport, { strict: bool, pub transport: T, // FIXME: do not make public; only public for testing! } impl TBinaryOutputProtocol where T: TWriteTransport, { /// Create a `TBinaryOutputProtocol` that writes bytes to `transport`. /// /// Set `strict` to `true` if all outgoing messages should contain the /// protocol version number in the protocol header. pub fn new(transport: T, strict: bool) -> TBinaryOutputProtocol { TBinaryOutputProtocol { strict, transport } } } impl TOutputProtocol for TBinaryOutputProtocol where T: TWriteTransport, { fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> crate::Result<()> { if self.strict { let message_type: u8 = identifier.message_type.into(); let header = BINARY_PROTOCOL_VERSION_1 | (message_type as u32); self.transport.write_u32::(header)?; self.write_string(&identifier.name)?; self.write_i32(identifier.sequence_number) } else { self.write_string(&identifier.name)?; self.write_byte(identifier.message_type.into())?; self.write_i32(identifier.sequence_number) } } fn write_message_end(&mut self) -> crate::Result<()> { Ok(()) } fn write_struct_begin(&mut self, _: &TStructIdentifier) -> crate::Result<()> { Ok(()) } fn write_struct_end(&mut self) -> crate::Result<()> { Ok(()) } fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> crate::Result<()> { if identifier.id.is_none() && identifier.field_type != TType::Stop { return Err(crate::Error::Protocol(ProtocolError { kind: ProtocolErrorKind::Unknown, message: format!( "cannot write identifier {:?} without sequence number", &identifier ), })); } self.write_byte(field_type_to_u8(identifier.field_type))?; if let Some(id) = identifier.id { self.write_i16(id) } else { Ok(()) } } fn write_field_end(&mut self) -> crate::Result<()> { Ok(()) } fn write_field_stop(&mut self) -> crate::Result<()> { self.write_byte(field_type_to_u8(TType::Stop)) } fn write_bytes(&mut self, b: &[u8]) -> crate::Result<()> { self.write_i32(b.len() as i32)?; self.transport.write_all(b).map_err(From::from) } fn write_bool(&mut self, b: bool) -> crate::Result<()> { if b { self.write_i8(1) } else { self.write_i8(0) } } fn write_i8(&mut self, i: i8) -> crate::Result<()> { self.transport.write_i8(i).map_err(From::from) } fn write_i16(&mut self, i: i16) -> crate::Result<()> { self.transport.write_i16::(i).map_err(From::from) } fn write_i32(&mut self, i: i32) -> crate::Result<()> { self.transport.write_i32::(i).map_err(From::from) } fn write_i64(&mut self, i: i64) -> crate::Result<()> { self.transport.write_i64::(i).map_err(From::from) } fn write_double(&mut self, d: f64) -> crate::Result<()> { self.transport.write_f64::(d).map_err(From::from) } fn write_string(&mut self, s: &str) -> crate::Result<()> { self.write_bytes(s.as_bytes()) } fn write_list_begin(&mut self, identifier: &TListIdentifier) -> crate::Result<()> { self.write_byte(field_type_to_u8(identifier.element_type))?; self.write_i32(identifier.size) } fn write_list_end(&mut self) -> crate::Result<()> { Ok(()) } fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> crate::Result<()> { self.write_byte(field_type_to_u8(identifier.element_type))?; self.write_i32(identifier.size) } fn write_set_end(&mut self) -> crate::Result<()> { Ok(()) } fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> crate::Result<()> { let key_type = identifier .key_type .expect("map identifier to write should contain key type"); self.write_byte(field_type_to_u8(key_type))?; let val_type = identifier .value_type .expect("map identifier to write should contain value type"); self.write_byte(field_type_to_u8(val_type))?; self.write_i32(identifier.size) } fn write_map_end(&mut self) -> crate::Result<()> { Ok(()) } fn flush(&mut self) -> crate::Result<()> { self.transport.flush().map_err(From::from) } // utility // fn write_byte(&mut self, b: u8) -> crate::Result<()> { self.transport.write_u8(b).map_err(From::from) } } /// Factory for creating instances of `TBinaryOutputProtocol`. #[derive(Default)] pub struct TBinaryOutputProtocolFactory; impl TBinaryOutputProtocolFactory { /// Create a `TBinaryOutputProtocolFactory`. pub fn new() -> TBinaryOutputProtocolFactory { TBinaryOutputProtocolFactory {} } } impl TOutputProtocolFactory for TBinaryOutputProtocolFactory { fn create( &self, transport: Box, ) -> Box { Box::new(TBinaryOutputProtocol::new(transport, true)) } } fn field_type_to_u8(field_type: TType) -> u8 { match field_type { TType::Stop => 0x00, TType::Void => 0x01, TType::Bool => 0x02, TType::I08 => 0x03, // equivalent to TType::Byte TType::Double => 0x04, TType::I16 => 0x06, TType::I32 => 0x08, TType::I64 => 0x0A, TType::String | TType::Utf7 => 0x0B, TType::Struct => 0x0C, TType::Map => 0x0D, TType::Set => 0x0E, TType::List => 0x0F, TType::Utf8 => 0x10, TType::Utf16 => 0x11, } } fn field_type_from_u8(b: u8) -> crate::Result { match b { 0x00 => Ok(TType::Stop), 0x01 => Ok(TType::Void), 0x02 => Ok(TType::Bool), 0x03 => Ok(TType::I08), // Equivalent to TType::Byte 0x04 => Ok(TType::Double), 0x06 => Ok(TType::I16), 0x08 => Ok(TType::I32), 0x0A => Ok(TType::I64), 0x0B => Ok(TType::String), // technically, also a UTF7, but we'll treat it as string 0x0C => Ok(TType::Struct), 0x0D => Ok(TType::Map), 0x0E => Ok(TType::Set), 0x0F => Ok(TType::List), 0x10 => Ok(TType::Utf8), 0x11 => Ok(TType::Utf16), unkn => Err(crate::Error::Protocol(ProtocolError { kind: ProtocolErrorKind::InvalidData, message: format!("cannot convert {} to TType", unkn), })), } } #[cfg(test)] mod tests { use crate::protocol::{ TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType, }; use crate::transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf}; use super::*; #[test] fn must_write_strict_message_call_begin() { let (_, mut o_prot) = test_objects(true); let ident = TMessageIdentifier::new("test", TMessageType::Call, 1); assert!(o_prot.write_message_begin(&ident).is_ok()); #[rustfmt::skip] let expected: [u8; 16] = [ 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x01, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_write_non_strict_message_call_begin() { let (_, mut o_prot) = test_objects(false); let ident = TMessageIdentifier::new("test", TMessageType::Call, 1); assert!(o_prot.write_message_begin(&ident).is_ok()); #[rustfmt::skip] let expected: [u8; 13] = [ 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, 0x00, 0x00, 0x00, 0x01, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_write_strict_message_reply_begin() { let (_, mut o_prot) = test_objects(true); let ident = TMessageIdentifier::new("test", TMessageType::Reply, 10); assert!(o_prot.write_message_begin(&ident).is_ok()); #[rustfmt::skip] let expected: [u8; 16] = [ 0x80, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x0A, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_write_non_strict_message_reply_begin() { let (_, mut o_prot) = test_objects(false); let ident = TMessageIdentifier::new("test", TMessageType::Reply, 10); assert!(o_prot.write_message_begin(&ident).is_ok()); #[rustfmt::skip] let expected: [u8; 13] = [ 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x02, 0x00, 0x00, 0x00, 0x0A, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_strict_message_begin() { let (mut i_prot, mut o_prot) = test_objects(true); let sent_ident = TMessageIdentifier::new("test", TMessageType::Call, 1); assert!(o_prot.write_message_begin(&sent_ident).is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let received_ident = assert_success!(i_prot.read_message_begin()); assert_eq!(&received_ident, &sent_ident); } #[test] fn must_round_trip_non_strict_message_begin() { let (mut i_prot, mut o_prot) = test_objects(false); let sent_ident = TMessageIdentifier::new("test", TMessageType::Call, 1); assert!(o_prot.write_message_begin(&sent_ident).is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let received_ident = assert_success!(i_prot.read_message_begin()); assert_eq!(&received_ident, &sent_ident); } #[test] fn must_write_message_end() { assert_no_write(|o| o.write_message_end(), true); } #[test] fn must_write_struct_begin() { assert_no_write( |o| o.write_struct_begin(&TStructIdentifier::new("foo")), true, ); } #[test] fn must_write_struct_end() { assert_no_write(|o| o.write_struct_end(), true); } #[test] fn must_write_field_begin() { let (_, mut o_prot) = test_objects(true); assert!(o_prot .write_field_begin(&TFieldIdentifier::new("some_field", TType::String, 22)) .is_ok()); let expected: [u8; 3] = [0x0B, 0x00, 0x16]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_field_begin() { let (mut i_prot, mut o_prot) = test_objects(true); let sent_field_ident = TFieldIdentifier::new("foo", TType::I64, 20); assert!(o_prot.write_field_begin(&sent_field_ident).is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let expected_ident = TFieldIdentifier { name: None, field_type: TType::I64, id: Some(20), }; // no name let received_ident = assert_success!(i_prot.read_field_begin()); assert_eq!(&received_ident, &expected_ident); } #[test] fn must_write_stop_field() { let (_, mut o_prot) = test_objects(true); assert!(o_prot.write_field_stop().is_ok()); let expected: [u8; 1] = [0x00]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_field_stop() { let (mut i_prot, mut o_prot) = test_objects(true); assert!(o_prot.write_field_stop().is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let expected_ident = TFieldIdentifier { name: None, field_type: TType::Stop, id: Some(0), }; // we get id 0 let received_ident = assert_success!(i_prot.read_field_begin()); assert_eq!(&received_ident, &expected_ident); } #[test] fn must_write_field_end() { assert_no_write(|o| o.write_field_end(), true); } #[test] fn must_write_list_begin() { let (_, mut o_prot) = test_objects(true); assert!(o_prot .write_list_begin(&TListIdentifier::new(TType::Bool, 5)) .is_ok()); let expected: [u8; 5] = [0x02, 0x00, 0x00, 0x00, 0x05]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_list_begin() { let (mut i_prot, mut o_prot) = test_objects(true); let ident = TListIdentifier::new(TType::List, 900); assert!(o_prot.write_list_begin(&ident).is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let received_ident = assert_success!(i_prot.read_list_begin()); assert_eq!(&received_ident, &ident); } #[test] fn must_write_list_end() { assert_no_write(|o| o.write_list_end(), true); } #[test] fn must_write_set_begin() { let (_, mut o_prot) = test_objects(true); assert!(o_prot .write_set_begin(&TSetIdentifier::new(TType::I16, 7)) .is_ok()); let expected: [u8; 5] = [0x06, 0x00, 0x00, 0x00, 0x07]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_set_begin() { let (mut i_prot, mut o_prot) = test_objects(true); let ident = TSetIdentifier::new(TType::I64, 2000); assert!(o_prot.write_set_begin(&ident).is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let received_ident_result = i_prot.read_set_begin(); assert!(received_ident_result.is_ok()); assert_eq!(&received_ident_result.unwrap(), &ident); } #[test] fn must_write_set_end() { assert_no_write(|o| o.write_set_end(), true); } #[test] fn must_write_map_begin() { let (_, mut o_prot) = test_objects(true); assert!(o_prot .write_map_begin(&TMapIdentifier::new(TType::I64, TType::Struct, 32)) .is_ok()); let expected: [u8; 6] = [0x0A, 0x0C, 0x00, 0x00, 0x00, 0x20]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_map_begin() { let (mut i_prot, mut o_prot) = test_objects(true); let ident = TMapIdentifier::new(TType::Map, TType::Set, 100); assert!(o_prot.write_map_begin(&ident).is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let received_ident = assert_success!(i_prot.read_map_begin()); assert_eq!(&received_ident, &ident); } #[test] fn must_write_map_end() { assert_no_write(|o| o.write_map_end(), true); } #[test] fn must_write_bool_true() { let (_, mut o_prot) = test_objects(true); assert!(o_prot.write_bool(true).is_ok()); let expected: [u8; 1] = [0x01]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_write_bool_false() { let (_, mut o_prot) = test_objects(true); assert!(o_prot.write_bool(false).is_ok()); let expected: [u8; 1] = [0x00]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_bool_true() { let (mut i_prot, _) = test_objects(true); set_readable_bytes!(i_prot, &[0x01]); let read_bool = assert_success!(i_prot.read_bool()); assert_eq!(read_bool, true); } #[test] fn must_read_bool_false() { let (mut i_prot, _) = test_objects(true); set_readable_bytes!(i_prot, &[0x00]); let read_bool = assert_success!(i_prot.read_bool()); assert_eq!(read_bool, false); } #[test] fn must_allow_any_non_zero_value_to_be_interpreted_as_bool_true() { let (mut i_prot, _) = test_objects(true); set_readable_bytes!(i_prot, &[0xAC]); let read_bool = assert_success!(i_prot.read_bool()); assert_eq!(read_bool, true); } #[test] fn must_write_bytes() { let (_, mut o_prot) = test_objects(true); let bytes: [u8; 10] = [0x0A, 0xCC, 0xD1, 0x84, 0x99, 0x12, 0xAB, 0xBB, 0x45, 0xDF]; assert!(o_prot.write_bytes(&bytes).is_ok()); let buf = o_prot.transport.write_bytes(); assert_eq!(&buf[0..4], [0x00, 0x00, 0x00, 0x0A]); // length assert_eq!(&buf[4..], bytes); // actual bytes } #[test] fn must_round_trip_bytes() { let (mut i_prot, mut o_prot) = test_objects(true); #[rustfmt::skip] let bytes: [u8; 25] = [ 0x20, 0xFD, 0x18, 0x84, 0x99, 0x12, 0xAB, 0xBB, 0x45, 0xDF, 0x34, 0xDC, 0x98, 0xA4, 0x6D, 0xF3, 0x99, 0xB4, 0xB7, 0xD4, 0x9C, 0xA5, 0xB3, 0xC9, 0x88, ]; assert!(o_prot.write_bytes(&bytes).is_ok()); copy_write_buffer_to_read_buffer!(o_prot); let received_bytes = assert_success!(i_prot.read_bytes()); assert_eq!(&received_bytes, &bytes); } fn test_objects( strict: bool, ) -> ( TBinaryInputProtocol>, TBinaryOutputProtocol>, ) { let mem = TBufferChannel::with_capacity(40, 40); let (r_mem, w_mem) = mem.split().unwrap(); let i_prot = TBinaryInputProtocol::new(r_mem, strict); let o_prot = TBinaryOutputProtocol::new(w_mem, strict); (i_prot, o_prot) } fn assert_no_write(mut write_fn: F, strict: bool) where F: FnMut(&mut TBinaryOutputProtocol>) -> crate::Result<()>, { let (_, mut o_prot) = test_objects(strict); assert!(write_fn(&mut o_prot).is_ok()); assert_eq!(o_prot.transport.write_bytes().len(), 0); } } thrift-0.16.0/lib/rs/src/protocol/compact.rs000066400000000000000000002702101420101504100207020ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use integer_encoding::{VarIntReader, VarIntWriter}; use std::convert::{From, TryFrom}; use std::io; use super::{ TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, }; use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType}; use crate::transport::{TReadTransport, TWriteTransport}; const COMPACT_PROTOCOL_ID: u8 = 0x82; const COMPACT_VERSION: u8 = 0x01; const COMPACT_VERSION_MASK: u8 = 0x1F; /// Read messages encoded in the Thrift compact protocol. /// /// # Examples /// /// Create and use a `TCompactInputProtocol`. /// /// ```no_run /// use thrift::protocol::{TCompactInputProtocol, TInputProtocol}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("localhost:9090").unwrap(); /// /// let mut protocol = TCompactInputProtocol::new(channel); /// /// let recvd_bool = protocol.read_bool().unwrap(); /// let recvd_string = protocol.read_string().unwrap(); /// ``` #[derive(Debug)] pub struct TCompactInputProtocol where T: TReadTransport, { // Identifier of the last field deserialized for a struct. last_read_field_id: i16, // Stack of the last read field ids (a new entry is added each time a nested struct is read). read_field_id_stack: Vec, // Boolean value for a field. // Saved because boolean fields and their value are encoded in a single byte, // and reading the field only occurs after the field id is read. pending_read_bool_value: Option, // Underlying transport used for byte-level operations. transport: T, } impl TCompactInputProtocol where T: TReadTransport, { /// Create a `TCompactInputProtocol` that reads bytes from `transport`. pub fn new(transport: T) -> TCompactInputProtocol { TCompactInputProtocol { last_read_field_id: 0, read_field_id_stack: Vec::new(), pending_read_bool_value: None, transport, } } fn read_list_set_begin(&mut self) -> crate::Result<(TType, i32)> { let header = self.read_byte()?; let element_type = collection_u8_to_type(header & 0x0F)?; let element_count; let possible_element_count = (header & 0xF0) >> 4; if possible_element_count != 15 { // high bits set high if count and type encoded separately element_count = possible_element_count as i32; } else { element_count = self.transport.read_varint::()? as i32; } Ok((element_type, element_count)) } } impl TInputProtocol for TCompactInputProtocol where T: TReadTransport, { fn read_message_begin(&mut self) -> crate::Result { let compact_id = self.read_byte()?; if compact_id != COMPACT_PROTOCOL_ID { Err(crate::Error::Protocol(crate::ProtocolError { kind: crate::ProtocolErrorKind::BadVersion, message: format!("invalid compact protocol header {:?}", compact_id), })) } else { Ok(()) }?; let type_and_byte = self.read_byte()?; let received_version = type_and_byte & COMPACT_VERSION_MASK; if received_version != COMPACT_VERSION { Err(crate::Error::Protocol(crate::ProtocolError { kind: crate::ProtocolErrorKind::BadVersion, message: format!( "cannot process compact protocol version {:?}", received_version ), })) } else { Ok(()) }?; // NOTE: unsigned right shift will pad with 0s let message_type: TMessageType = TMessageType::try_from(type_and_byte >> 5)?; // writing side wrote signed sequence number as u32 to avoid zigzag encoding let sequence_number = self.transport.read_varint::()? as i32; let service_call_name = self.read_string()?; self.last_read_field_id = 0; Ok(TMessageIdentifier::new( service_call_name, message_type, sequence_number, )) } fn read_message_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_struct_begin(&mut self) -> crate::Result> { self.read_field_id_stack.push(self.last_read_field_id); self.last_read_field_id = 0; Ok(None) } fn read_struct_end(&mut self) -> crate::Result<()> { self.last_read_field_id = self .read_field_id_stack .pop() .expect("should have previous field ids"); Ok(()) } fn read_field_begin(&mut self) -> crate::Result { // we can read at least one byte, which is: // - the type // - the field delta and the type let field_type = self.read_byte()?; let field_delta = (field_type & 0xF0) >> 4; let field_type = match field_type & 0x0F { 0x01 => { self.pending_read_bool_value = Some(true); Ok(TType::Bool) } 0x02 => { self.pending_read_bool_value = Some(false); Ok(TType::Bool) } ttu8 => u8_to_type(ttu8), }?; match field_type { TType::Stop => Ok( TFieldIdentifier::new::, String, Option>( None, TType::Stop, None, ), ), _ => { if field_delta != 0 { self.last_read_field_id += field_delta as i16; } else { self.last_read_field_id = self.read_i16()?; }; Ok(TFieldIdentifier { name: None, field_type, id: Some(self.last_read_field_id), }) } } } fn read_field_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_bool(&mut self) -> crate::Result { match self.pending_read_bool_value.take() { Some(b) => Ok(b), None => { let b = self.read_byte()?; match b { 0x01 => Ok(true), 0x02 => Ok(false), unkn => Err(crate::Error::Protocol(crate::ProtocolError { kind: crate::ProtocolErrorKind::InvalidData, message: format!("cannot convert {} into bool", unkn), })), } } } } fn read_bytes(&mut self) -> crate::Result> { let len = self.transport.read_varint::()?; let mut buf = vec![0u8; len as usize]; self.transport .read_exact(&mut buf) .map_err(From::from) .map(|_| buf) } fn read_i8(&mut self) -> crate::Result { self.read_byte().map(|i| i as i8) } fn read_i16(&mut self) -> crate::Result { self.transport.read_varint::().map_err(From::from) } fn read_i32(&mut self) -> crate::Result { self.transport.read_varint::().map_err(From::from) } fn read_i64(&mut self) -> crate::Result { self.transport.read_varint::().map_err(From::from) } fn read_double(&mut self) -> crate::Result { self.transport .read_f64::() .map_err(From::from) } fn read_string(&mut self) -> crate::Result { let bytes = self.read_bytes()?; String::from_utf8(bytes).map_err(From::from) } fn read_list_begin(&mut self) -> crate::Result { let (element_type, element_count) = self.read_list_set_begin()?; Ok(TListIdentifier::new(element_type, element_count)) } fn read_list_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_set_begin(&mut self) -> crate::Result { let (element_type, element_count) = self.read_list_set_begin()?; Ok(TSetIdentifier::new(element_type, element_count)) } fn read_set_end(&mut self) -> crate::Result<()> { Ok(()) } fn read_map_begin(&mut self) -> crate::Result { let element_count = self.transport.read_varint::()? as i32; if element_count == 0 { Ok(TMapIdentifier::new(None, None, 0)) } else { let type_header = self.read_byte()?; let key_type = collection_u8_to_type((type_header & 0xF0) >> 4)?; let val_type = collection_u8_to_type(type_header & 0x0F)?; Ok(TMapIdentifier::new(key_type, val_type, element_count)) } } fn read_map_end(&mut self) -> crate::Result<()> { Ok(()) } // utility // fn read_byte(&mut self) -> crate::Result { let mut buf = [0u8; 1]; self.transport .read_exact(&mut buf) .map_err(From::from) .map(|_| buf[0]) } } impl io::Seek for TCompactInputProtocol where T: io::Seek + TReadTransport, { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { self.transport.seek(pos) } } /// Factory for creating instances of `TCompactInputProtocol`. #[derive(Default)] pub struct TCompactInputProtocolFactory; impl TCompactInputProtocolFactory { /// Create a `TCompactInputProtocolFactory`. pub fn new() -> TCompactInputProtocolFactory { TCompactInputProtocolFactory {} } } impl TInputProtocolFactory for TCompactInputProtocolFactory { fn create(&self, transport: Box) -> Box { Box::new(TCompactInputProtocol::new(transport)) } } /// Write messages using the Thrift compact protocol. /// /// # Examples /// /// Create and use a `TCompactOutputProtocol`. /// /// ```no_run /// use thrift::protocol::{TCompactOutputProtocol, TOutputProtocol}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("localhost:9090").unwrap(); /// /// let mut protocol = TCompactOutputProtocol::new(channel); /// /// protocol.write_bool(true).unwrap(); /// protocol.write_string("test_string").unwrap(); /// ``` #[derive(Debug)] pub struct TCompactOutputProtocol where T: TWriteTransport, { // Identifier of the last field serialized for a struct. last_write_field_id: i16, // Stack of the last written field ids (new entry added each time a nested struct is written). write_field_id_stack: Vec, // Field identifier of the boolean field to be written. // Saved because boolean fields and their value are encoded in a single byte pending_write_bool_field_identifier: Option, // Underlying transport used for byte-level operations. transport: T, } impl TCompactOutputProtocol where T: TWriteTransport, { /// Create a `TCompactOutputProtocol` that writes bytes to `transport`. pub fn new(transport: T) -> TCompactOutputProtocol { TCompactOutputProtocol { last_write_field_id: 0, write_field_id_stack: Vec::new(), pending_write_bool_field_identifier: None, transport, } } // FIXME: field_type as unconstrained u8 is bad fn write_field_header(&mut self, field_type: u8, field_id: i16) -> crate::Result<()> { let field_delta = field_id - self.last_write_field_id; if field_delta > 0 && field_delta < 15 { self.write_byte(((field_delta as u8) << 4) | field_type)?; } else { self.write_byte(field_type)?; self.write_i16(field_id)?; } self.last_write_field_id = field_id; Ok(()) } fn write_list_set_begin( &mut self, element_type: TType, element_count: i32, ) -> crate::Result<()> { let elem_identifier = collection_type_to_u8(element_type); if element_count <= 14 { let header = (element_count as u8) << 4 | elem_identifier; self.write_byte(header) } else { let header = 0xF0 | elem_identifier; self.write_byte(header)?; // element count is strictly positive as per the spec, so // cast i32 as u32 so that varint writing won't use zigzag encoding self.transport .write_varint(element_count as u32) .map_err(From::from) .map(|_| ()) } } fn assert_no_pending_bool_write(&self) { if let Some(ref f) = self.pending_write_bool_field_identifier { panic!("pending bool field {:?} not written", f) } } } impl TOutputProtocol for TCompactOutputProtocol where T: TWriteTransport, { fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> crate::Result<()> { self.write_byte(COMPACT_PROTOCOL_ID)?; self.write_byte((u8::from(identifier.message_type) << 5) | COMPACT_VERSION)?; // cast i32 as u32 so that varint writing won't use zigzag encoding self.transport .write_varint(identifier.sequence_number as u32)?; self.write_string(&identifier.name)?; Ok(()) } fn write_message_end(&mut self) -> crate::Result<()> { self.assert_no_pending_bool_write(); Ok(()) } fn write_struct_begin(&mut self, _: &TStructIdentifier) -> crate::Result<()> { self.write_field_id_stack.push(self.last_write_field_id); self.last_write_field_id = 0; Ok(()) } fn write_struct_end(&mut self) -> crate::Result<()> { self.assert_no_pending_bool_write(); self.last_write_field_id = self .write_field_id_stack .pop() .expect("should have previous field ids"); Ok(()) } fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> crate::Result<()> { match identifier.field_type { TType::Bool => { if self.pending_write_bool_field_identifier.is_some() { panic!( "should not have a pending bool while writing another bool with id: \ {:?}", identifier ) } self.pending_write_bool_field_identifier = Some(identifier.clone()); Ok(()) } _ => { let field_type = type_to_u8(identifier.field_type); let field_id = identifier.id.expect("non-stop field should have field id"); self.write_field_header(field_type, field_id) } } } fn write_field_end(&mut self) -> crate::Result<()> { self.assert_no_pending_bool_write(); Ok(()) } fn write_field_stop(&mut self) -> crate::Result<()> { self.assert_no_pending_bool_write(); self.write_byte(type_to_u8(TType::Stop)) } fn write_bool(&mut self, b: bool) -> crate::Result<()> { match self.pending_write_bool_field_identifier.take() { Some(pending) => { let field_id = pending.id.expect("bool field should have a field id"); let field_type_as_u8 = if b { 0x01 } else { 0x02 }; self.write_field_header(field_type_as_u8, field_id) } None => { if b { self.write_byte(0x01) } else { self.write_byte(0x02) } } } } fn write_bytes(&mut self, b: &[u8]) -> crate::Result<()> { // length is strictly positive as per the spec, so // cast i32 as u32 so that varint writing won't use zigzag encoding self.transport.write_varint(b.len() as u32)?; self.transport.write_all(b).map_err(From::from) } fn write_i8(&mut self, i: i8) -> crate::Result<()> { self.write_byte(i as u8) } fn write_i16(&mut self, i: i16) -> crate::Result<()> { self.transport .write_varint(i) .map_err(From::from) .map(|_| ()) } fn write_i32(&mut self, i: i32) -> crate::Result<()> { self.transport .write_varint(i) .map_err(From::from) .map(|_| ()) } fn write_i64(&mut self, i: i64) -> crate::Result<()> { self.transport .write_varint(i) .map_err(From::from) .map(|_| ()) } fn write_double(&mut self, d: f64) -> crate::Result<()> { self.transport .write_f64::(d) .map_err(From::from) } fn write_string(&mut self, s: &str) -> crate::Result<()> { self.write_bytes(s.as_bytes()) } fn write_list_begin(&mut self, identifier: &TListIdentifier) -> crate::Result<()> { self.write_list_set_begin(identifier.element_type, identifier.size) } fn write_list_end(&mut self) -> crate::Result<()> { Ok(()) } fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> crate::Result<()> { self.write_list_set_begin(identifier.element_type, identifier.size) } fn write_set_end(&mut self) -> crate::Result<()> { Ok(()) } fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> crate::Result<()> { if identifier.size == 0 { self.write_byte(0) } else { // element count is strictly positive as per the spec, so // cast i32 as u32 so that varint writing won't use zigzag encoding self.transport.write_varint(identifier.size as u32)?; let key_type = identifier .key_type .expect("map identifier to write should contain key type"); let key_type_byte = collection_type_to_u8(key_type) << 4; let val_type = identifier .value_type .expect("map identifier to write should contain value type"); let val_type_byte = collection_type_to_u8(val_type); let map_type_header = key_type_byte | val_type_byte; self.write_byte(map_type_header) } } fn write_map_end(&mut self) -> crate::Result<()> { Ok(()) } fn flush(&mut self) -> crate::Result<()> { self.transport.flush().map_err(From::from) } // utility // fn write_byte(&mut self, b: u8) -> crate::Result<()> { self.transport.write(&[b]).map_err(From::from).map(|_| ()) } } /// Factory for creating instances of `TCompactOutputProtocol`. #[derive(Default)] pub struct TCompactOutputProtocolFactory; impl TCompactOutputProtocolFactory { /// Create a `TCompactOutputProtocolFactory`. pub fn new() -> TCompactOutputProtocolFactory { TCompactOutputProtocolFactory {} } } impl TOutputProtocolFactory for TCompactOutputProtocolFactory { fn create( &self, transport: Box, ) -> Box { Box::new(TCompactOutputProtocol::new(transport)) } } fn collection_type_to_u8(field_type: TType) -> u8 { match field_type { TType::Bool => 0x01, f => type_to_u8(f), } } fn type_to_u8(field_type: TType) -> u8 { match field_type { TType::Stop => 0x00, TType::I08 => 0x03, // equivalent to TType::Byte TType::I16 => 0x04, TType::I32 => 0x05, TType::I64 => 0x06, TType::Double => 0x07, TType::String => 0x08, TType::List => 0x09, TType::Set => 0x0A, TType::Map => 0x0B, TType::Struct => 0x0C, _ => panic!("should not have attempted to convert {} to u8", field_type), } } fn collection_u8_to_type(b: u8) -> crate::Result { match b { 0x01 => Ok(TType::Bool), o => u8_to_type(o), } } fn u8_to_type(b: u8) -> crate::Result { match b { 0x00 => Ok(TType::Stop), 0x03 => Ok(TType::I08), // equivalent to TType::Byte 0x04 => Ok(TType::I16), 0x05 => Ok(TType::I32), 0x06 => Ok(TType::I64), 0x07 => Ok(TType::Double), 0x08 => Ok(TType::String), 0x09 => Ok(TType::List), 0x0A => Ok(TType::Set), 0x0B => Ok(TType::Map), 0x0C => Ok(TType::Struct), unkn => Err(crate::Error::Protocol(crate::ProtocolError { kind: crate::ProtocolErrorKind::InvalidData, message: format!("cannot convert {} into TType", unkn), })), } } #[cfg(test)] mod tests { use std::i32; use crate::protocol::{ TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType, }; use crate::transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf}; use super::*; #[test] fn must_write_message_begin_largest_maximum_positive_sequence_number() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "bar", TMessageType::Reply, i32::MAX ))); #[rustfmt::skip] let expected: [u8; 11] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0xFF, 0xFF, 0xFF, 0xFF, 0x07, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_largest_maximum_positive_sequence_number() { let (mut i_prot, _) = test_objects(); #[rustfmt::skip] let source_bytes: [u8; 11] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0xFF, 0xFF, 0xFF, 0xFF, 0x07, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("bar", TMessageType::Reply, i32::MAX); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_write_message_begin_positive_sequence_number_0() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "foo", TMessageType::Call, 431 ))); #[rustfmt::skip] let expected: [u8; 8] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0xAF, 0x03, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F /* "foo" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_positive_sequence_number_0() { let (mut i_prot, _) = test_objects(); #[rustfmt::skip] let source_bytes: [u8; 8] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0xAF, 0x03, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F /* "foo" */, ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("foo", TMessageType::Call, 431); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_write_message_begin_positive_sequence_number_1() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "bar", TMessageType::Reply, 991_828 ))); #[rustfmt::skip] let expected: [u8; 9] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0xD4, 0xC4, 0x3C, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_positive_sequence_number_1() { let (mut i_prot, _) = test_objects(); #[rustfmt::skip] let source_bytes: [u8; 9] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0xD4, 0xC4, 0x3C, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("bar", TMessageType::Reply, 991_828); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_write_message_begin_zero_sequence_number() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "bar", TMessageType::Reply, 0 ))); #[rustfmt::skip] let expected: [u8; 7] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0x00, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_zero_sequence_number() { let (mut i_prot, _) = test_objects(); #[rustfmt::skip] let source_bytes: [u8; 7] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0x00, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("bar", TMessageType::Reply, 0); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_write_message_begin_largest_minimum_negative_sequence_number() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "bar", TMessageType::Reply, i32::MIN ))); // two's complement notation of i32::MIN = 1000_0000_0000_0000_0000_0000_0000_0000 #[rustfmt::skip] let expected: [u8; 11] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0x80, 0x80, 0x80, 0x80, 0x08, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_largest_minimum_negative_sequence_number() { let (mut i_prot, _) = test_objects(); // two's complement notation of i32::MIN = 1000_0000_0000_0000_0000_0000_0000_0000 #[rustfmt::skip] let source_bytes: [u8; 11] = [ 0x82, /* protocol ID */ 0x41, /* message type | protocol version */ 0x80, 0x80, 0x80, 0x80, 0x08, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x62, 0x61, 0x72 /* "bar" */, ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("bar", TMessageType::Reply, i32::MIN); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_write_message_begin_negative_sequence_number_0() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "foo", TMessageType::Call, -431 ))); // signed two's complement of -431 = 1111_1111_1111_1111_1111_1110_0101_0001 #[rustfmt::skip] let expected: [u8; 11] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0xD1, 0xFC, 0xFF, 0xFF, 0x0F, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F /* "foo" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_negative_sequence_number_0() { let (mut i_prot, _) = test_objects(); // signed two's complement of -431 = 1111_1111_1111_1111_1111_1110_0101_0001 #[rustfmt::skip] let source_bytes: [u8; 11] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0xD1, 0xFC, 0xFF, 0xFF, 0x0F, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F /* "foo" */, ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("foo", TMessageType::Call, -431); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_write_message_begin_negative_sequence_number_1() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "foo", TMessageType::Call, -73_184_125 ))); // signed two's complement of -73184125 = 1111_1011_1010_0011_0100_1100_1000_0011 #[rustfmt::skip] let expected: [u8; 11] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0x83, 0x99, 0x8D, 0xDD, 0x0F, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F /* "foo" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_negative_sequence_number_1() { let (mut i_prot, _) = test_objects(); // signed two's complement of -73184125 = 1111_1011_1010_0011_0100_1100_1000_0011 #[rustfmt::skip] let source_bytes: [u8; 11] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0x83, 0x99, 0x8D, 0xDD, 0x0F, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F /* "foo" */, ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("foo", TMessageType::Call, -73_184_125); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_write_message_begin_negative_sequence_number_2() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new( "foo", TMessageType::Call, -1_073_741_823 ))); // signed two's complement of -1073741823 = 1100_0000_0000_0000_0000_0000_0000_0001 #[rustfmt::skip] let expected: [u8; 11] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0x81, 0x80, 0x80, 0x80, 0x0C, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F /* "foo" */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_message_begin_negative_sequence_number_2() { let (mut i_prot, _) = test_objects(); // signed two's complement of -1073741823 = 1100_0000_0000_0000_0000_0000_0000_0001 #[rustfmt::skip] let source_bytes: [u8; 11] = [ 0x82, /* protocol ID */ 0x21, /* message type | protocol version */ 0x81, 0x80, 0x80, 0x80, 0x0C, /* non-zig-zag varint sequence number */ 0x03, /* message-name length */ 0x66, 0x6F, 0x6F, /* "foo" */ ]; i_prot.transport.set_readable_bytes(&source_bytes); let expected = TMessageIdentifier::new("foo", TMessageType::Call, -1_073_741_823); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&expected, &res); } #[test] fn must_round_trip_upto_i64_maxvalue() { // See https://issues.apache.org/jira/browse/THRIFT-5131 for i in 0..64 { let (mut i_prot, mut o_prot) = test_objects(); let val: i64 = ((1u64 << i) - 1) as i64; o_prot .write_field_begin(&TFieldIdentifier::new("val", TType::I64, 1)) .unwrap(); o_prot.write_i64(val).unwrap(); o_prot.write_field_end().unwrap(); o_prot.flush().unwrap(); copy_write_buffer_to_read_buffer!(o_prot); i_prot.read_field_begin().unwrap(); assert_eq!(val, i_prot.read_i64().unwrap()); } } #[test] fn must_round_trip_message_begin() { let (mut i_prot, mut o_prot) = test_objects(); let ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1_283_948); assert_success!(o_prot.write_message_begin(&ident)); copy_write_buffer_to_read_buffer!(o_prot); let res = assert_success!(i_prot.read_message_begin()); assert_eq!(&res, &ident); } #[test] fn must_write_message_end() { assert_no_write(|o| o.write_message_end()); } // NOTE: structs and fields are tested together // #[test] fn must_write_struct_with_delta_fields() { let (_, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with tiny field ids // since they're small the field ids will be encoded as deltas // since this is the first field (and it's zero) it gets the full varint write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 0))); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I16, 4))); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::List, 9))); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 5] = [ 0x03, /* field type */ 0x00, /* first field id */ 0x44, /* field delta (4) | field type */ 0x59, /* field delta (5) | field type */ 0x00 /* field stop */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_struct_with_delta_fields() { let (mut i_prot, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with tiny field ids // since they're small the field ids will be encoded as deltas // since this is the first field (and it's zero) it gets the full varint write let field_ident_1 = TFieldIdentifier::new("foo", TType::I08, 0); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta let field_ident_2 = TFieldIdentifier::new("foo", TType::I16, 4); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta let field_ident_3 = TFieldIdentifier::new("foo", TType::List, 9); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read the struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_struct_with_non_zero_initial_field_and_delta_fields() { let (_, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with tiny field ids // since they're small the field ids will be encoded as deltas // gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 1))); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2))); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 6))); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 4] = [ 0x15, /* field delta (1) | field type */ 0x1A, /* field delta (1) | field type */ 0x48, /* field delta (4) | field type */ 0x00 /* field stop */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_struct_with_non_zero_initial_field_and_delta_fields() { let (mut i_prot, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with tiny field ids // since they're small the field ids will be encoded as deltas // gets a delta write let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 1); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta let field_ident_2 = TFieldIdentifier::new("foo", TType::Set, 2); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it can be encoded as a delta let field_ident_3 = TFieldIdentifier::new("foo", TType::String, 6); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read the struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_struct_with_long_fields() { let (_, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with field ids that cannot be encoded as deltas // since this is the first field (and it's zero) it gets the full varint write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 0))); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 16))); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 99))); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 8] = [ 0x05, /* field type */ 0x00, /* first field id */ 0x06, /* field type */ 0x20, /* zig-zag varint field id */ 0x0A, /* field type */ 0xC6, 0x01, /* zig-zag varint field id */ 0x00 /* field stop */, ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_struct_with_long_fields() { let (mut i_prot, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with field ids that cannot be encoded as deltas // since this is the first field (and it's zero) it gets the full varint write let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 0); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint let field_ident_2 = TFieldIdentifier::new("foo", TType::I64, 16); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 99); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read the struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_struct_with_mix_of_long_and_delta_fields() { let (_, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with field ids that cannot be encoded as deltas // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9))); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 1000))); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2001))); assert_success!(o_prot.write_field_end()); // since this is only 3 up from the previous it is recorded as a delta assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2004))); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 10] = [ 0x16, /* field delta (1) | field type */ 0x85, /* field delta (8) | field type */ 0x0A, /* field type */ 0xD0, 0x0F, /* zig-zag varint field id */ 0x0A, /* field type */ 0xA2, 0x1F, /* zig-zag varint field id */ 0x3A, /* field delta (3) | field type */ 0x00 /* field stop */, ]; assert_eq_written_bytes!(o_prot, expected); } #[allow(clippy::cognitive_complexity)] #[test] fn must_round_trip_struct_with_mix_of_long_and_delta_fields() { let (mut i_prot, mut o_prot) = test_objects(); // no bytes should be written however let struct_ident = TStructIdentifier::new("foo"); assert_success!(o_prot.write_struct_begin(&struct_ident)); // write three fields with field ids that cannot be encoded as deltas // since the delta is > 0 and < 15 it gets a delta write let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it gets a delta write let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 1000); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // since this delta is > 15 it is encoded as a zig-zag varint let field_ident_4 = TFieldIdentifier::new("foo", TType::Set, 2001); assert_success!(o_prot.write_field_begin(&field_ident_4)); assert_success!(o_prot.write_field_end()); // since this is only 3 up from the previous it is recorded as a delta let field_ident_5 = TFieldIdentifier::new("foo", TType::Set, 2004); assert_success!(o_prot.write_field_begin(&field_ident_5)); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read the struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, ..field_ident_4 } ); assert_success!(i_prot.read_field_end()); let read_ident_5 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_5, TFieldIdentifier { name: None, ..field_ident_5 } ); assert_success!(i_prot.read_field_end()); let read_ident_6 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_6, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_nested_structs_0() { // last field of the containing struct is a delta // first field of the the contained struct is a delta let (_, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9))); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 7))); assert_success!(o_prot.write_field_end()); // contained struct // since this delta > 15 it gets a full write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24))); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 7] = [ 0x16, /* field delta (1) | field type */ 0x85, /* field delta (8) | field type */ 0x73, /* field delta (7) | field type */ 0x07, /* field type */ 0x30, /* zig-zag varint field id */ 0x00, /* field stop - contained */ 0x00 /* field stop - containing */, ]; assert_eq_written_bytes!(o_prot, expected); } #[allow(clippy::cognitive_complexity)] #[test] fn must_round_trip_nested_structs_0() { // last field of the containing struct is a delta // first field of the the contained struct is a delta let (mut i_prot, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 0 and < 15 it gets a delta write let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_3 = TFieldIdentifier::new("foo", TType::I08, 7); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // contained struct // since this delta > 15 it gets a full write let field_ident_4 = TFieldIdentifier::new("foo", TType::Double, 24); assert_success!(o_prot.write_field_begin(&field_ident_4)); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read containing struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); // read contained struct back assert_success!(i_prot.read_struct_begin()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, ..field_ident_4 } ); assert_success!(i_prot.read_field_end()); // end contained struct let read_ident_6 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_6, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); // end containing struct let read_ident_7 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_7, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_nested_structs_1() { // last field of the containing struct is a delta // first field of the the contained struct is a full write let (_, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9))); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since this delta > 15 it gets a full write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24))); assert_success!(o_prot.write_field_end()); // contained struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27))); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 7] = [ 0x16, /* field delta (1) | field type */ 0x85, /* field delta (8) | field type */ 0x07, /* field type */ 0x30, /* zig-zag varint field id */ 0x33, /* field delta (3) | field type */ 0x00, /* field stop - contained */ 0x00 /* field stop - containing */, ]; assert_eq_written_bytes!(o_prot, expected); } #[allow(clippy::cognitive_complexity)] #[test] fn must_round_trip_nested_structs_1() { // last field of the containing struct is a delta // first field of the the contained struct is a full write let (mut i_prot, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 0 and < 15 it gets a delta write let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since this delta > 15 it gets a full write let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 24); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // contained struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27); assert_success!(o_prot.write_field_begin(&field_ident_4)); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read containing struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); // read contained struct back assert_success!(i_prot.read_struct_begin()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, ..field_ident_4 } ); assert_success!(i_prot.read_field_end()); // end contained struct let read_ident_6 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_6, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); // end containing struct let read_ident_7 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_7, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_nested_structs_2() { // last field of the containing struct is a full write // first field of the the contained struct is a delta write let (_, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 15 it gets a full write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21))); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since this delta > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 7))); assert_success!(o_prot.write_field_end()); // contained struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 10))); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 7] = [ 0x16, /* field delta (1) | field type */ 0x08, /* field type */ 0x2A, /* zig-zag varint field id */ 0x77, /* field delta(7) | field type */ 0x33, /* field delta (3) | field type */ 0x00, /* field stop - contained */ 0x00 /* field stop - containing */, ]; assert_eq_written_bytes!(o_prot, expected); } #[allow(clippy::cognitive_complexity)] #[test] fn must_round_trip_nested_structs_2() { let (mut i_prot, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 15 it gets a full write let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since this delta > 0 and < 15 it gets a delta write let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 7); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // contained struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 10); assert_success!(o_prot.write_field_begin(&field_ident_4)); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read containing struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); // read contained struct back assert_success!(i_prot.read_struct_begin()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, ..field_ident_4 } ); assert_success!(i_prot.read_field_end()); // end contained struct let read_ident_6 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_6, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); // end containing struct let read_ident_7 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_7, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_nested_structs_3() { // last field of the containing struct is a full write // first field of the the contained struct is a full write let (_, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1))); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 15 it gets a full write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21))); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since this delta > 15 it gets a full write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 21))); assert_success!(o_prot.write_field_end()); // contained struct // since the delta is > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27))); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 8] = [ 0x16, /* field delta (1) | field type */ 0x08, /* field type */ 0x2A, /* zig-zag varint field id */ 0x07, /* field type */ 0x2A, /* zig-zag varint field id */ 0x63, /* field delta (6) | field type */ 0x00, /* field stop - contained */ 0x00 /* field stop - containing */, ]; assert_eq_written_bytes!(o_prot, expected); } #[allow(clippy::cognitive_complexity)] #[test] fn must_round_trip_nested_structs_3() { // last field of the containing struct is a full write // first field of the the contained struct is a full write let (mut i_prot, mut o_prot) = test_objects(); // start containing struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // containing struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_field_end()); // containing struct // since this delta > 15 it gets a full write let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_field_end()); // start contained struct assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // contained struct // since this delta > 15 it gets a full write let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 21); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_field_end()); // contained struct // since the delta is > 0 and < 15 it gets a delta write let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27); assert_success!(o_prot.write_field_begin(&field_ident_4)); assert_success!(o_prot.write_field_end()); // end contained struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); // end containing struct assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read containing struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); assert_success!(i_prot.read_field_end()); // read contained struct back assert_success!(i_prot.read_struct_begin()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, ..field_ident_4 } ); assert_success!(i_prot.read_field_end()); // end contained struct let read_ident_6 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_6, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); // end containing struct let read_ident_7 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_7, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] fn must_write_bool_field() { let (_, mut o_prot) = test_objects(); // no bytes should be written however assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); // write three fields with field ids that cannot be encoded as deltas // since the delta is > 0 and < 16 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); assert_success!(o_prot.write_bool(true)); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it gets a delta write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 9))); assert_success!(o_prot.write_bool(false)); assert_success!(o_prot.write_field_end()); // since this delta > 15 it gets a full write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 26))); assert_success!(o_prot.write_bool(true)); assert_success!(o_prot.write_field_end()); // since this delta > 15 it gets a full write assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 45))); assert_success!(o_prot.write_bool(false)); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); #[rustfmt::skip] let expected: [u8; 7] = [ 0x11, /* field delta (1) | true */ 0x82, /* field delta (8) | false */ 0x01, /* true */ 0x34, /* field id */ 0x02, /* false */ 0x5A, /* field id */ 0x00 /* stop field */, ]; assert_eq_written_bytes!(o_prot, expected); } #[allow(clippy::cognitive_complexity)] #[test] fn must_round_trip_bool_field() { let (mut i_prot, mut o_prot) = test_objects(); // no bytes should be written however let struct_ident = TStructIdentifier::new("foo"); assert_success!(o_prot.write_struct_begin(&struct_ident)); // write two fields // since the delta is > 0 and < 16 it gets a delta write let field_ident_1 = TFieldIdentifier::new("foo", TType::Bool, 1); assert_success!(o_prot.write_field_begin(&field_ident_1)); assert_success!(o_prot.write_bool(true)); assert_success!(o_prot.write_field_end()); // since this delta > 0 and < 15 it gets a delta write let field_ident_2 = TFieldIdentifier::new("foo", TType::Bool, 9); assert_success!(o_prot.write_field_begin(&field_ident_2)); assert_success!(o_prot.write_bool(false)); assert_success!(o_prot.write_field_end()); // since this delta > 15 it gets a full write let field_ident_3 = TFieldIdentifier::new("foo", TType::Bool, 26); assert_success!(o_prot.write_field_begin(&field_ident_3)); assert_success!(o_prot.write_bool(true)); assert_success!(o_prot.write_field_end()); // since this delta > 15 it gets a full write let field_ident_4 = TFieldIdentifier::new("foo", TType::Bool, 45); assert_success!(o_prot.write_field_begin(&field_ident_4)); assert_success!(o_prot.write_bool(false)); assert_success!(o_prot.write_field_end()); // now, finish the struct off assert_success!(o_prot.write_field_stop()); assert_success!(o_prot.write_struct_end()); copy_write_buffer_to_read_buffer!(o_prot); // read the struct back assert_success!(i_prot.read_struct_begin()); let read_ident_1 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_1, TFieldIdentifier { name: None, ..field_ident_1 } ); let read_value_1 = assert_success!(i_prot.read_bool()); assert_eq!(read_value_1, true); assert_success!(i_prot.read_field_end()); let read_ident_2 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_2, TFieldIdentifier { name: None, ..field_ident_2 } ); let read_value_2 = assert_success!(i_prot.read_bool()); assert_eq!(read_value_2, false); assert_success!(i_prot.read_field_end()); let read_ident_3 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_3, TFieldIdentifier { name: None, ..field_ident_3 } ); let read_value_3 = assert_success!(i_prot.read_bool()); assert_eq!(read_value_3, true); assert_success!(i_prot.read_field_end()); let read_ident_4 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_4, TFieldIdentifier { name: None, ..field_ident_4 } ); let read_value_4 = assert_success!(i_prot.read_bool()); assert_eq!(read_value_4, false); assert_success!(i_prot.read_field_end()); let read_ident_5 = assert_success!(i_prot.read_field_begin()); assert_eq!( read_ident_5, TFieldIdentifier { name: None, field_type: TType::Stop, id: None, } ); assert_success!(i_prot.read_struct_end()); } #[test] #[should_panic] fn must_fail_if_write_field_end_without_writing_bool_value() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); o_prot.write_field_end().unwrap(); } #[test] #[should_panic] fn must_fail_if_write_stop_field_without_writing_bool_value() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); o_prot.write_field_stop().unwrap(); } #[test] #[should_panic] fn must_fail_if_write_struct_end_without_writing_bool_value() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo"))); assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1))); o_prot.write_struct_end().unwrap(); } #[test] #[should_panic] fn must_fail_if_write_struct_end_without_any_fields() { let (_, mut o_prot) = test_objects(); o_prot.write_struct_end().unwrap(); } #[test] fn must_write_field_end() { assert_no_write(|o| o.write_field_end()); } #[test] fn must_write_small_sized_list_begin() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_list_begin(&TListIdentifier::new(TType::I64, 4))); let expected: [u8; 1] = [0x46 /* size | elem_type */]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_small_sized_list_begin() { let (mut i_prot, mut o_prot) = test_objects(); let ident = TListIdentifier::new(TType::I08, 10); assert_success!(o_prot.write_list_begin(&ident)); copy_write_buffer_to_read_buffer!(o_prot); let res = assert_success!(i_prot.read_list_begin()); assert_eq!(&res, &ident); } #[test] fn must_write_large_sized_list_begin() { let (_, mut o_prot) = test_objects(); let res = o_prot.write_list_begin(&TListIdentifier::new(TType::List, 9999)); assert!(res.is_ok()); let expected: [u8; 3] = [ 0xF9, /* 0xF0 | elem_type */ 0x8F, 0x4E, /* size as varint */ ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_large_sized_list_begin() { let (mut i_prot, mut o_prot) = test_objects(); let ident = TListIdentifier::new(TType::Set, 47381); assert_success!(o_prot.write_list_begin(&ident)); copy_write_buffer_to_read_buffer!(o_prot); let res = assert_success!(i_prot.read_list_begin()); assert_eq!(&res, &ident); } #[test] fn must_write_list_end() { assert_no_write(|o| o.write_list_end()); } #[test] fn must_write_small_sized_set_begin() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Struct, 2))); let expected: [u8; 1] = [0x2C /* size | elem_type */]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_small_sized_set_begin() { let (mut i_prot, mut o_prot) = test_objects(); let ident = TSetIdentifier::new(TType::I16, 7); assert_success!(o_prot.write_set_begin(&ident)); copy_write_buffer_to_read_buffer!(o_prot); let res = assert_success!(i_prot.read_set_begin()); assert_eq!(&res, &ident); } #[test] fn must_write_large_sized_set_begin() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Double, 23891))); let expected: [u8; 4] = [ 0xF7, /* 0xF0 | elem_type */ 0xD3, 0xBA, 0x01, /* size as varint */ ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_large_sized_set_begin() { let (mut i_prot, mut o_prot) = test_objects(); let ident = TSetIdentifier::new(TType::Map, 3_928_429); assert_success!(o_prot.write_set_begin(&ident)); copy_write_buffer_to_read_buffer!(o_prot); let res = assert_success!(i_prot.read_set_begin()); assert_eq!(&res, &ident); } #[test] fn must_write_set_end() { assert_no_write(|o| o.write_set_end()); } #[test] fn must_write_zero_sized_map_begin() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::String, TType::I32, 0))); let expected: [u8; 1] = [0x00]; // since size is zero we don't write anything assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_read_zero_sized_map_begin() { let (mut i_prot, mut o_prot) = test_objects(); assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::I32, 0))); copy_write_buffer_to_read_buffer!(o_prot); let res = assert_success!(i_prot.read_map_begin()); assert_eq!( &res, &TMapIdentifier { key_type: None, value_type: None, size: 0, } ); } #[test] fn must_write_map_begin() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_map_begin(&TMapIdentifier::new( TType::Double, TType::String, 238 ))); let expected: [u8; 3] = [ 0xEE, 0x01, /* size as varint */ 0x78, /* key type | val type */ ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_map_begin() { let (mut i_prot, mut o_prot) = test_objects(); let ident = TMapIdentifier::new(TType::Map, TType::List, 1_928_349); assert_success!(o_prot.write_map_begin(&ident)); copy_write_buffer_to_read_buffer!(o_prot); let res = assert_success!(i_prot.read_map_begin()); assert_eq!(&res, &ident); } #[test] fn must_write_map_end() { assert_no_write(|o| o.write_map_end()); } #[test] fn must_write_map_with_bool_key_and_value() { let (_, mut o_prot) = test_objects(); assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Bool, TType::Bool, 1))); assert_success!(o_prot.write_bool(true)); assert_success!(o_prot.write_bool(false)); assert_success!(o_prot.write_map_end()); let expected: [u8; 4] = [ 0x01, /* size as varint */ 0x11, /* key type | val type */ 0x01, /* key: true */ 0x02, /* val: false */ ]; assert_eq_written_bytes!(o_prot, expected); } #[test] fn must_round_trip_map_with_bool_value() { let (mut i_prot, mut o_prot) = test_objects(); let map_ident = TMapIdentifier::new(TType::Bool, TType::Bool, 2); assert_success!(o_prot.write_map_begin(&map_ident)); assert_success!(o_prot.write_bool(true)); assert_success!(o_prot.write_bool(false)); assert_success!(o_prot.write_bool(false)); assert_success!(o_prot.write_bool(true)); assert_success!(o_prot.write_map_end()); copy_write_buffer_to_read_buffer!(o_prot); // map header let rcvd_ident = assert_success!(i_prot.read_map_begin()); assert_eq!(&rcvd_ident, &map_ident); // key 1 let b = assert_success!(i_prot.read_bool()); assert_eq!(b, true); // val 1 let b = assert_success!(i_prot.read_bool()); assert_eq!(b, false); // key 2 let b = assert_success!(i_prot.read_bool()); assert_eq!(b, false); // val 2 let b = assert_success!(i_prot.read_bool()); assert_eq!(b, true); // map end assert_success!(i_prot.read_map_end()); } #[test] fn must_read_map_end() { let (mut i_prot, _) = test_objects(); assert!(i_prot.read_map_end().is_ok()); // will blow up if we try to read from empty buffer } fn test_objects() -> ( TCompactInputProtocol>, TCompactOutputProtocol>, ) { let mem = TBufferChannel::with_capacity(80, 80); let (r_mem, w_mem) = mem.split().unwrap(); let i_prot = TCompactInputProtocol::new(r_mem); let o_prot = TCompactOutputProtocol::new(w_mem); (i_prot, o_prot) } #[test] fn must_read_write_double() { let (mut i_prot, mut o_prot) = test_objects(); #[allow(clippy::approx_constant)] let double = 3.141_592_653_589_793; o_prot.write_double(double).unwrap(); copy_write_buffer_to_read_buffer!(o_prot); let read_double = i_prot.read_double().unwrap(); assert!(read_double - double < std::f64::EPSILON); } #[test] fn must_encode_double_as_other_langs() { let (_, mut o_prot) = test_objects(); let expected = [24, 45, 68, 84, 251, 33, 9, 64]; #[allow(clippy::approx_constant)] let double = 3.141_592_653_589_793; o_prot.write_double(double).unwrap(); assert_eq_written_bytes!(o_prot, expected); } fn assert_no_write(mut write_fn: F) where F: FnMut(&mut TCompactOutputProtocol>) -> crate::Result<()>, { let (_, mut o_prot) = test_objects(); assert!(write_fn(&mut o_prot).is_ok()); assert_eq!(o_prot.transport.write_bytes().len(), 0); } } thrift-0.16.0/lib/rs/src/protocol/mod.rs000066400000000000000000000753421420101504100200440ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. //! Types used to send and receive primitives between a Thrift client and server. //! //! # Examples //! //! Create and use a `TInputProtocol`. //! //! ```no_run //! use thrift::protocol::{TBinaryInputProtocol, TInputProtocol}; //! use thrift::transport::TTcpChannel; //! //! // create the I/O channel //! let mut channel = TTcpChannel::new(); //! channel.open("127.0.0.1:9090").unwrap(); //! //! // create the protocol to decode bytes into types //! let mut protocol = TBinaryInputProtocol::new(channel, true); //! //! // read types from the wire //! let field_identifier = protocol.read_field_begin().unwrap(); //! let field_contents = protocol.read_string().unwrap(); //! let field_end = protocol.read_field_end().unwrap(); //! ``` //! //! Create and use a `TOutputProtocol`. //! //! ```no_run //! use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType}; //! use thrift::transport::TTcpChannel; //! //! // create the I/O channel //! let mut channel = TTcpChannel::new(); //! channel.open("127.0.0.1:9090").unwrap(); //! //! // create the protocol to encode types into bytes //! let mut protocol = TBinaryOutputProtocol::new(channel, true); //! //! // write types //! protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap(); //! protocol.write_string("foo").unwrap(); //! protocol.write_field_end().unwrap(); //! ``` use std::convert::{From, TryFrom}; use std::fmt; use std::fmt::{Display, Formatter}; use crate::transport::{TReadTransport, TWriteTransport}; use crate::{ProtocolError, ProtocolErrorKind}; #[cfg(test)] macro_rules! assert_eq_written_bytes { ($o_prot:ident, $expected_bytes:ident) => {{ assert_eq!($o_prot.transport.write_bytes(), &$expected_bytes); }}; } // FIXME: should take both read and write #[cfg(test)] macro_rules! copy_write_buffer_to_read_buffer { ($o_prot:ident) => {{ $o_prot.transport.copy_write_buffer_to_read_buffer(); }}; } #[cfg(test)] macro_rules! set_readable_bytes { ($i_prot:ident, $bytes:expr) => { $i_prot.transport.set_readable_bytes($bytes); }; } mod binary; mod compact; mod multiplexed; mod stored; pub use self::binary::{ TBinaryInputProtocol, TBinaryInputProtocolFactory, TBinaryOutputProtocol, TBinaryOutputProtocolFactory, }; pub use self::compact::{ TCompactInputProtocol, TCompactInputProtocolFactory, TCompactOutputProtocol, TCompactOutputProtocolFactory, }; pub use self::multiplexed::TMultiplexedOutputProtocol; pub use self::stored::TStoredInputProtocol; // Default maximum depth to which `TInputProtocol::skip` will skip a Thrift // field. A default is necessary because Thrift structs or collections may // contain nested structs and collections, which could result in indefinite // recursion. const MAXIMUM_SKIP_DEPTH: i8 = 64; /// Converts a stream of bytes into Thrift identifiers, primitives, /// containers, or structs. /// /// This trait does not deal with higher-level Thrift concepts like structs or /// exceptions - only with primitives and message or container boundaries. Once /// bytes are read they are deserialized and an identifier (for example /// `TMessageIdentifier`) or a primitive is returned. /// /// All methods return a `thrift::Result`. If an `Err` is returned the protocol /// instance and its underlying transport should be terminated. /// /// # Examples /// /// Create and use a `TInputProtocol` /// /// ```no_run /// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("127.0.0.1:9090").unwrap(); /// /// let mut protocol = TBinaryInputProtocol::new(channel, true); /// /// let field_identifier = protocol.read_field_begin().unwrap(); /// let field_contents = protocol.read_string().unwrap(); /// let field_end = protocol.read_field_end().unwrap(); /// ``` pub trait TInputProtocol { /// Read the beginning of a Thrift message. fn read_message_begin(&mut self) -> crate::Result; /// Read the end of a Thrift message. fn read_message_end(&mut self) -> crate::Result<()>; /// Read the beginning of a Thrift struct. fn read_struct_begin(&mut self) -> crate::Result>; /// Read the end of a Thrift struct. fn read_struct_end(&mut self) -> crate::Result<()>; /// Read the beginning of a Thrift struct field. fn read_field_begin(&mut self) -> crate::Result; /// Read the end of a Thrift struct field. fn read_field_end(&mut self) -> crate::Result<()>; /// Read a bool. fn read_bool(&mut self) -> crate::Result; /// Read a fixed-length byte array. fn read_bytes(&mut self) -> crate::Result>; /// Read a word. fn read_i8(&mut self) -> crate::Result; /// Read a 16-bit signed integer. fn read_i16(&mut self) -> crate::Result; /// Read a 32-bit signed integer. fn read_i32(&mut self) -> crate::Result; /// Read a 64-bit signed integer. fn read_i64(&mut self) -> crate::Result; /// Read a 64-bit float. fn read_double(&mut self) -> crate::Result; /// Read a fixed-length string (not null terminated). fn read_string(&mut self) -> crate::Result; /// Read the beginning of a list. fn read_list_begin(&mut self) -> crate::Result; /// Read the end of a list. fn read_list_end(&mut self) -> crate::Result<()>; /// Read the beginning of a set. fn read_set_begin(&mut self) -> crate::Result; /// Read the end of a set. fn read_set_end(&mut self) -> crate::Result<()>; /// Read the beginning of a map. fn read_map_begin(&mut self) -> crate::Result; /// Read the end of a map. fn read_map_end(&mut self) -> crate::Result<()>; /// Skip a field with type `field_type` recursively until the default /// maximum skip depth is reached. fn skip(&mut self, field_type: TType) -> crate::Result<()> { self.skip_till_depth(field_type, MAXIMUM_SKIP_DEPTH) } /// Skip a field with type `field_type` recursively up to `depth` levels. fn skip_till_depth(&mut self, field_type: TType, depth: i8) -> crate::Result<()> { if depth == 0 { return Err(crate::Error::Protocol(ProtocolError { kind: ProtocolErrorKind::DepthLimit, message: format!("cannot parse past {:?}", field_type), })); } match field_type { TType::Bool => self.read_bool().map(|_| ()), TType::I08 => self.read_i8().map(|_| ()), TType::I16 => self.read_i16().map(|_| ()), TType::I32 => self.read_i32().map(|_| ()), TType::I64 => self.read_i64().map(|_| ()), TType::Double => self.read_double().map(|_| ()), TType::String => self.read_string().map(|_| ()), TType::Struct => { self.read_struct_begin()?; loop { let field_ident = self.read_field_begin()?; if field_ident.field_type == TType::Stop { break; } self.skip_till_depth(field_ident.field_type, depth - 1)?; } self.read_struct_end() } TType::List => { let list_ident = self.read_list_begin()?; for _ in 0..list_ident.size { self.skip_till_depth(list_ident.element_type, depth - 1)?; } self.read_list_end() } TType::Set => { let set_ident = self.read_set_begin()?; for _ in 0..set_ident.size { self.skip_till_depth(set_ident.element_type, depth - 1)?; } self.read_set_end() } TType::Map => { let map_ident = self.read_map_begin()?; for _ in 0..map_ident.size { let key_type = map_ident .key_type .expect("non-zero sized map should contain key type"); let val_type = map_ident .value_type .expect("non-zero sized map should contain value type"); self.skip_till_depth(key_type, depth - 1)?; self.skip_till_depth(val_type, depth - 1)?; } self.read_map_end() } u => Err(crate::Error::Protocol(ProtocolError { kind: ProtocolErrorKind::Unknown, message: format!("cannot skip field type {:?}", &u), })), } } // utility (DO NOT USE IN GENERATED CODE!!!!) // /// Read an unsigned byte. /// /// This method should **never** be used in generated code. fn read_byte(&mut self) -> crate::Result; } /// Converts Thrift identifiers, primitives, containers or structs into a /// stream of bytes. /// /// This trait does not deal with higher-level Thrift concepts like structs or /// exceptions - only with primitives and message or container boundaries. /// Write methods take an identifier (for example, `TMessageIdentifier`) or a /// primitive. Any or all of the fields in an identifier may be omitted when /// writing to the transport. Write methods may even be noops. All of this is /// transparent to the caller; as long as a matching `TInputProtocol` /// implementation is used, received messages will be decoded correctly. /// /// All methods return a `thrift::Result`. If an `Err` is returned the protocol /// instance and its underlying transport should be terminated. /// /// # Examples /// /// Create and use a `TOutputProtocol` /// /// ```no_run /// use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("127.0.0.1:9090").unwrap(); /// /// let mut protocol = TBinaryOutputProtocol::new(channel, true); /// /// protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap(); /// protocol.write_string("foo").unwrap(); /// protocol.write_field_end().unwrap(); /// ``` pub trait TOutputProtocol { /// Write the beginning of a Thrift message. fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> crate::Result<()>; /// Write the end of a Thrift message. fn write_message_end(&mut self) -> crate::Result<()>; /// Write the beginning of a Thrift struct. fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> crate::Result<()>; /// Write the end of a Thrift struct. fn write_struct_end(&mut self) -> crate::Result<()>; /// Write the beginning of a Thrift field. fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> crate::Result<()>; /// Write the end of a Thrift field. fn write_field_end(&mut self) -> crate::Result<()>; /// Write a STOP field indicating that all the fields in a struct have been /// written. fn write_field_stop(&mut self) -> crate::Result<()>; /// Write a bool. fn write_bool(&mut self, b: bool) -> crate::Result<()>; /// Write a fixed-length byte array. fn write_bytes(&mut self, b: &[u8]) -> crate::Result<()>; /// Write an 8-bit signed integer. fn write_i8(&mut self, i: i8) -> crate::Result<()>; /// Write a 16-bit signed integer. fn write_i16(&mut self, i: i16) -> crate::Result<()>; /// Write a 32-bit signed integer. fn write_i32(&mut self, i: i32) -> crate::Result<()>; /// Write a 64-bit signed integer. fn write_i64(&mut self, i: i64) -> crate::Result<()>; /// Write a 64-bit float. fn write_double(&mut self, d: f64) -> crate::Result<()>; /// Write a fixed-length string. fn write_string(&mut self, s: &str) -> crate::Result<()>; /// Write the beginning of a list. fn write_list_begin(&mut self, identifier: &TListIdentifier) -> crate::Result<()>; /// Write the end of a list. fn write_list_end(&mut self) -> crate::Result<()>; /// Write the beginning of a set. fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> crate::Result<()>; /// Write the end of a set. fn write_set_end(&mut self) -> crate::Result<()>; /// Write the beginning of a map. fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> crate::Result<()>; /// Write the end of a map. fn write_map_end(&mut self) -> crate::Result<()>; /// Flush buffered bytes to the underlying transport. fn flush(&mut self) -> crate::Result<()>; // utility (DO NOT USE IN GENERATED CODE!!!!) // /// Write an unsigned byte. /// /// This method should **never** be used in generated code. fn write_byte(&mut self, b: u8) -> crate::Result<()>; // FIXME: REMOVE } impl

TInputProtocol for Box

where P: TInputProtocol + ?Sized, { fn read_message_begin(&mut self) -> crate::Result { (**self).read_message_begin() } fn read_message_end(&mut self) -> crate::Result<()> { (**self).read_message_end() } fn read_struct_begin(&mut self) -> crate::Result> { (**self).read_struct_begin() } fn read_struct_end(&mut self) -> crate::Result<()> { (**self).read_struct_end() } fn read_field_begin(&mut self) -> crate::Result { (**self).read_field_begin() } fn read_field_end(&mut self) -> crate::Result<()> { (**self).read_field_end() } fn read_bool(&mut self) -> crate::Result { (**self).read_bool() } fn read_bytes(&mut self) -> crate::Result> { (**self).read_bytes() } fn read_i8(&mut self) -> crate::Result { (**self).read_i8() } fn read_i16(&mut self) -> crate::Result { (**self).read_i16() } fn read_i32(&mut self) -> crate::Result { (**self).read_i32() } fn read_i64(&mut self) -> crate::Result { (**self).read_i64() } fn read_double(&mut self) -> crate::Result { (**self).read_double() } fn read_string(&mut self) -> crate::Result { (**self).read_string() } fn read_list_begin(&mut self) -> crate::Result { (**self).read_list_begin() } fn read_list_end(&mut self) -> crate::Result<()> { (**self).read_list_end() } fn read_set_begin(&mut self) -> crate::Result { (**self).read_set_begin() } fn read_set_end(&mut self) -> crate::Result<()> { (**self).read_set_end() } fn read_map_begin(&mut self) -> crate::Result { (**self).read_map_begin() } fn read_map_end(&mut self) -> crate::Result<()> { (**self).read_map_end() } fn read_byte(&mut self) -> crate::Result { (**self).read_byte() } } impl

TOutputProtocol for Box

where P: TOutputProtocol + ?Sized, { fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> crate::Result<()> { (**self).write_message_begin(identifier) } fn write_message_end(&mut self) -> crate::Result<()> { (**self).write_message_end() } fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> crate::Result<()> { (**self).write_struct_begin(identifier) } fn write_struct_end(&mut self) -> crate::Result<()> { (**self).write_struct_end() } fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> crate::Result<()> { (**self).write_field_begin(identifier) } fn write_field_end(&mut self) -> crate::Result<()> { (**self).write_field_end() } fn write_field_stop(&mut self) -> crate::Result<()> { (**self).write_field_stop() } fn write_bool(&mut self, b: bool) -> crate::Result<()> { (**self).write_bool(b) } fn write_bytes(&mut self, b: &[u8]) -> crate::Result<()> { (**self).write_bytes(b) } fn write_i8(&mut self, i: i8) -> crate::Result<()> { (**self).write_i8(i) } fn write_i16(&mut self, i: i16) -> crate::Result<()> { (**self).write_i16(i) } fn write_i32(&mut self, i: i32) -> crate::Result<()> { (**self).write_i32(i) } fn write_i64(&mut self, i: i64) -> crate::Result<()> { (**self).write_i64(i) } fn write_double(&mut self, d: f64) -> crate::Result<()> { (**self).write_double(d) } fn write_string(&mut self, s: &str) -> crate::Result<()> { (**self).write_string(s) } fn write_list_begin(&mut self, identifier: &TListIdentifier) -> crate::Result<()> { (**self).write_list_begin(identifier) } fn write_list_end(&mut self) -> crate::Result<()> { (**self).write_list_end() } fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> crate::Result<()> { (**self).write_set_begin(identifier) } fn write_set_end(&mut self) -> crate::Result<()> { (**self).write_set_end() } fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> crate::Result<()> { (**self).write_map_begin(identifier) } fn write_map_end(&mut self) -> crate::Result<()> { (**self).write_map_end() } fn flush(&mut self) -> crate::Result<()> { (**self).flush() } fn write_byte(&mut self, b: u8) -> crate::Result<()> { (**self).write_byte(b) } } /// Helper type used by servers to create `TInputProtocol` instances for /// accepted client connections. /// /// # Examples /// /// Create a `TInputProtocolFactory` and use it to create a `TInputProtocol`. /// /// ```no_run /// use thrift::protocol::{TBinaryInputProtocolFactory, TInputProtocolFactory}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("127.0.0.1:9090").unwrap(); /// /// let factory = TBinaryInputProtocolFactory::new(); /// let protocol = factory.create(Box::new(channel)); /// ``` pub trait TInputProtocolFactory { // Create a `TInputProtocol` that reads bytes from `transport`. fn create(&self, transport: Box) -> Box; } impl TInputProtocolFactory for Box where T: TInputProtocolFactory + ?Sized, { fn create(&self, transport: Box) -> Box { (**self).create(transport) } } /// Helper type used by servers to create `TOutputProtocol` instances for /// accepted client connections. /// /// # Examples /// /// Create a `TOutputProtocolFactory` and use it to create a `TOutputProtocol`. /// /// ```no_run /// use thrift::protocol::{TBinaryOutputProtocolFactory, TOutputProtocolFactory}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("127.0.0.1:9090").unwrap(); /// /// let factory = TBinaryOutputProtocolFactory::new(); /// let protocol = factory.create(Box::new(channel)); /// ``` pub trait TOutputProtocolFactory { /// Create a `TOutputProtocol` that writes bytes to `transport`. fn create(&self, transport: Box) -> Box; } impl TOutputProtocolFactory for Box where T: TOutputProtocolFactory + ?Sized, { fn create( &self, transport: Box, ) -> Box { (**self).create(transport) } } /// Thrift message identifier. #[derive(Clone, Debug, Eq, PartialEq)] pub struct TMessageIdentifier { /// Service call the message is associated with. pub name: String, /// Message type. pub message_type: TMessageType, /// Ordered sequence number identifying the message. pub sequence_number: i32, } impl TMessageIdentifier { /// Create a `TMessageIdentifier` for a Thrift service-call named `name` /// with message type `message_type` and sequence number `sequence_number`. pub fn new>( name: S, message_type: TMessageType, sequence_number: i32, ) -> TMessageIdentifier { TMessageIdentifier { name: name.into(), message_type, sequence_number, } } } /// Thrift struct identifier. #[derive(Clone, Debug, Eq, PartialEq)] pub struct TStructIdentifier { /// Name of the encoded Thrift struct. pub name: String, } impl TStructIdentifier { /// Create a `TStructIdentifier` for a struct named `name`. pub fn new>(name: S) -> TStructIdentifier { TStructIdentifier { name: name.into() } } } /// Thrift field identifier. #[derive(Clone, Debug, Eq, PartialEq)] pub struct TFieldIdentifier { /// Name of the Thrift field. /// /// `None` if it's not sent over the wire. pub name: Option, /// Field type. /// /// This may be a primitive, container, or a struct. pub field_type: TType, /// Thrift field id. /// /// `None` only if `field_type` is `TType::Stop`. pub id: Option, } impl TFieldIdentifier { /// Create a `TFieldIdentifier` for a field named `name` with type /// `field_type` and field id `id`. /// /// `id` should be `None` if `field_type` is `TType::Stop`. pub fn new(name: N, field_type: TType, id: I) -> TFieldIdentifier where N: Into>, S: Into, I: Into>, { TFieldIdentifier { name: name.into().map(|n| n.into()), field_type, id: id.into(), } } } /// Thrift list identifier. #[derive(Clone, Debug, Eq, PartialEq)] pub struct TListIdentifier { /// Type of the elements in the list. pub element_type: TType, /// Number of elements in the list. pub size: i32, } impl TListIdentifier { /// Create a `TListIdentifier` for a list with `size` elements of type /// `element_type`. pub fn new(element_type: TType, size: i32) -> TListIdentifier { TListIdentifier { element_type, size } } } /// Thrift set identifier. #[derive(Clone, Debug, Eq, PartialEq)] pub struct TSetIdentifier { /// Type of the elements in the set. pub element_type: TType, /// Number of elements in the set. pub size: i32, } impl TSetIdentifier { /// Create a `TSetIdentifier` for a set with `size` elements of type /// `element_type`. pub fn new(element_type: TType, size: i32) -> TSetIdentifier { TSetIdentifier { element_type, size } } } /// Thrift map identifier. #[derive(Clone, Debug, Eq, PartialEq)] pub struct TMapIdentifier { /// Map key type. pub key_type: Option, /// Map value type. pub value_type: Option, /// Number of entries in the map. pub size: i32, } impl TMapIdentifier { /// Create a `TMapIdentifier` for a map with `size` entries of type /// `key_type -> value_type`. pub fn new(key_type: K, value_type: V, size: i32) -> TMapIdentifier where K: Into>, V: Into>, { TMapIdentifier { key_type: key_type.into(), value_type: value_type.into(), size, } } } /// Thrift message types. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum TMessageType { /// Service-call request. Call, /// Service-call response. Reply, /// Unexpected error in the remote service. Exception, /// One-way service-call request (no response is expected). OneWay, } impl Display for TMessageType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match *self { TMessageType::Call => write!(f, "Call"), TMessageType::Reply => write!(f, "Reply"), TMessageType::Exception => write!(f, "Exception"), TMessageType::OneWay => write!(f, "OneWay"), } } } impl From for u8 { fn from(message_type: TMessageType) -> Self { match message_type { TMessageType::Call => 0x01, TMessageType::Reply => 0x02, TMessageType::Exception => 0x03, TMessageType::OneWay => 0x04, } } } impl TryFrom for TMessageType { type Error = crate::Error; fn try_from(b: u8) -> Result { match b { 0x01 => Ok(TMessageType::Call), 0x02 => Ok(TMessageType::Reply), 0x03 => Ok(TMessageType::Exception), 0x04 => Ok(TMessageType::OneWay), unkn => Err(crate::Error::Protocol(ProtocolError { kind: ProtocolErrorKind::InvalidData, message: format!("cannot convert {} to TMessageType", unkn), })), } } } /// Thrift struct-field types. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum TType { /// Indicates that there are no more serialized fields in this Thrift struct. Stop, /// Void (`()`) field. Void, /// Boolean. Bool, /// Signed 8-bit int. I08, /// Double-precision number. Double, /// Signed 16-bit int. I16, /// Signed 32-bit int. I32, /// Signed 64-bit int. I64, /// UTF-8 string. String, /// UTF-7 string. *Unsupported*. Utf7, /// Thrift struct. Struct, /// Map. Map, /// Set. Set, /// List. List, /// UTF-8 string. Utf8, /// UTF-16 string. *Unsupported*. Utf16, } impl Display for TType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match *self { TType::Stop => write!(f, "STOP"), TType::Void => write!(f, "void"), TType::Bool => write!(f, "bool"), TType::I08 => write!(f, "i08"), TType::Double => write!(f, "double"), TType::I16 => write!(f, "i16"), TType::I32 => write!(f, "i32"), TType::I64 => write!(f, "i64"), TType::String => write!(f, "string"), TType::Utf7 => write!(f, "UTF7"), TType::Struct => write!(f, "struct"), TType::Map => write!(f, "map"), TType::Set => write!(f, "set"), TType::List => write!(f, "list"), TType::Utf8 => write!(f, "UTF8"), TType::Utf16 => write!(f, "UTF16"), } } } /// Compare the expected message sequence number `expected` with the received /// message sequence number `actual`. /// /// Return `()` if `actual == expected`, `Err` otherwise. pub fn verify_expected_sequence_number(expected: i32, actual: i32) -> crate::Result<()> { if expected == actual { Ok(()) } else { Err(crate::Error::Application(crate::ApplicationError { kind: crate::ApplicationErrorKind::BadSequenceId, message: format!("expected {} got {}", expected, actual), })) } } /// Compare the expected service-call name `expected` with the received /// service-call name `actual`. /// /// Return `()` if `actual == expected`, `Err` otherwise. pub fn verify_expected_service_call(expected: &str, actual: &str) -> crate::Result<()> { if expected == actual { Ok(()) } else { Err(crate::Error::Application(crate::ApplicationError { kind: crate::ApplicationErrorKind::WrongMethodName, message: format!("expected {} got {}", expected, actual), })) } } /// Compare the expected message type `expected` with the received message type /// `actual`. /// /// Return `()` if `actual == expected`, `Err` otherwise. pub fn verify_expected_message_type( expected: TMessageType, actual: TMessageType, ) -> crate::Result<()> { if expected == actual { Ok(()) } else { Err(crate::Error::Application(crate::ApplicationError { kind: crate::ApplicationErrorKind::InvalidMessageType, message: format!("expected {} got {}", expected, actual), })) } } /// Check if a required Thrift struct field exists. /// /// Return `()` if it does, `Err` otherwise. pub fn verify_required_field_exists(field_name: &str, field: &Option) -> crate::Result<()> { match *field { Some(_) => Ok(()), None => Err(crate::Error::Protocol(crate::ProtocolError { kind: crate::ProtocolErrorKind::Unknown, message: format!("missing required field {}", field_name), })), } } /// Extract the field id from a Thrift field identifier. /// /// `field_ident` must *not* have `TFieldIdentifier.field_type` of type `TType::Stop`. /// /// Return `TFieldIdentifier.id` if an id exists, `Err` otherwise. pub fn field_id(field_ident: &TFieldIdentifier) -> crate::Result { field_ident.id.ok_or_else(|| { crate::Error::Protocol(crate::ProtocolError { kind: crate::ProtocolErrorKind::Unknown, message: format!("missing field in in {:?}", field_ident), }) }) } #[cfg(test)] mod tests { use std::io::Cursor; use super::*; use crate::transport::{TReadTransport, TWriteTransport}; #[test] fn must_create_usable_input_protocol_from_concrete_input_protocol() { let r: Box = Box::new(Cursor::new([0, 1, 2])); let mut t = TCompactInputProtocol::new(r); takes_input_protocol(&mut t) } #[test] fn must_create_usable_input_protocol_from_boxed_input() { let r: Box = Box::new(Cursor::new([0, 1, 2])); let mut t: Box = Box::new(TCompactInputProtocol::new(r)); takes_input_protocol(&mut t) } #[test] fn must_create_usable_output_protocol_from_concrete_output_protocol() { let w: Box = Box::new(vec![0u8; 10]); let mut t = TCompactOutputProtocol::new(w); takes_output_protocol(&mut t) } #[test] fn must_create_usable_output_protocol_from_boxed_output() { let w: Box = Box::new(vec![0u8; 10]); let mut t: Box = Box::new(TCompactOutputProtocol::new(w)); takes_output_protocol(&mut t) } fn takes_input_protocol(t: &mut R) where R: TInputProtocol, { t.read_byte().unwrap(); } fn takes_output_protocol(t: &mut W) where W: TOutputProtocol, { t.flush().unwrap(); } } thrift-0.16.0/lib/rs/src/protocol/multiplexed.rs000066400000000000000000000167061420101504100216200ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use super::{ TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TOutputProtocol, TSetIdentifier, TStructIdentifier, }; /// `TOutputProtocol` that prefixes the service name to all outgoing Thrift /// messages. /// /// A `TMultiplexedOutputProtocol` should be used when multiple Thrift services /// send messages over a single I/O channel. By prefixing service identifiers /// to outgoing messages receivers are able to demux them and route them to the /// appropriate service processor. Rust receivers must use a `TMultiplexedProcessor` /// to process incoming messages, while other languages must use their /// corresponding multiplexed processor implementations. /// /// For example, given a service `TestService` and a service call `test_call`, /// this implementation would identify messages as originating from /// `TestService:test_call`. /// /// # Examples /// /// Create and use a `TMultiplexedOutputProtocol`. /// /// ```no_run /// use thrift::protocol::{TMessageIdentifier, TMessageType, TOutputProtocol}; /// use thrift::protocol::{TBinaryOutputProtocol, TMultiplexedOutputProtocol}; /// use thrift::transport::TTcpChannel; /// /// let mut channel = TTcpChannel::new(); /// channel.open("localhost:9090").unwrap(); /// /// let protocol = TBinaryOutputProtocol::new(channel, true); /// let mut protocol = TMultiplexedOutputProtocol::new("service_name", protocol); /// /// let ident = TMessageIdentifier::new("svc_call", TMessageType::Call, 1); /// protocol.write_message_begin(&ident).unwrap(); /// ``` #[derive(Debug)] pub struct TMultiplexedOutputProtocol

where P: TOutputProtocol, { service_name: String, inner: P, } impl

TMultiplexedOutputProtocol

where P: TOutputProtocol, { /// Create a `TMultiplexedOutputProtocol` that identifies outgoing messages /// as originating from a service named `service_name` and sends them over /// the `wrapped` `TOutputProtocol`. Outgoing messages are encoded and sent /// by `wrapped`, not by this instance. pub fn new(service_name: &str, wrapped: P) -> TMultiplexedOutputProtocol

{ TMultiplexedOutputProtocol { service_name: service_name.to_owned(), inner: wrapped, } } } // FIXME: avoid passthrough methods impl

TOutputProtocol for TMultiplexedOutputProtocol

where P: TOutputProtocol, { fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> crate::Result<()> { match identifier.message_type { // FIXME: is there a better way to override identifier here? TMessageType::Call | TMessageType::OneWay => { let identifier = TMessageIdentifier { name: format!("{}:{}", self.service_name, identifier.name), ..*identifier }; self.inner.write_message_begin(&identifier) } _ => self.inner.write_message_begin(identifier), } } fn write_message_end(&mut self) -> crate::Result<()> { self.inner.write_message_end() } fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> crate::Result<()> { self.inner.write_struct_begin(identifier) } fn write_struct_end(&mut self) -> crate::Result<()> { self.inner.write_struct_end() } fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> crate::Result<()> { self.inner.write_field_begin(identifier) } fn write_field_end(&mut self) -> crate::Result<()> { self.inner.write_field_end() } fn write_field_stop(&mut self) -> crate::Result<()> { self.inner.write_field_stop() } fn write_bytes(&mut self, b: &[u8]) -> crate::Result<()> { self.inner.write_bytes(b) } fn write_bool(&mut self, b: bool) -> crate::Result<()> { self.inner.write_bool(b) } fn write_i8(&mut self, i: i8) -> crate::Result<()> { self.inner.write_i8(i) } fn write_i16(&mut self, i: i16) -> crate::Result<()> { self.inner.write_i16(i) } fn write_i32(&mut self, i: i32) -> crate::Result<()> { self.inner.write_i32(i) } fn write_i64(&mut self, i: i64) -> crate::Result<()> { self.inner.write_i64(i) } fn write_double(&mut self, d: f64) -> crate::Result<()> { self.inner.write_double(d) } fn write_string(&mut self, s: &str) -> crate::Result<()> { self.inner.write_string(s) } fn write_list_begin(&mut self, identifier: &TListIdentifier) -> crate::Result<()> { self.inner.write_list_begin(identifier) } fn write_list_end(&mut self) -> crate::Result<()> { self.inner.write_list_end() } fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> crate::Result<()> { self.inner.write_set_begin(identifier) } fn write_set_end(&mut self) -> crate::Result<()> { self.inner.write_set_end() } fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> crate::Result<()> { self.inner.write_map_begin(identifier) } fn write_map_end(&mut self) -> crate::Result<()> { self.inner.write_map_end() } fn flush(&mut self) -> crate::Result<()> { self.inner.flush() } // utility // fn write_byte(&mut self, b: u8) -> crate::Result<()> { self.inner.write_byte(b) } } #[cfg(test)] mod tests { use crate::protocol::{ TBinaryOutputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol, }; use crate::transport::{TBufferChannel, TIoChannel, WriteHalf}; use super::*; #[test] fn must_write_message_begin_with_prefixed_service_name() { let mut o_prot = test_objects(); let ident = TMessageIdentifier::new("bar", TMessageType::Call, 2); assert_success!(o_prot.write_message_begin(&ident)); #[rustfmt::skip] let expected: [u8; 19] = [ 0x80, 0x01, /* protocol identifier */ 0x00, 0x01, /* message type */ 0x00, 0x00, 0x00, 0x07, 0x66, 0x6F, 0x6F, /* "foo" */ 0x3A, /* ":" */ 0x62, 0x61, 0x72, /* "bar" */ 0x00, 0x00, 0x00, 0x02 /* sequence number */, ]; assert_eq!(o_prot.inner.transport.write_bytes(), expected); } fn test_objects() -> TMultiplexedOutputProtocol>> { let c = TBufferChannel::with_capacity(40, 40); let (_, w_chan) = c.split().unwrap(); let prot = TBinaryOutputProtocol::new(w_chan, true); TMultiplexedOutputProtocol::new("foo", prot) } } thrift-0.16.0/lib/rs/src/protocol/stored.rs000066400000000000000000000144051420101504100205560ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::convert::Into; use super::{ TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier, TSetIdentifier, TStructIdentifier, }; use crate::ProtocolErrorKind; /// `TInputProtocol` required to use a `TMultiplexedProcessor`. /// /// A `TMultiplexedProcessor` reads incoming message identifiers to determine to /// which `TProcessor` requests should be forwarded. However, once read, those /// message identifier bytes are no longer on the wire. Since downstream /// processors expect to read message identifiers from the given input protocol /// we need some way of supplying a `TMessageIdentifier` with the service-name /// stripped. This implementation stores the received `TMessageIdentifier` /// (without the service name) and passes it to the wrapped `TInputProtocol` /// when `TInputProtocol::read_message_begin(...)` is called. It delegates all /// other calls directly to the wrapped `TInputProtocol`. /// /// This type **should not** be used by application code. /// /// # Examples /// /// Create and use a `TStoredInputProtocol`. /// /// ```no_run /// use thrift::protocol::{TInputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol}; /// use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TStoredInputProtocol}; /// use thrift::server::TProcessor; /// use thrift::transport::{TIoChannel, TTcpChannel}; /// /// // sample processor /// struct ActualProcessor; /// impl TProcessor for ActualProcessor { /// fn process( /// &self, /// _: &mut dyn TInputProtocol, /// _: &mut dyn TOutputProtocol /// ) -> thrift::Result<()> { /// unimplemented!() /// } /// } /// let processor = ActualProcessor {}; /// /// // construct the shared transport /// let mut channel = TTcpChannel::new(); /// channel.open("localhost:9090").unwrap(); /// /// let (i_chan, o_chan) = channel.split().unwrap(); /// /// // construct the actual input and output protocols /// let mut i_prot = TBinaryInputProtocol::new(i_chan, true); /// let mut o_prot = TBinaryOutputProtocol::new(o_chan, true); /// /// // message identifier received from remote and modified to remove the service name /// let new_msg_ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1); /// /// // construct the proxy input protocol /// let mut proxy_i_prot = TStoredInputProtocol::new(&mut i_prot, new_msg_ident); /// let res = processor.process(&mut proxy_i_prot, &mut o_prot); /// ``` // FIXME: implement Debug pub struct TStoredInputProtocol<'a> { inner: &'a mut dyn TInputProtocol, message_ident: Option, } impl<'a> TStoredInputProtocol<'a> { /// Create a `TStoredInputProtocol` that delegates all calls other than /// `TInputProtocol::read_message_begin(...)` to a `wrapped` /// `TInputProtocol`. `message_ident` is the modified message identifier - /// with service name stripped - that will be passed to /// `wrapped.read_message_begin(...)`. pub fn new( wrapped: &mut dyn TInputProtocol, message_ident: TMessageIdentifier, ) -> TStoredInputProtocol<'_> { TStoredInputProtocol { inner: wrapped, message_ident: message_ident.into(), } } } impl<'a> TInputProtocol for TStoredInputProtocol<'a> { fn read_message_begin(&mut self) -> crate::Result { self.message_ident.take().ok_or_else(|| { crate::errors::new_protocol_error( ProtocolErrorKind::Unknown, "message identifier already read", ) }) } fn read_message_end(&mut self) -> crate::Result<()> { self.inner.read_message_end() } fn read_struct_begin(&mut self) -> crate::Result> { self.inner.read_struct_begin() } fn read_struct_end(&mut self) -> crate::Result<()> { self.inner.read_struct_end() } fn read_field_begin(&mut self) -> crate::Result { self.inner.read_field_begin() } fn read_field_end(&mut self) -> crate::Result<()> { self.inner.read_field_end() } fn read_bytes(&mut self) -> crate::Result> { self.inner.read_bytes() } fn read_bool(&mut self) -> crate::Result { self.inner.read_bool() } fn read_i8(&mut self) -> crate::Result { self.inner.read_i8() } fn read_i16(&mut self) -> crate::Result { self.inner.read_i16() } fn read_i32(&mut self) -> crate::Result { self.inner.read_i32() } fn read_i64(&mut self) -> crate::Result { self.inner.read_i64() } fn read_double(&mut self) -> crate::Result { self.inner.read_double() } fn read_string(&mut self) -> crate::Result { self.inner.read_string() } fn read_list_begin(&mut self) -> crate::Result { self.inner.read_list_begin() } fn read_list_end(&mut self) -> crate::Result<()> { self.inner.read_list_end() } fn read_set_begin(&mut self) -> crate::Result { self.inner.read_set_begin() } fn read_set_end(&mut self) -> crate::Result<()> { self.inner.read_set_end() } fn read_map_begin(&mut self) -> crate::Result { self.inner.read_map_begin() } fn read_map_end(&mut self) -> crate::Result<()> { self.inner.read_map_end() } // utility // fn read_byte(&mut self) -> crate::Result { self.inner.read_byte() } } thrift-0.16.0/lib/rs/src/server/000077500000000000000000000000001420101504100163515ustar00rootroot00000000000000thrift-0.16.0/lib/rs/src/server/mod.rs000066400000000000000000000101621420101504100174760ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. //! Types used to implement a Thrift server. use crate::protocol::{TInputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol}; use crate::{ApplicationError, ApplicationErrorKind}; mod multiplexed; mod threaded; pub use self::multiplexed::TMultiplexedProcessor; pub use self::threaded::TServer; /// Handles incoming Thrift messages and dispatches them to the user-defined /// handler functions. /// /// An implementation is auto-generated for each Thrift service. When used by a /// server (for example, a `TSimpleServer`), it will demux incoming service /// calls and invoke the corresponding user-defined handler function. /// /// # Examples /// /// Create and start a server using the auto-generated `TProcessor` for /// a Thrift service `SimpleService`. /// /// ```no_run /// use thrift::protocol::{TInputProtocol, TOutputProtocol}; /// use thrift::server::TProcessor; /// /// // /// // auto-generated /// // /// /// // processor for `SimpleService` /// struct SimpleServiceSyncProcessor; /// impl SimpleServiceSyncProcessor { /// fn new(processor: H) -> SimpleServiceSyncProcessor { /// unimplemented!(); /// } /// } /// /// // `TProcessor` implementation for `SimpleService` /// impl TProcessor for SimpleServiceSyncProcessor { /// fn process(&self, i: &mut dyn TInputProtocol, o: &mut dyn TOutputProtocol) -> thrift::Result<()> { /// unimplemented!(); /// } /// } /// /// // service functions for SimpleService /// trait SimpleServiceSyncHandler { /// fn service_call(&self) -> thrift::Result<()>; /// } /// /// // /// // user-code follows /// // /// /// // define a handler that will be invoked when `service_call` is received /// struct SimpleServiceHandlerImpl; /// impl SimpleServiceSyncHandler for SimpleServiceHandlerImpl { /// fn service_call(&self) -> thrift::Result<()> { /// unimplemented!(); /// } /// } /// /// // instantiate the processor /// let processor = SimpleServiceSyncProcessor::new(SimpleServiceHandlerImpl {}); /// /// // at this point you can pass the processor to the server /// // let server = TServer::new(..., processor); /// ``` pub trait TProcessor { /// Process a Thrift service call. /// /// Reads arguments from `i`, executes the user's handler code, and writes /// the response to `o`. /// /// Returns `()` if the handler was executed; `Err` otherwise. fn process(&self, i: &mut dyn TInputProtocol, o: &mut dyn TOutputProtocol) -> crate::Result<()>; } /// Convenience function used in generated `TProcessor` implementations to /// return an `ApplicationError` if thrift message processing failed. pub fn handle_process_result( msg_ident: &TMessageIdentifier, res: crate::Result<()>, o_prot: &mut dyn TOutputProtocol, ) -> crate::Result<()> { if let Err(e) = res { let e = match e { crate::Error::Application(a) => a, _ => ApplicationError::new(ApplicationErrorKind::Unknown, format!("{:?}", e)), }; let ident = TMessageIdentifier::new( msg_ident.name.clone(), TMessageType::Exception, msg_ident.sequence_number, ); o_prot.write_message_begin(&ident)?; crate::Error::write_application_error_to_out_protocol(&e, o_prot)?; o_prot.write_message_end()?; o_prot.flush() } else { Ok(()) } } thrift-0.16.0/lib/rs/src/server/multiplexed.rs000066400000000000000000000312561420101504100212620ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use log::debug; use std::collections::HashMap; use std::convert::Into; use std::fmt; use std::fmt::{Debug, Formatter}; use std::sync::{Arc, Mutex}; use crate::protocol::{TInputProtocol, TMessageIdentifier, TOutputProtocol, TStoredInputProtocol}; use super::{handle_process_result, TProcessor}; const MISSING_SEPARATOR_AND_NO_DEFAULT: &str = "missing service separator and no default processor set"; type ThreadSafeProcessor = Box; /// A `TProcessor` that can demux service calls to multiple underlying /// Thrift services. /// /// Users register service-specific `TProcessor` instances with a /// `TMultiplexedProcessor`, and then register that processor with a server /// implementation. Following that, all incoming service calls are automatically /// routed to the service-specific `TProcessor`. /// /// A `TMultiplexedProcessor` can only handle messages sent by a /// `TMultiplexedOutputProtocol`. #[derive(Default)] pub struct TMultiplexedProcessor { stored: Mutex, } #[derive(Default)] struct StoredProcessors { processors: HashMap>, default_processor: Option>, } impl TMultiplexedProcessor { /// Create a new `TMultiplexedProcessor` with no registered service-specific /// processors. pub fn new() -> TMultiplexedProcessor { TMultiplexedProcessor { stored: Mutex::new(StoredProcessors { processors: HashMap::new(), default_processor: None, }), } } /// Register a service-specific `processor` for the service named /// `service_name`. This implementation is also backwards-compatible with /// non-multiplexed clients. Set `as_default` to `true` to allow /// non-namespaced requests to be dispatched to a default processor. /// /// Returns success if a new entry was inserted. Returns an error if: /// * A processor exists for `service_name` /// * You attempt to register a processor as default, and an existing default exists #[allow(clippy::map_entry)] pub fn register>( &mut self, service_name: S, processor: Box, as_default: bool, ) -> crate::Result<()> { let mut stored = self.stored.lock().unwrap(); let name = service_name.into(); if !stored.processors.contains_key(&name) { let processor = Arc::new(processor); if as_default { if stored.default_processor.is_none() { stored.processors.insert(name, processor.clone()); stored.default_processor = Some(processor.clone()); Ok(()) } else { Err("cannot reset default processor".into()) } } else { stored.processors.insert(name, processor); Ok(()) } } else { Err(format!("cannot overwrite existing processor for service {}", name).into()) } } fn process_message( &self, msg_ident: &TMessageIdentifier, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol, ) -> crate::Result<()> { let (svc_name, svc_call) = split_ident_name(&msg_ident.name); debug!("routing svc_name {:?} svc_call {}", &svc_name, &svc_call); let processor: Option> = { let stored = self.stored.lock().unwrap(); if let Some(name) = svc_name { stored.processors.get(name).cloned() } else { stored.default_processor.clone() } }; match processor { Some(arc) => { let new_msg_ident = TMessageIdentifier::new( svc_call, msg_ident.message_type, msg_ident.sequence_number, ); let mut proxy_i_prot = TStoredInputProtocol::new(i_prot, new_msg_ident); (*arc).process(&mut proxy_i_prot, o_prot) } None => Err(missing_processor_message(svc_name).into()), } } } impl TProcessor for TMultiplexedProcessor { fn process( &self, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol, ) -> crate::Result<()> { let msg_ident = i_prot.read_message_begin()?; debug!("process incoming msg id:{:?}", &msg_ident); let res = self.process_message(&msg_ident, i_prot, o_prot); handle_process_result(&msg_ident, res, o_prot) } } impl Debug for TMultiplexedProcessor { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let stored = self.stored.lock().unwrap(); write!( f, "TMultiplexedProcess {{ registered_count: {:?} default: {:?} }}", stored.processors.keys().len(), stored.default_processor.is_some() ) } } fn split_ident_name(ident_name: &str) -> (Option<&str>, &str) { ident_name .find(':') .map(|pos| { let (svc_name, svc_call) = ident_name.split_at(pos); let (_, svc_call) = svc_call.split_at(1); // remove colon from service call name (Some(svc_name), svc_call) }) .or_else(|| Some((None, ident_name))) .unwrap() } fn missing_processor_message(svc_name: Option<&str>) -> String { match svc_name { Some(name) => format!("no processor found for service {}", name), None => MISSING_SEPARATOR_AND_NO_DEFAULT.to_owned(), } } #[cfg(test)] mod tests { use std::convert::Into; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use crate::protocol::{ TBinaryInputProtocol, TBinaryOutputProtocol, TMessageIdentifier, TMessageType, }; use crate::transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf}; use crate::{ApplicationError, ApplicationErrorKind}; use super::*; #[test] fn should_split_name_into_proper_separator_and_service_call() { let ident_name = "foo:bar_call"; let (serv, call) = split_ident_name(&ident_name); assert_eq!(serv, Some("foo")); assert_eq!(call, "bar_call"); } #[test] fn should_return_full_ident_if_no_separator_exists() { let ident_name = "bar_call"; let (serv, call) = split_ident_name(&ident_name); assert_eq!(serv, None); assert_eq!(call, "bar_call"); } #[test] fn should_write_error_if_no_separator_found_and_no_default_processor_exists() { let (mut i, mut o) = build_objects(); let sent_ident = TMessageIdentifier::new("foo", TMessageType::Call, 10); o.write_message_begin(&sent_ident).unwrap(); o.flush().unwrap(); o.transport.copy_write_buffer_to_read_buffer(); o.transport.empty_write_buffer(); let p = TMultiplexedProcessor::new(); p.process(&mut i, &mut o).unwrap(); // at this point an error should be written out i.transport.set_readable_bytes(&o.transport.write_bytes()); let rcvd_ident = i.read_message_begin().unwrap(); let expected_ident = TMessageIdentifier::new("foo", TMessageType::Exception, 10); assert_eq!(rcvd_ident, expected_ident); let rcvd_err = crate::Error::read_application_error_from_in_protocol(&mut i).unwrap(); let expected_err = ApplicationError::new( ApplicationErrorKind::Unknown, MISSING_SEPARATOR_AND_NO_DEFAULT, ); assert_eq!(rcvd_err, expected_err); } #[test] fn should_write_error_if_separator_exists_and_no_processor_found() { let (mut i, mut o) = build_objects(); let sent_ident = TMessageIdentifier::new("missing:call", TMessageType::Call, 10); o.write_message_begin(&sent_ident).unwrap(); o.flush().unwrap(); o.transport.copy_write_buffer_to_read_buffer(); o.transport.empty_write_buffer(); let p = TMultiplexedProcessor::new(); p.process(&mut i, &mut o).unwrap(); // at this point an error should be written out i.transport.set_readable_bytes(&o.transport.write_bytes()); let rcvd_ident = i.read_message_begin().unwrap(); let expected_ident = TMessageIdentifier::new("missing:call", TMessageType::Exception, 10); assert_eq!(rcvd_ident, expected_ident); let rcvd_err = crate::Error::read_application_error_from_in_protocol(&mut i).unwrap(); let expected_err = ApplicationError::new( ApplicationErrorKind::Unknown, missing_processor_message(Some("missing")), ); assert_eq!(rcvd_err, expected_err); } #[derive(Default)] struct Service { pub invoked: Arc, } impl TProcessor for Service { fn process( &self, _: &mut dyn TInputProtocol, _: &mut dyn TOutputProtocol, ) -> crate::Result<()> { let res = self .invoked .compare_and_swap(false, true, Ordering::Relaxed); if res { Ok(()) } else { Err("failed swap".into()) } } } #[test] fn should_route_call_to_correct_processor() { let (mut i, mut o) = build_objects(); // build the services let svc_1 = Service { invoked: Arc::new(AtomicBool::new(false)), }; let atm_1 = svc_1.invoked.clone(); let svc_2 = Service { invoked: Arc::new(AtomicBool::new(false)), }; let atm_2 = svc_2.invoked.clone(); // register them let mut p = TMultiplexedProcessor::new(); p.register("service_1", Box::new(svc_1), false).unwrap(); p.register("service_2", Box::new(svc_2), false).unwrap(); // make the service call let sent_ident = TMessageIdentifier::new("service_1:call", TMessageType::Call, 10); o.write_message_begin(&sent_ident).unwrap(); o.flush().unwrap(); o.transport.copy_write_buffer_to_read_buffer(); o.transport.empty_write_buffer(); p.process(&mut i, &mut o).unwrap(); // service 1 should have been invoked, not service 2 assert_eq!(atm_1.load(Ordering::Relaxed), true); assert_eq!(atm_2.load(Ordering::Relaxed), false); } #[test] fn should_route_call_to_correct_processor_if_no_separator_exists_and_default_processor_set() { let (mut i, mut o) = build_objects(); // build the services let svc_1 = Service { invoked: Arc::new(AtomicBool::new(false)), }; let atm_1 = svc_1.invoked.clone(); let svc_2 = Service { invoked: Arc::new(AtomicBool::new(false)), }; let atm_2 = svc_2.invoked.clone(); // register them let mut p = TMultiplexedProcessor::new(); p.register("service_1", Box::new(svc_1), false).unwrap(); p.register("service_2", Box::new(svc_2), true).unwrap(); // second processor is default // make the service call (it's an old client, so we have to be backwards compatible) let sent_ident = TMessageIdentifier::new("old_call", TMessageType::Call, 10); o.write_message_begin(&sent_ident).unwrap(); o.flush().unwrap(); o.transport.copy_write_buffer_to_read_buffer(); o.transport.empty_write_buffer(); p.process(&mut i, &mut o).unwrap(); // service 2 should have been invoked, not service 1 assert_eq!(atm_1.load(Ordering::Relaxed), false); assert_eq!(atm_2.load(Ordering::Relaxed), true); } fn build_objects() -> ( TBinaryInputProtocol>, TBinaryOutputProtocol>, ) { let c = TBufferChannel::with_capacity(128, 128); let (r_c, w_c) = c.split().unwrap(); ( TBinaryInputProtocol::new(r_c, true), TBinaryOutputProtocol::new(w_c, true), ) } } thrift-0.16.0/lib/rs/src/server/threaded.rs000066400000000000000000000213361420101504100205040ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use log::warn; use std::net::{TcpListener, TcpStream, ToSocketAddrs}; use std::sync::Arc; use threadpool::ThreadPool; use crate::protocol::{ TInputProtocol, TInputProtocolFactory, TOutputProtocol, TOutputProtocolFactory, }; use crate::transport::{TIoChannel, TReadTransportFactory, TTcpChannel, TWriteTransportFactory}; use crate::{ApplicationError, ApplicationErrorKind}; use super::TProcessor; use crate::TransportErrorKind; /// Fixed-size thread-pool blocking Thrift server. /// /// A `TServer` listens on a given address and submits accepted connections /// to an **unbounded** queue. Connections from this queue are serviced by /// the first available worker thread from a **fixed-size** thread pool. Each /// accepted connection is handled by that worker thread, and communication /// over this thread occurs sequentially and synchronously (i.e. calls block). /// Accepted connections have an input half and an output half, each of which /// uses a `TTransport` and `TInputProtocol`/`TOutputProtocol` to translate /// messages to and from byes. Any combination of `TInputProtocol`, `TOutputProtocol` /// and `TTransport` may be used. /// /// # Examples /// /// Creating and running a `TServer` using Thrift-compiler-generated /// service code. /// /// ```no_run /// use thrift::protocol::{TInputProtocolFactory, TOutputProtocolFactory}; /// use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory}; /// use thrift::protocol::{TInputProtocol, TOutputProtocol}; /// use thrift::transport::{TBufferedReadTransportFactory, TBufferedWriteTransportFactory, /// TReadTransportFactory, TWriteTransportFactory}; /// use thrift::server::{TProcessor, TServer}; /// /// // /// // auto-generated /// // /// /// // processor for `SimpleService` /// struct SimpleServiceSyncProcessor; /// impl SimpleServiceSyncProcessor { /// fn new(processor: H) -> SimpleServiceSyncProcessor { /// unimplemented!(); /// } /// } /// /// // `TProcessor` implementation for `SimpleService` /// impl TProcessor for SimpleServiceSyncProcessor { /// fn process(&self, i: &mut dyn TInputProtocol, o: &mut dyn TOutputProtocol) -> thrift::Result<()> { /// unimplemented!(); /// } /// } /// /// // service functions for SimpleService /// trait SimpleServiceSyncHandler { /// fn service_call(&self) -> thrift::Result<()>; /// } /// /// // /// // user-code follows /// // /// /// // define a handler that will be invoked when `service_call` is received /// struct SimpleServiceHandlerImpl; /// impl SimpleServiceSyncHandler for SimpleServiceHandlerImpl { /// fn service_call(&self) -> thrift::Result<()> { /// unimplemented!(); /// } /// } /// /// // instantiate the processor /// let processor = SimpleServiceSyncProcessor::new(SimpleServiceHandlerImpl {}); /// /// // instantiate the server /// let i_tr_fact: Box = Box::new(TBufferedReadTransportFactory::new()); /// let i_pr_fact: Box = Box::new(TBinaryInputProtocolFactory::new()); /// let o_tr_fact: Box = Box::new(TBufferedWriteTransportFactory::new()); /// let o_pr_fact: Box = Box::new(TBinaryOutputProtocolFactory::new()); /// /// let mut server = TServer::new( /// i_tr_fact, /// i_pr_fact, /// o_tr_fact, /// o_pr_fact, /// processor, /// 10 /// ); /// /// // start listening for incoming connections /// match server.listen("127.0.0.1:8080") { /// Ok(_) => println!("listen completed"), /// Err(e) => println!("listen failed with error {:?}", e), /// } /// ``` #[derive(Debug)] pub struct TServer where PRC: TProcessor + Send + Sync + 'static, RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static, { r_trans_factory: RTF, i_proto_factory: IPF, w_trans_factory: WTF, o_proto_factory: OPF, processor: Arc, worker_pool: ThreadPool, } impl TServer where PRC: TProcessor + Send + Sync + 'static, RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static, { /// Create a `TServer`. /// /// Each accepted connection has an input and output half, each of which /// requires a `TTransport` and `TProtocol`. `TServer` uses /// `read_transport_factory` and `input_protocol_factory` to create /// implementations for the input, and `write_transport_factory` and /// `output_protocol_factory` to create implementations for the output. pub fn new( read_transport_factory: RTF, input_protocol_factory: IPF, write_transport_factory: WTF, output_protocol_factory: OPF, processor: PRC, num_workers: usize, ) -> TServer { TServer { r_trans_factory: read_transport_factory, i_proto_factory: input_protocol_factory, w_trans_factory: write_transport_factory, o_proto_factory: output_protocol_factory, processor: Arc::new(processor), worker_pool: ThreadPool::with_name("Thrift service processor".to_owned(), num_workers), } } /// Listen for incoming connections on `listen_address`. /// /// `listen_address` should implement `ToSocketAddrs` trait. /// /// Return `()` if successful. /// /// Return `Err` when the server cannot bind to `listen_address` or there /// is an unrecoverable error. pub fn listen(&mut self, listen_address: A) -> crate::Result<()> { let listener = TcpListener::bind(listen_address)?; for stream in listener.incoming() { match stream { Ok(s) => { let (i_prot, o_prot) = self.new_protocols_for_connection(s)?; let processor = self.processor.clone(); self.worker_pool .execute(move || handle_incoming_connection(processor, i_prot, o_prot)); } Err(e) => { warn!("failed to accept remote connection with error {:?}", e); } } } Err(crate::Error::Application(ApplicationError { kind: ApplicationErrorKind::Unknown, message: "aborted listen loop".into(), })) } fn new_protocols_for_connection( &mut self, stream: TcpStream, ) -> crate::Result<( Box, Box, )> { // create the shared tcp stream let channel = TTcpChannel::with_stream(stream); // split it into two - one to be owned by the // input tran/proto and the other by the output let (r_chan, w_chan) = channel.split()?; // input protocol and transport let r_tran = self.r_trans_factory.create(Box::new(r_chan)); let i_prot = self.i_proto_factory.create(r_tran); // output protocol and transport let w_tran = self.w_trans_factory.create(Box::new(w_chan)); let o_prot = self.o_proto_factory.create(w_tran); Ok((i_prot, o_prot)) } } fn handle_incoming_connection( processor: Arc, i_prot: Box, o_prot: Box, ) where PRC: TProcessor, { let mut i_prot = i_prot; let mut o_prot = o_prot; loop { match processor.process(&mut *i_prot, &mut *o_prot) { Ok(()) => {} Err(err) => { match err { crate::Error::Transport(ref transport_err) if transport_err.kind == TransportErrorKind::EndOfFile => {} other => warn!("processor completed with error: {:?}", other), } break; } } } } thrift-0.16.0/lib/rs/src/transport/000077500000000000000000000000001420101504100170775ustar00rootroot00000000000000thrift-0.16.0/lib/rs/src/transport/buffered.rs000066400000000000000000000352101420101504100212300ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::cmp; use std::io; use std::io::{Read, Write}; use super::{TReadTransport, TReadTransportFactory, TWriteTransport, TWriteTransportFactory}; /// Default capacity of the read buffer in bytes. const READ_CAPACITY: usize = 4096; /// Default capacity of the write buffer in bytes.. const WRITE_CAPACITY: usize = 4096; /// Transport that reads messages via an internal buffer. /// /// A `TBufferedReadTransport` maintains a fixed-size internal read buffer. /// On a call to `TBufferedReadTransport::read(...)` one full message - both /// fixed-length header and bytes - is read from the wrapped channel and buffered. /// Subsequent read calls are serviced from the internal buffer until it is /// exhausted, at which point the next full message is read from the wrapped /// channel. /// /// # Examples /// /// Create and use a `TBufferedReadTransport`. /// /// ```no_run /// use std::io::Read; /// use thrift::transport::{TBufferedReadTransport, TTcpChannel}; /// /// let mut c = TTcpChannel::new(); /// c.open("localhost:9090").unwrap(); /// /// let mut t = TBufferedReadTransport::new(c); /// /// t.read(&mut vec![0u8; 1]).unwrap(); /// ``` #[derive(Debug)] pub struct TBufferedReadTransport where C: Read, { buf: Box<[u8]>, pos: usize, cap: usize, chan: C, } impl TBufferedReadTransport where C: Read, { /// Create a `TBufferedTransport` with default-sized internal read and /// write buffers that wraps the given `TIoChannel`. pub fn new(channel: C) -> TBufferedReadTransport { TBufferedReadTransport::with_capacity(READ_CAPACITY, channel) } /// Create a `TBufferedTransport` with an internal read buffer of size /// `read_capacity` and an internal write buffer of size /// `write_capacity` that wraps the given `TIoChannel`. pub fn with_capacity(read_capacity: usize, channel: C) -> TBufferedReadTransport { TBufferedReadTransport { buf: vec![0; read_capacity].into_boxed_slice(), pos: 0, cap: 0, chan: channel, } } fn get_bytes(&mut self) -> io::Result<&[u8]> { if self.cap - self.pos == 0 { self.pos = 0; self.cap = self.chan.read(&mut self.buf)?; } Ok(&self.buf[self.pos..self.cap]) } fn consume(&mut self, consumed: usize) { // TODO: was a bug here += <-- test somehow self.pos = cmp::min(self.cap, self.pos + consumed); } } impl Read for TBufferedReadTransport where C: Read, { fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut bytes_read = 0; loop { let nread = { let avail_bytes = self.get_bytes()?; let avail_space = buf.len() - bytes_read; let nread = cmp::min(avail_space, avail_bytes.len()); buf[bytes_read..(bytes_read + nread)].copy_from_slice(&avail_bytes[..nread]); nread }; self.consume(nread); bytes_read += nread; if bytes_read == buf.len() || nread == 0 { break; } } Ok(bytes_read) } } /// Factory for creating instances of `TBufferedReadTransport`. #[derive(Default)] pub struct TBufferedReadTransportFactory; impl TBufferedReadTransportFactory { pub fn new() -> TBufferedReadTransportFactory { TBufferedReadTransportFactory {} } } impl TReadTransportFactory for TBufferedReadTransportFactory { /// Create a `TBufferedReadTransport`. fn create(&self, channel: Box) -> Box { Box::new(TBufferedReadTransport::new(channel)) } } /// Transport that writes messages via an internal buffer. /// /// A `TBufferedWriteTransport` maintains a fixed-size internal write buffer. /// All writes are made to this buffer and are sent to the wrapped channel only /// when `TBufferedWriteTransport::flush()` is called. On a flush a fixed-length /// header with a count of the buffered bytes is written, followed by the bytes /// themselves. /// /// # Examples /// /// Create and use a `TBufferedWriteTransport`. /// /// ```no_run /// use std::io::Write; /// use thrift::transport::{TBufferedWriteTransport, TTcpChannel}; /// /// let mut c = TTcpChannel::new(); /// c.open("localhost:9090").unwrap(); /// /// let mut t = TBufferedWriteTransport::new(c); /// /// t.write(&[0x00]).unwrap(); /// t.flush().unwrap(); /// ``` #[derive(Debug)] pub struct TBufferedWriteTransport where C: Write, { buf: Vec, cap: usize, channel: C, } impl TBufferedWriteTransport where C: Write, { /// Create a `TBufferedTransport` with default-sized internal read and /// write buffers that wraps the given `TIoChannel`. pub fn new(channel: C) -> TBufferedWriteTransport { TBufferedWriteTransport::with_capacity(WRITE_CAPACITY, channel) } /// Create a `TBufferedTransport` with an internal read buffer of size /// `read_capacity` and an internal write buffer of size /// `write_capacity` that wraps the given `TIoChannel`. pub fn with_capacity(write_capacity: usize, channel: C) -> TBufferedWriteTransport { assert!( write_capacity > 0, "write buffer size must be a positive integer" ); TBufferedWriteTransport { buf: Vec::with_capacity(write_capacity), cap: write_capacity, channel, } } } impl Write for TBufferedWriteTransport where C: Write, { fn write(&mut self, buf: &[u8]) -> io::Result { if !buf.is_empty() { let mut avail_bytes; loop { avail_bytes = cmp::min(buf.len(), self.cap - self.buf.len()); if avail_bytes == 0 { self.flush()?; } else { break; } } let avail_bytes = avail_bytes; self.buf.extend_from_slice(&buf[..avail_bytes]); assert!(self.buf.len() <= self.cap, "copy overflowed buffer"); Ok(avail_bytes) } else { Ok(0) } } fn flush(&mut self) -> io::Result<()> { self.channel.write_all(&self.buf)?; self.channel.flush()?; self.buf.clear(); Ok(()) } } /// Factory for creating instances of `TBufferedWriteTransport`. #[derive(Default)] pub struct TBufferedWriteTransportFactory; impl TBufferedWriteTransportFactory { pub fn new() -> TBufferedWriteTransportFactory { TBufferedWriteTransportFactory {} } } impl TWriteTransportFactory for TBufferedWriteTransportFactory { /// Create a `TBufferedWriteTransport`. fn create(&self, channel: Box) -> Box { Box::new(TBufferedWriteTransport::new(channel)) } } #[cfg(test)] mod tests { use std::io::{Read, Write}; use super::*; use crate::transport::TBufferChannel; #[test] fn must_return_zero_if_read_buffer_is_empty() { let mem = TBufferChannel::with_capacity(10, 0); let mut t = TBufferedReadTransport::with_capacity(10, mem); let mut b = vec![0; 10]; let read_result = t.read(&mut b); assert_eq!(read_result.unwrap(), 0); } #[test] fn must_return_zero_if_caller_reads_into_zero_capacity_buffer() { let mem = TBufferChannel::with_capacity(10, 0); let mut t = TBufferedReadTransport::with_capacity(10, mem); let read_result = t.read(&mut []); assert_eq!(read_result.unwrap(), 0); } #[test] fn must_return_zero_if_nothing_more_can_be_read() { let mem = TBufferChannel::with_capacity(4, 0); let mut t = TBufferedReadTransport::with_capacity(4, mem); t.chan.set_readable_bytes(&[0, 1, 2, 3]); // read buffer is exactly the same size as bytes available let mut buf = vec![0u8; 4]; let read_result = t.read(&mut buf); // we've read exactly 4 bytes assert_eq!(read_result.unwrap(), 4); assert_eq!(&buf, &[0, 1, 2, 3]); // try read again let buf_again = vec![0u8; 4]; let read_result = t.read(&mut buf); // this time, 0 bytes and we haven't changed the buffer assert_eq!(read_result.unwrap(), 0); assert_eq!(&buf_again, &[0, 0, 0, 0]) } #[test] fn must_fill_user_buffer_with_only_as_many_bytes_as_available() { let mem = TBufferChannel::with_capacity(4, 0); let mut t = TBufferedReadTransport::with_capacity(4, mem); t.chan.set_readable_bytes(&[0, 1, 2, 3]); // read buffer is much larger than the bytes available let mut buf = vec![0u8; 8]; let read_result = t.read(&mut buf); // we've read exactly 4 bytes assert_eq!(read_result.unwrap(), 4); assert_eq!(&buf[..4], &[0, 1, 2, 3]); // try read again let read_result = t.read(&mut buf[4..]); // this time, 0 bytes and we haven't changed the buffer assert_eq!(read_result.unwrap(), 0); assert_eq!(&buf, &[0, 1, 2, 3, 0, 0, 0, 0]) } #[test] fn must_read_successfully() { // this test involves a few loops within the buffered transport // itself where it has to drain the underlying transport in order // to service a read // we have a much smaller buffer than the // underlying transport has bytes available let mem = TBufferChannel::with_capacity(10, 0); let mut t = TBufferedReadTransport::with_capacity(2, mem); // fill the underlying transport's byte buffer let mut readable_bytes = [0u8; 10]; for (i, b) in readable_bytes.iter_mut().enumerate() { *b = i as u8; } t.chan.set_readable_bytes(&readable_bytes); // we ask to read into a buffer that's much larger // than the one the buffered transport has; as a result // it's going to have to keep asking the underlying // transport for more bytes let mut buf = [0u8; 8]; let read_result = t.read(&mut buf); // we should have read 8 bytes assert_eq!(read_result.unwrap(), 8); assert_eq!(&buf, &[0, 1, 2, 3, 4, 5, 6, 7]); // let's clear out the buffer and try read again for b in &mut buf { *b = 0; } let read_result = t.read(&mut buf); // this time we were only able to read 2 bytes // (all that's remaining from the underlying transport) // let's also check that the remaining bytes are untouched assert_eq!(read_result.unwrap(), 2); assert_eq!(&buf[0..2], &[8, 9]); assert_eq!(&buf[2..], &[0, 0, 0, 0, 0, 0]); // try read again (we should get 0) // and all the existing bytes were untouched let read_result = t.read(&mut buf); assert_eq!(read_result.unwrap(), 0); assert_eq!(&buf[0..2], &[8, 9]); assert_eq!(&buf[2..], &[0, 0, 0, 0, 0, 0]); } #[test] fn must_return_error_when_nothing_can_be_written_to_underlying_channel() { let mem = TBufferChannel::with_capacity(0, 0); let mut t = TBufferedWriteTransport::with_capacity(1, mem); let b = vec![0; 10]; let r = t.write(&b); // should have written 1 byte assert_eq!(r.unwrap(), 1); // let's try again... let r = t.write(&b[1..]); // this time we'll error out because the auto-flush failed assert!(r.is_err()); } #[test] fn must_return_zero_if_caller_calls_write_with_empty_buffer() { let mem = TBufferChannel::with_capacity(0, 10); let mut t = TBufferedWriteTransport::with_capacity(10, mem); let r = t.write(&[]); let expected: [u8; 0] = []; assert_eq!(r.unwrap(), 0); assert_eq_transport_written_bytes!(t, expected); } #[test] fn must_auto_flush_if_write_buffer_full() { let mem = TBufferChannel::with_capacity(0, 8); let mut t = TBufferedWriteTransport::with_capacity(4, mem); let b0 = [0x00, 0x01, 0x02, 0x03]; let b1 = [0x04, 0x05, 0x06, 0x07]; // write the first 4 bytes; we've now filled the transport's write buffer let r = t.write(&b0); assert_eq!(r.unwrap(), 4); // try write the next 4 bytes; this causes the transport to auto-flush the first 4 bytes let r = t.write(&b1); assert_eq!(r.unwrap(), 4); // check that in writing the second 4 bytes we auto-flushed the first 4 bytes assert_eq_transport_num_written_bytes!(t, 4); assert_eq_transport_written_bytes!(t, b0); t.channel.empty_write_buffer(); // now flush the transport to push the second 4 bytes to the underlying channel assert!(t.flush().is_ok()); // check that we wrote out the second 4 bytes assert_eq_transport_written_bytes!(t, b1); } #[test] fn must_write_to_inner_transport_on_flush() { let mem = TBufferChannel::with_capacity(10, 10); let mut t = TBufferedWriteTransport::new(mem); let b: [u8; 5] = [0, 1, 2, 3, 4]; assert_eq!(t.write(&b).unwrap(), 5); assert_eq_transport_num_written_bytes!(t, 0); assert!(t.flush().is_ok()); assert_eq_transport_written_bytes!(t, b); } #[test] fn must_write_successfully_after_flush() { let mem = TBufferChannel::with_capacity(0, 5); let mut t = TBufferedWriteTransport::with_capacity(5, mem); // write and flush let b: [u8; 5] = [0, 1, 2, 3, 4]; assert_eq!(t.write(&b).unwrap(), 5); assert!(t.flush().is_ok()); // check the flushed bytes assert_eq_transport_written_bytes!(t, b); // reset our underlying transport t.channel.empty_write_buffer(); // write and flush again assert_eq!(t.write(&b).unwrap(), 5); assert!(t.flush().is_ok()); // check the flushed bytes assert_eq_transport_written_bytes!(t, b); } } thrift-0.16.0/lib/rs/src/transport/framed.rs000066400000000000000000000340071420101504100207070ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::cmp; use std::io; use std::io::{Read, Write}; use super::{TReadTransport, TReadTransportFactory, TWriteTransport, TWriteTransportFactory}; /// Default capacity of the read buffer in bytes. const READ_CAPACITY: usize = 4096; /// Default capacity of the write buffer in bytes. const WRITE_CAPACITY: usize = 4096; /// Transport that reads framed messages. /// /// A `TFramedReadTransport` maintains a fixed-size internal read buffer. /// On a call to `TFramedReadTransport::read(...)` one full message - both /// fixed-length header and bytes - is read from the wrapped channel and /// buffered. Subsequent read calls are serviced from the internal buffer /// until it is exhausted, at which point the next full message is read /// from the wrapped channel. /// /// # Examples /// /// Create and use a `TFramedReadTransport`. /// /// ```no_run /// use std::io::Read; /// use thrift::transport::{TFramedReadTransport, TTcpChannel}; /// /// let mut c = TTcpChannel::new(); /// c.open("localhost:9090").unwrap(); /// /// let mut t = TFramedReadTransport::new(c); /// /// t.read(&mut vec![0u8; 1]).unwrap(); /// ``` #[derive(Debug)] pub struct TFramedReadTransport where C: Read, { buf: Vec, pos: usize, cap: usize, chan: C, } impl TFramedReadTransport where C: Read, { /// Create a `TFramedReadTransport` with a default-sized /// internal read buffer that wraps the given `TIoChannel`. pub fn new(channel: C) -> TFramedReadTransport { TFramedReadTransport::with_capacity(READ_CAPACITY, channel) } /// Create a `TFramedTransport` with an internal read buffer /// of size `read_capacity` that wraps the given `TIoChannel`. pub fn with_capacity(read_capacity: usize, channel: C) -> TFramedReadTransport { TFramedReadTransport { buf: vec![0; read_capacity], // FIXME: do I actually have to do this? pos: 0, cap: 0, chan: channel, } } } impl Read for TFramedReadTransport where C: Read, { fn read(&mut self, b: &mut [u8]) -> io::Result { if self.cap - self.pos == 0 { let message_size = self.chan.read_i32::()? as usize; let buf_capacity = cmp::max(message_size, READ_CAPACITY); self.buf.resize(buf_capacity, 0); self.chan.read_exact(&mut self.buf[..message_size])?; self.cap = message_size as usize; self.pos = 0; } let nread = cmp::min(b.len(), self.cap - self.pos); b[..nread].clone_from_slice(&self.buf[self.pos..self.pos + nread]); self.pos += nread; Ok(nread) } } /// Factory for creating instances of `TFramedReadTransport`. #[derive(Default)] pub struct TFramedReadTransportFactory; impl TFramedReadTransportFactory { pub fn new() -> TFramedReadTransportFactory { TFramedReadTransportFactory {} } } impl TReadTransportFactory for TFramedReadTransportFactory { /// Create a `TFramedReadTransport`. fn create(&self, channel: Box) -> Box { Box::new(TFramedReadTransport::new(channel)) } } /// Transport that writes framed messages. /// /// A `TFramedWriteTransport` maintains a fixed-size internal write buffer. All /// writes are made to this buffer and are sent to the wrapped channel only /// when `TFramedWriteTransport::flush()` is called. On a flush a fixed-length /// header with a count of the buffered bytes is written, followed by the bytes /// themselves. /// /// # Examples /// /// Create and use a `TFramedWriteTransport`. /// /// ```no_run /// use std::io::Write; /// use thrift::transport::{TFramedWriteTransport, TTcpChannel}; /// /// let mut c = TTcpChannel::new(); /// c.open("localhost:9090").unwrap(); /// /// let mut t = TFramedWriteTransport::new(c); /// /// t.write(&[0x00]).unwrap(); /// t.flush().unwrap(); /// ``` #[derive(Debug)] pub struct TFramedWriteTransport where C: Write, { buf: Vec, channel: C, } impl TFramedWriteTransport where C: Write, { /// Create a `TFramedWriteTransport` with default-sized internal /// write buffer that wraps the given `TIoChannel`. pub fn new(channel: C) -> TFramedWriteTransport { TFramedWriteTransport::with_capacity(WRITE_CAPACITY, channel) } /// Create a `TFramedWriteTransport` with an internal write buffer /// of size `write_capacity` that wraps the given `TIoChannel`. pub fn with_capacity(write_capacity: usize, channel: C) -> TFramedWriteTransport { TFramedWriteTransport { buf: Vec::with_capacity(write_capacity), channel, } } } impl Write for TFramedWriteTransport where C: Write, { fn write(&mut self, b: &[u8]) -> io::Result { let current_capacity = self.buf.capacity(); let available_space = current_capacity - self.buf.len(); if b.len() > available_space { let additional_space = cmp::max(b.len() - available_space, current_capacity); self.buf.reserve(additional_space); } self.buf.extend_from_slice(b); Ok(b.len()) } fn flush(&mut self) -> io::Result<()> { let message_size = self.buf.len(); if let 0 = message_size { return Ok(()); } else { self.channel.write_i32::(message_size as i32)?; } // will spin if the underlying channel can't be written to let mut byte_index = 0; while byte_index < message_size { let nwrite = self.channel.write(&self.buf[byte_index..message_size])?; byte_index = cmp::min(byte_index + nwrite, message_size); } let buf_capacity = cmp::min(self.buf.capacity(), WRITE_CAPACITY); self.buf.resize(buf_capacity, 0); self.buf.clear(); self.channel.flush() } } /// Factory for creating instances of `TFramedWriteTransport`. #[derive(Default)] pub struct TFramedWriteTransportFactory; impl TFramedWriteTransportFactory { pub fn new() -> TFramedWriteTransportFactory { TFramedWriteTransportFactory {} } } impl TWriteTransportFactory for TFramedWriteTransportFactory { /// Create a `TFramedWriteTransport`. fn create(&self, channel: Box) -> Box { Box::new(TFramedWriteTransport::new(channel)) } } #[cfg(test)] mod tests { use super::*; use crate::transport::mem::TBufferChannel; // FIXME: test a forced reserve #[test] fn must_read_message_smaller_than_initial_buffer_size() { let c = TBufferChannel::with_capacity(10, 10); let mut t = TFramedReadTransport::with_capacity(8, c); t.chan.set_readable_bytes(&[ 0x00, 0x00, 0x00, 0x04, /* message size */ 0x00, 0x01, 0x02, 0x03, /* message body */ ]); let mut buf = vec![0; 8]; // we've read exactly 4 bytes assert_eq!(t.read(&mut buf).unwrap(), 4); assert_eq!(&buf[..4], &[0x00, 0x01, 0x02, 0x03]); } #[test] fn must_read_message_greater_than_initial_buffer_size() { let c = TBufferChannel::with_capacity(10, 10); let mut t = TFramedReadTransport::with_capacity(2, c); t.chan.set_readable_bytes(&[ 0x00, 0x00, 0x00, 0x04, /* message size */ 0x00, 0x01, 0x02, 0x03, /* message body */ ]); let mut buf = vec![0; 8]; // we've read exactly 4 bytes assert_eq!(t.read(&mut buf).unwrap(), 4); assert_eq!(&buf[..4], &[0x00, 0x01, 0x02, 0x03]); } #[test] fn must_read_multiple_messages_in_sequence_correctly() { let c = TBufferChannel::with_capacity(10, 10); let mut t = TFramedReadTransport::with_capacity(2, c); // // 1st message // t.chan.set_readable_bytes(&[ 0x00, 0x00, 0x00, 0x04, /* message size */ 0x00, 0x01, 0x02, 0x03, /* message body */ ]); let mut buf = vec![0; 8]; // we've read exactly 4 bytes assert_eq!(t.read(&mut buf).unwrap(), 4); assert_eq!(&buf, &[0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00]); // // 2nd message // t.chan.set_readable_bytes(&[ 0x00, 0x00, 0x00, 0x01, /* message size */ 0x04, /* message body */ ]); let mut buf = vec![0; 8]; // we've read exactly 1 byte assert_eq!(t.read(&mut buf).unwrap(), 1); assert_eq!(&buf, &[0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); } #[test] fn must_write_message_smaller_than_buffer_size() { let mem = TBufferChannel::with_capacity(0, 0); let mut t = TFramedWriteTransport::with_capacity(20, mem); let b = vec![0; 10]; // should have written 10 bytes assert_eq!(t.write(&b).unwrap(), 10); } #[test] fn must_return_zero_if_caller_calls_write_with_empty_buffer() { let mem = TBufferChannel::with_capacity(0, 10); let mut t = TFramedWriteTransport::with_capacity(10, mem); let expected: [u8; 0] = []; assert_eq!(t.write(&[]).unwrap(), 0); assert_eq_transport_written_bytes!(t, expected); } #[test] fn must_write_to_inner_transport_on_flush() { let mem = TBufferChannel::with_capacity(10, 10); let mut t = TFramedWriteTransport::new(mem); let b: [u8; 5] = [0x00, 0x01, 0x02, 0x03, 0x04]; assert_eq!(t.write(&b).unwrap(), 5); assert_eq_transport_num_written_bytes!(t, 0); assert!(t.flush().is_ok()); let expected_bytes = [ 0x00, 0x00, 0x00, 0x05, /* message size */ 0x00, 0x01, 0x02, 0x03, 0x04, /* message body */ ]; assert_eq_transport_written_bytes!(t, expected_bytes); } #[test] fn must_write_message_greater_than_buffer_size_00() { let mem = TBufferChannel::with_capacity(0, 10); // IMPORTANT: DO **NOT** CHANGE THE WRITE_CAPACITY OR THE NUMBER OF BYTES TO BE WRITTEN! // these lengths were chosen to be just long enough // that doubling the capacity is a **worse** choice than // simply resizing the buffer to b.len() let mut t = TFramedWriteTransport::with_capacity(1, mem); let b = [0x00, 0x01, 0x02]; // should have written 3 bytes assert_eq!(t.write(&b).unwrap(), 3); assert_eq_transport_num_written_bytes!(t, 0); assert!(t.flush().is_ok()); let expected_bytes = [ 0x00, 0x00, 0x00, 0x03, /* message size */ 0x00, 0x01, 0x02, /* message body */ ]; assert_eq_transport_written_bytes!(t, expected_bytes); } #[test] fn must_write_message_greater_than_buffer_size_01() { let mem = TBufferChannel::with_capacity(0, 10); // IMPORTANT: DO **NOT** CHANGE THE WRITE_CAPACITY OR THE NUMBER OF BYTES TO BE WRITTEN! // these lengths were chosen to be just long enough // that doubling the capacity is a **better** choice than // simply resizing the buffer to b.len() let mut t = TFramedWriteTransport::with_capacity(2, mem); let b = [0x00, 0x01, 0x02]; // should have written 3 bytes assert_eq!(t.write(&b).unwrap(), 3); assert_eq_transport_num_written_bytes!(t, 0); assert!(t.flush().is_ok()); let expected_bytes = [ 0x00, 0x00, 0x00, 0x03, /* message size */ 0x00, 0x01, 0x02, /* message body */ ]; assert_eq_transport_written_bytes!(t, expected_bytes); } #[test] fn must_return_error_if_nothing_can_be_written_to_inner_transport_on_flush() { let mem = TBufferChannel::with_capacity(0, 0); let mut t = TFramedWriteTransport::with_capacity(1, mem); let b = vec![0; 10]; // should have written 10 bytes assert_eq!(t.write(&b).unwrap(), 10); // let's flush let r = t.flush(); // this time we'll error out because the flush can't write to the underlying channel assert!(r.is_err()); } #[test] fn must_write_successfully_after_flush() { // IMPORTANT: write capacity *MUST* be greater // than message sizes used in this test + 4-byte frame header let mem = TBufferChannel::with_capacity(0, 10); let mut t = TFramedWriteTransport::with_capacity(5, mem); // write and flush let first_message: [u8; 5] = [0x00, 0x01, 0x02, 0x03, 0x04]; assert_eq!(t.write(&first_message).unwrap(), 5); assert!(t.flush().is_ok()); let mut expected = Vec::new(); expected.write_all(&[0x00, 0x00, 0x00, 0x05]).unwrap(); // message size expected.extend_from_slice(&first_message); // check the flushed bytes assert_eq!(t.channel.write_bytes(), expected); // reset our underlying transport t.channel.empty_write_buffer(); let second_message: [u8; 3] = [0x05, 0x06, 0x07]; assert_eq!(t.write(&second_message).unwrap(), 3); assert!(t.flush().is_ok()); expected.clear(); expected.write_all(&[0x00, 0x00, 0x00, 0x03]).unwrap(); // message size expected.extend_from_slice(&second_message); // check the flushed bytes assert_eq!(t.channel.write_bytes(), expected); } } thrift-0.16.0/lib/rs/src/transport/mem.rs000066400000000000000000000330701420101504100202260ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::cmp; use std::io; use std::sync::{Arc, Mutex}; use super::{ReadHalf, TIoChannel, WriteHalf}; /// In-memory read and write channel with fixed-size read and write buffers. /// /// On a `write` bytes are written to the internal write buffer. Writes are no /// longer accepted once this buffer is full. Callers must `empty_write_buffer()` /// before subsequent writes are accepted. /// /// You can set readable bytes in the internal read buffer by filling it with /// `set_readable_bytes(...)`. Callers can then read until the buffer is /// depleted. No further reads are accepted until the internal read buffer is /// replenished again. #[derive(Clone, Debug)] pub struct TBufferChannel { read: Arc>, write: Arc>, } #[derive(Debug)] struct ReadData { buf: Box<[u8]>, pos: usize, idx: usize, cap: usize, } #[derive(Debug)] struct WriteData { buf: Box<[u8]>, pos: usize, cap: usize, } impl TBufferChannel { /// Constructs a new, empty `TBufferChannel` with the given /// read buffer capacity and write buffer capacity. pub fn with_capacity(read_capacity: usize, write_capacity: usize) -> TBufferChannel { TBufferChannel { read: Arc::new(Mutex::new(ReadData { buf: vec![0; read_capacity].into_boxed_slice(), idx: 0, pos: 0, cap: read_capacity, })), write: Arc::new(Mutex::new(WriteData { buf: vec![0; write_capacity].into_boxed_slice(), pos: 0, cap: write_capacity, })), } } /// Return a copy of the bytes held by the internal read buffer. /// Returns an empty vector if no readable bytes are present. pub fn read_bytes(&self) -> Vec { let rdata = self.read.as_ref().lock().unwrap(); let mut buf = vec![0u8; rdata.idx]; buf.copy_from_slice(&rdata.buf[..rdata.idx]); buf } // FIXME: do I really need this API call? // FIXME: should this simply reset to the last set of readable bytes? /// Reset the number of readable bytes to zero. /// /// Subsequent calls to `read` will return nothing. pub fn empty_read_buffer(&mut self) { let mut rdata = self.read.as_ref().lock().unwrap(); rdata.pos = 0; rdata.idx = 0; } /// Copy bytes from the source buffer `buf` into the internal read buffer, /// overwriting any existing bytes. Returns the number of bytes copied, /// which is `min(buf.len(), internal_read_buf.len())`. pub fn set_readable_bytes(&mut self, buf: &[u8]) -> usize { self.empty_read_buffer(); let mut rdata = self.read.as_ref().lock().unwrap(); let max_bytes = cmp::min(rdata.cap, buf.len()); rdata.buf[..max_bytes].clone_from_slice(&buf[..max_bytes]); rdata.idx = max_bytes; max_bytes } /// Return a copy of the bytes held by the internal write buffer. /// Returns an empty vector if no bytes were written. pub fn write_bytes(&self) -> Vec { let wdata = self.write.as_ref().lock().unwrap(); let mut buf = vec![0u8; wdata.pos]; buf.copy_from_slice(&wdata.buf[..wdata.pos]); buf } /// Resets the internal write buffer, making it seem like no bytes were /// written. Calling `write_buffer` after this returns an empty vector. pub fn empty_write_buffer(&mut self) { let mut wdata = self.write.as_ref().lock().unwrap(); wdata.pos = 0; } /// Overwrites the contents of the read buffer with the contents of the /// write buffer. The write buffer is emptied after this operation. pub fn copy_write_buffer_to_read_buffer(&mut self) { // FIXME: redo this entire method let buf = { let wdata = self.write.as_ref().lock().unwrap(); let b = &wdata.buf[..wdata.pos]; let mut b_ret = vec![0; b.len()]; b_ret.copy_from_slice(b); b_ret }; let bytes_copied = self.set_readable_bytes(&buf); assert_eq!(bytes_copied, buf.len()); self.empty_write_buffer(); } } impl TIoChannel for TBufferChannel { fn split(self) -> crate::Result<(ReadHalf, WriteHalf)> where Self: Sized, { Ok(( ReadHalf { handle: TBufferChannel { read: self.read.clone(), write: self.write.clone(), }, }, WriteHalf { handle: TBufferChannel { read: self.read.clone(), // NOTE: not cloning here, since this is the last statement // in this method and `write` can take ownership of `self.write` write: self.write, }, }, )) } } impl io::Read for TBufferChannel { fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut rdata = self.read.as_ref().lock().unwrap(); let nread = cmp::min(buf.len(), rdata.idx - rdata.pos); buf[..nread].clone_from_slice(&rdata.buf[rdata.pos..rdata.pos + nread]); rdata.pos += nread; Ok(nread) } } impl io::Write for TBufferChannel { fn write(&mut self, buf: &[u8]) -> io::Result { let mut wdata = self.write.as_ref().lock().unwrap(); let nwrite = cmp::min(buf.len(), wdata.cap - wdata.pos); let (start, end) = (wdata.pos, wdata.pos + nwrite); wdata.buf[start..end].clone_from_slice(&buf[..nwrite]); wdata.pos += nwrite; Ok(nwrite) } fn flush(&mut self) -> io::Result<()> { Ok(()) // nothing to do on flush } } #[cfg(test)] mod tests { use std::io::{Read, Write}; use super::TBufferChannel; #[test] fn must_empty_write_buffer() { let mut t = TBufferChannel::with_capacity(0, 1); let bytes_to_write: [u8; 1] = [0x01]; let result = t.write(&bytes_to_write); assert_eq!(result.unwrap(), 1); assert_eq!(&t.write_bytes(), &bytes_to_write); t.empty_write_buffer(); assert_eq!(t.write_bytes().len(), 0); } #[test] fn must_accept_writes_after_buffer_emptied() { let mut t = TBufferChannel::with_capacity(0, 2); let bytes_to_write: [u8; 2] = [0x01, 0x02]; // first write (all bytes written) let result = t.write(&bytes_to_write); assert_eq!(result.unwrap(), 2); assert_eq!(&t.write_bytes(), &bytes_to_write); // try write again (nothing should be written) let result = t.write(&bytes_to_write); assert_eq!(result.unwrap(), 0); assert_eq!(&t.write_bytes(), &bytes_to_write); // still the same as before // now reset the buffer t.empty_write_buffer(); assert_eq!(t.write_bytes().len(), 0); // now try write again - the write should succeed let result = t.write(&bytes_to_write); assert_eq!(result.unwrap(), 2); assert_eq!(&t.write_bytes(), &bytes_to_write); } #[test] fn must_accept_multiple_writes_until_buffer_is_full() { let mut t = TBufferChannel::with_capacity(0, 10); // first write (all bytes written) let bytes_to_write_0: [u8; 2] = [0x01, 0x41]; let write_0_result = t.write(&bytes_to_write_0); assert_eq!(write_0_result.unwrap(), 2); assert_eq!(t.write_bytes(), &bytes_to_write_0); // second write (all bytes written, starting at index 2) let bytes_to_write_1: [u8; 7] = [0x24, 0x41, 0x32, 0x33, 0x11, 0x98, 0xAF]; let write_1_result = t.write(&bytes_to_write_1); assert_eq!(write_1_result.unwrap(), 7); assert_eq!(&t.write_bytes()[2..], &bytes_to_write_1); // third write (only 1 byte written - that's all we have space for) let bytes_to_write_2: [u8; 3] = [0xBF, 0xDA, 0x98]; let write_2_result = t.write(&bytes_to_write_2); assert_eq!(write_2_result.unwrap(), 1); assert_eq!(&t.write_bytes()[9..], &bytes_to_write_2[0..1]); // how does this syntax work?! // fourth write (no writes are accepted) let bytes_to_write_3: [u8; 3] = [0xBF, 0xAA, 0xFD]; let write_3_result = t.write(&bytes_to_write_3); assert_eq!(write_3_result.unwrap(), 0); // check the full write buffer let mut expected: Vec = Vec::with_capacity(10); expected.extend_from_slice(&bytes_to_write_0); expected.extend_from_slice(&bytes_to_write_1); expected.extend_from_slice(&bytes_to_write_2[0..1]); assert_eq!(t.write_bytes(), &expected[..]); } #[test] fn must_empty_read_buffer() { let mut t = TBufferChannel::with_capacity(1, 0); let bytes_to_read: [u8; 1] = [0x01]; let result = t.set_readable_bytes(&bytes_to_read); assert_eq!(result, 1); assert_eq!(t.read_bytes(), &bytes_to_read); t.empty_read_buffer(); assert_eq!(t.read_bytes().len(), 0); } #[test] fn must_allow_readable_bytes_to_be_set_after_read_buffer_emptied() { let mut t = TBufferChannel::with_capacity(1, 0); let bytes_to_read_0: [u8; 1] = [0x01]; let result = t.set_readable_bytes(&bytes_to_read_0); assert_eq!(result, 1); assert_eq!(t.read_bytes(), &bytes_to_read_0); t.empty_read_buffer(); assert_eq!(t.read_bytes().len(), 0); let bytes_to_read_1: [u8; 1] = [0x02]; let result = t.set_readable_bytes(&bytes_to_read_1); assert_eq!(result, 1); assert_eq!(t.read_bytes(), &bytes_to_read_1); } #[test] fn must_accept_multiple_reads_until_all_bytes_read() { let mut t = TBufferChannel::with_capacity(10, 0); let readable_bytes: [u8; 10] = [0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0x00, 0x1A, 0x2B, 0x3C, 0x4D]; // check that we're able to set the bytes to be read let result = t.set_readable_bytes(&readable_bytes); assert_eq!(result, 10); assert_eq!(t.read_bytes(), &readable_bytes); // first read let mut read_buf_0 = vec![0; 5]; let read_result = t.read(&mut read_buf_0); assert_eq!(read_result.unwrap(), 5); assert_eq!(read_buf_0.as_slice(), &(readable_bytes[0..5])); // second read let mut read_buf_1 = vec![0; 4]; let read_result = t.read(&mut read_buf_1); assert_eq!(read_result.unwrap(), 4); assert_eq!(read_buf_1.as_slice(), &(readable_bytes[5..9])); // third read (only 1 byte remains to be read) let mut read_buf_2 = vec![0; 3]; let read_result = t.read(&mut read_buf_2); assert_eq!(read_result.unwrap(), 1); read_buf_2.truncate(1); // FIXME: does the caller have to do this? assert_eq!(read_buf_2.as_slice(), &(readable_bytes[9..])); // fourth read (nothing should be readable) let mut read_buf_3 = vec![0; 10]; let read_result = t.read(&mut read_buf_3); assert_eq!(read_result.unwrap(), 0); read_buf_3.truncate(0); // check that all the bytes we received match the original (again!) let mut bytes_read = Vec::with_capacity(10); bytes_read.extend_from_slice(&read_buf_0); bytes_read.extend_from_slice(&read_buf_1); bytes_read.extend_from_slice(&read_buf_2); bytes_read.extend_from_slice(&read_buf_3); assert_eq!(&bytes_read, &readable_bytes); } #[test] fn must_allow_reads_to_succeed_after_read_buffer_replenished() { let mut t = TBufferChannel::with_capacity(3, 0); let readable_bytes_0: [u8; 3] = [0x02, 0xAB, 0x33]; // check that we're able to set the bytes to be read let result = t.set_readable_bytes(&readable_bytes_0); assert_eq!(result, 3); assert_eq!(t.read_bytes(), &readable_bytes_0); let mut read_buf = vec![0; 4]; // drain the read buffer let read_result = t.read(&mut read_buf); assert_eq!(read_result.unwrap(), 3); assert_eq!(t.read_bytes(), &read_buf[0..3]); // check that a subsequent read fails let read_result = t.read(&mut read_buf); assert_eq!(read_result.unwrap(), 0); // we don't modify the read buffer on failure let mut expected_bytes = Vec::with_capacity(4); expected_bytes.extend_from_slice(&readable_bytes_0); expected_bytes.push(0x00); assert_eq!(&read_buf, &expected_bytes); // replenish the read buffer again let readable_bytes_1: [u8; 2] = [0x91, 0xAA]; // check that we're able to set the bytes to be read let result = t.set_readable_bytes(&readable_bytes_1); assert_eq!(result, 2); assert_eq!(t.read_bytes(), &readable_bytes_1); // read again let read_result = t.read(&mut read_buf); assert_eq!(read_result.unwrap(), 2); assert_eq!(t.read_bytes(), &read_buf[0..2]); } } thrift-0.16.0/lib/rs/src/transport/mod.rs000066400000000000000000000172721420101504100202350ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. //! Types used to send and receive bytes over an I/O channel. //! //! The core types are the `TReadTransport`, `TWriteTransport` and the //! `TIoChannel` traits, through which `TInputProtocol` or //! `TOutputProtocol` can receive and send primitives over the wire. While //! `TInputProtocol` and `TOutputProtocol` instances deal with language primitives //! the types in this module understand only bytes. use std::io; use std::io::{Read, Write}; use std::ops::{Deref, DerefMut}; #[cfg(test)] macro_rules! assert_eq_transport_num_written_bytes { ($transport:ident, $num_written_bytes:expr) => {{ assert_eq!($transport.channel.write_bytes().len(), $num_written_bytes); }}; } #[cfg(test)] macro_rules! assert_eq_transport_written_bytes { ($transport:ident, $expected_bytes:ident) => {{ assert_eq!($transport.channel.write_bytes(), &$expected_bytes); }}; } mod buffered; mod framed; mod mem; mod socket; pub use self::buffered::{ TBufferedReadTransport, TBufferedReadTransportFactory, TBufferedWriteTransport, TBufferedWriteTransportFactory, }; pub use self::framed::{ TFramedReadTransport, TFramedReadTransportFactory, TFramedWriteTransport, TFramedWriteTransportFactory, }; pub use self::mem::TBufferChannel; pub use self::socket::TTcpChannel; /// Identifies a transport used by a `TInputProtocol` to receive bytes. pub trait TReadTransport: Read {} /// Helper type used by a server to create `TReadTransport` instances for /// accepted client connections. pub trait TReadTransportFactory { /// Create a `TTransport` that wraps a channel over which bytes are to be read. fn create(&self, channel: Box) -> Box; } /// Identifies a transport used by `TOutputProtocol` to send bytes. pub trait TWriteTransport: Write {} /// Helper type used by a server to create `TWriteTransport` instances for /// accepted client connections. pub trait TWriteTransportFactory { /// Create a `TTransport` that wraps a channel over which bytes are to be sent. fn create(&self, channel: Box) -> Box; } impl TReadTransport for T where T: Read {} impl TWriteTransport for T where T: Write {} // FIXME: implement the Debug trait for boxed transports impl TReadTransportFactory for Box where T: TReadTransportFactory + ?Sized, { fn create(&self, channel: Box) -> Box { (**self).create(channel) } } impl TWriteTransportFactory for Box where T: TWriteTransportFactory + ?Sized, { fn create(&self, channel: Box) -> Box { (**self).create(channel) } } /// Identifies a splittable bidirectional I/O channel used to send and receive bytes. pub trait TIoChannel: Read + Write { /// Split the channel into a readable half and a writable half, where the /// readable half implements `io::Read` and the writable half implements /// `io::Write`. Returns `None` if the channel was not initialized, or if it /// cannot be split safely. /// /// Returned halves may share the underlying OS channel or buffer resources. /// Implementations **should ensure** that these two halves can be safely /// used independently by concurrent threads. fn split( self, ) -> crate::Result<( crate::transport::ReadHalf, crate::transport::WriteHalf, )> where Self: Sized; } /// The readable half of an object returned from `TIoChannel::split`. #[derive(Debug)] pub struct ReadHalf where C: Read, { handle: C, } /// The writable half of an object returned from `TIoChannel::split`. #[derive(Debug)] pub struct WriteHalf where C: Write, { handle: C, } impl ReadHalf where C: Read, { /// Create a `ReadHalf` associated with readable `handle` pub fn new(handle: C) -> ReadHalf { ReadHalf { handle } } } impl WriteHalf where C: Write, { /// Create a `WriteHalf` associated with writable `handle` pub fn new(handle: C) -> WriteHalf { WriteHalf { handle } } } impl Read for ReadHalf where C: Read, { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.handle.read(buf) } } impl Write for WriteHalf where C: Write, { fn write(&mut self, buf: &[u8]) -> io::Result { self.handle.write(buf) } fn flush(&mut self) -> io::Result<()> { self.handle.flush() } } impl Deref for ReadHalf where C: Read, { type Target = C; fn deref(&self) -> &Self::Target { &self.handle } } impl DerefMut for ReadHalf where C: Read, { fn deref_mut(&mut self) -> &mut C { &mut self.handle } } impl Deref for WriteHalf where C: Write, { type Target = C; fn deref(&self) -> &Self::Target { &self.handle } } impl DerefMut for WriteHalf where C: Write, { fn deref_mut(&mut self) -> &mut C { &mut self.handle } } #[cfg(test)] mod tests { use std::io::Cursor; use super::*; #[test] fn must_create_usable_read_channel_from_concrete_read_type() { let r = Cursor::new([0, 1, 2]); let _ = TBufferedReadTransport::new(r); } #[test] fn must_create_usable_read_channel_from_boxed_read() { let r: Box = Box::new(Cursor::new([0, 1, 2])); let _ = TBufferedReadTransport::new(r); } #[test] fn must_create_usable_write_channel_from_concrete_write_type() { let w = vec![0u8; 10]; let _ = TBufferedWriteTransport::new(w); } #[test] fn must_create_usable_write_channel_from_boxed_write() { let w: Box = Box::new(vec![0u8; 10]); let _ = TBufferedWriteTransport::new(w); } #[test] fn must_create_usable_read_transport_from_concrete_read_transport() { let r = Cursor::new([0, 1, 2]); let mut t = TBufferedReadTransport::new(r); takes_read_transport(&mut t) } #[test] fn must_create_usable_read_transport_from_boxed_read() { let r = Cursor::new([0, 1, 2]); let mut t: Box = Box::new(TBufferedReadTransport::new(r)); takes_read_transport(&mut t) } #[test] fn must_create_usable_write_transport_from_concrete_write_transport() { let w = vec![0u8; 10]; let mut t = TBufferedWriteTransport::new(w); takes_write_transport(&mut t) } #[test] fn must_create_usable_write_transport_from_boxed_write() { let w = vec![0u8; 10]; let mut t: Box = Box::new(TBufferedWriteTransport::new(w)); takes_write_transport(&mut t) } fn takes_read_transport(t: &mut R) where R: TReadTransport, { t.bytes(); } fn takes_write_transport(t: &mut W) where W: TWriteTransport, { t.flush().unwrap(); } } thrift-0.16.0/lib/rs/src/transport/socket.rs000066400000000000000000000116631420101504100207440ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::convert::From; use std::io; use std::io::{ErrorKind, Read, Write}; use std::net::{Shutdown, TcpStream, ToSocketAddrs}; use super::{ReadHalf, TIoChannel, WriteHalf}; use crate::{new_transport_error, TransportErrorKind}; /// Bidirectional TCP/IP channel. /// /// # Examples /// /// Create a `TTcpChannel`. /// /// ```no_run /// use std::io::{Read, Write}; /// use thrift::transport::TTcpChannel; /// /// let mut c = TTcpChannel::new(); /// c.open("localhost:9090").unwrap(); /// /// let mut buf = vec![0u8; 4]; /// c.read(&mut buf).unwrap(); /// c.write(&vec![0, 1, 2]).unwrap(); /// ``` /// /// Create a `TTcpChannel` by wrapping an existing `TcpStream`. /// /// ```no_run /// use std::io::{Read, Write}; /// use std::net::TcpStream; /// use thrift::transport::TTcpChannel; /// /// let stream = TcpStream::connect("127.0.0.1:9189").unwrap(); /// /// // no need to call c.open() since we've already connected above /// let mut c = TTcpChannel::with_stream(stream); /// /// let mut buf = vec![0u8; 4]; /// c.read(&mut buf).unwrap(); /// c.write(&vec![0, 1, 2]).unwrap(); /// ``` #[derive(Debug, Default)] pub struct TTcpChannel { stream: Option, } impl TTcpChannel { /// Create an uninitialized `TTcpChannel`. /// /// The returned instance must be opened using `TTcpChannel::open(...)` /// before it can be used. pub fn new() -> TTcpChannel { TTcpChannel { stream: None } } /// Create a `TTcpChannel` that wraps an existing `TcpStream`. /// /// The passed-in stream is assumed to have been opened before being wrapped /// by the created `TTcpChannel` instance. pub fn with_stream(stream: TcpStream) -> TTcpChannel { TTcpChannel { stream: Some(stream), } } /// Connect to `remote_address`, which should implement `ToSocketAddrs` trait. pub fn open(&mut self, remote_address: A) -> crate::Result<()> { if self.stream.is_some() { Err(new_transport_error( TransportErrorKind::AlreadyOpen, "tcp connection previously opened", )) } else { match TcpStream::connect(&remote_address) { Ok(s) => { self.stream = Some(s); Ok(()) } Err(e) => Err(From::from(e)), } } } /// Shut down this channel. /// /// Both send and receive halves are closed, and this instance can no /// longer be used to communicate with another endpoint. pub fn close(&mut self) -> crate::Result<()> { self.if_set(|s| s.shutdown(Shutdown::Both)) .map_err(From::from) } fn if_set(&mut self, mut stream_operation: F) -> io::Result where F: FnMut(&mut TcpStream) -> io::Result, { if let Some(ref mut s) = self.stream { stream_operation(s) } else { Err(io::Error::new( ErrorKind::NotConnected, "tcp endpoint not connected", )) } } } impl TIoChannel for TTcpChannel { fn split(self) -> crate::Result<(ReadHalf, WriteHalf)> where Self: Sized, { let mut s = self; s.stream .as_mut() .and_then(|s| s.try_clone().ok()) .map(|cloned| { let read_half = ReadHalf::new(TTcpChannel { stream: s.stream.take(), }); let write_half = WriteHalf::new(TTcpChannel { stream: Some(cloned), }); (read_half, write_half) }) .ok_or_else(|| { new_transport_error( TransportErrorKind::Unknown, "cannot clone underlying tcp stream", ) }) } } impl Read for TTcpChannel { fn read(&mut self, b: &mut [u8]) -> io::Result { self.if_set(|s| s.read(b)) } } impl Write for TTcpChannel { fn write(&mut self, b: &[u8]) -> io::Result { self.if_set(|s| s.write(b)) } fn flush(&mut self) -> io::Result<()> { self.if_set(|s| s.flush()) } } thrift-0.16.0/lib/rs/test/000077500000000000000000000000001420101504100152335ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test/Cargo.toml000066400000000000000000000003771420101504100171720ustar00rootroot00000000000000[package] name = "kitchen-sink" version = "0.1.0" edition = "2018" license = "Apache-2.0" authors = ["Apache Thrift Developers "] publish = false [dependencies] clap = "~2.33" bitflags = "=1.2" [dependencies.thrift] path = "../" thrift-0.16.0/lib/rs/test/Makefile.am000066400000000000000000000040501420101504100172660ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # THRIFT = $(top_builddir)/compiler/cpp/thrift stubs: thrifts/Base_One.thrift thrifts/Base_Two.thrift thrifts/Midlayer.thrift thrifts/Ultimate.thrift $(top_builddir)/test/Recursive.thrift $(THRIFT) $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_One.thrift $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_Two.thrift $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Midlayer.thrift $(THRIFT) -I ./thrifts -out src --gen rs thrifts/Ultimate.thrift $(THRIFT) -out src --gen rs $(top_builddir)/test/Recursive.thrift $(THRIFT) -out src --gen rs $(top_builddir)/test/Identifiers.thrift #THRIFT-4953 check: stubs $(CARGO) fmt --all -- --check $(CARGO) clippy --all -- -D warnings $(CARGO) build $(CARGO) test [ -d bin ] || mkdir bin cp target/debug/kitchen_sink_server bin/kitchen_sink_server cp target/debug/kitchen_sink_client bin/kitchen_sink_client clean-local: $(CARGO) clean -$(RM) Cargo.lock -$(RM) src/base_one.rs -$(RM) src/base_two.rs -$(RM) src/midlayer.rs -$(RM) src/ultimate.rs -$(RM) src/recursive.rs -$(RM) src/identifiers.rs -$(RM) -r bin EXTRA_DIST = \ Cargo.toml \ thrifts/Base_One.thrift \ thrifts/Base_Two.thrift \ thrifts/Midlayer.thrift \ thrifts/Ultimate.thrift \ src/lib.rs \ src/bin/kitchen_sink_server.rs \ src/bin/kitchen_sink_client.rs thrift-0.16.0/lib/rs/test/src/000077500000000000000000000000001420101504100160225ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test/src/bin/000077500000000000000000000000001420101504100165725ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test/src/bin/kitchen_sink_client.rs000066400000000000000000000176051420101504100231600ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use clap::{clap_app, value_t}; use std::convert::Into; use kitchen_sink::base_two::{TNapkinServiceSyncClient, TRamenServiceSyncClient}; use kitchen_sink::midlayer::{MealServiceSyncClient, TMealServiceSyncClient}; use kitchen_sink::recursive; use kitchen_sink::recursive::{CoRec, CoRec2, RecList, RecTree, TTestServiceSyncClient}; use kitchen_sink::ultimate::{FullMealServiceSyncClient, TFullMealServiceSyncClient}; use thrift; use thrift::protocol::{ TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, TCompactOutputProtocol, TInputProtocol, TOutputProtocol, }; use thrift::transport::{ ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel, TTcpChannel, WriteHalf, }; fn main() { match run() { Ok(()) => println!("kitchen sink client completed successfully"), Err(e) => { println!("kitchen sink client failed with error {:?}", e); std::process::exit(1); } } } fn run() -> thrift::Result<()> { let matches = clap_app!(rust_kitchen_sink_client => (version: "0.1.0") (author: "Apache Thrift Developers ") (about: "Thrift Rust kitchen sink client") (@arg host: --host +takes_value "Host on which the Thrift test server is located") (@arg port: --port +takes_value "Port on which the Thrift test server is listening") (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")") (@arg service: --service +takes_value "Service type to contact (\"part\", \"full\", \"recursive\")") ) .get_matches(); let host = matches.value_of("host").unwrap_or("127.0.0.1"); let port = value_t!(matches, "port", u16).unwrap_or(9090); let protocol = matches.value_of("protocol").unwrap_or("compact"); let service = matches.value_of("service").unwrap_or("part"); let (i_chan, o_chan) = tcp_channel(host, port)?; let (i_tran, o_tran) = ( TFramedReadTransport::new(i_chan), TFramedWriteTransport::new(o_chan), ); let (i_prot, o_prot): (Box, Box) = match protocol { "binary" => ( Box::new(TBinaryInputProtocol::new(i_tran, true)), Box::new(TBinaryOutputProtocol::new(o_tran, true)), ), "compact" => ( Box::new(TCompactInputProtocol::new(i_tran)), Box::new(TCompactOutputProtocol::new(o_tran)), ), unmatched => return Err(format!("unsupported protocol {}", unmatched).into()), }; run_client(service, i_prot, o_prot) } fn run_client( service: &str, i_prot: Box, o_prot: Box, ) -> thrift::Result<()> { match service { "full" => exec_full_meal_client(i_prot, o_prot), "part" => exec_meal_client(i_prot, o_prot), "recursive" => exec_recursive_client(i_prot, o_prot), _ => Err(thrift::Error::from(format!( "unknown service type {}", service ))), } } fn tcp_channel( host: &str, port: u16, ) -> thrift::Result<(ReadHalf, WriteHalf)> { let mut c = TTcpChannel::new(); c.open(&format!("{}:{}", host, port))?; c.split() } fn exec_meal_client( i_prot: Box, o_prot: Box, ) -> thrift::Result<()> { let mut client = MealServiceSyncClient::new(i_prot, o_prot); // client.full_meal(); // <-- IMPORTANT: if you uncomment this, compilation *should* fail // this is because the MealService struct does not contain the appropriate service marker // only the following three calls work execute_call("part", "ramen", || client.ramen(50)).map(|_| ())?; execute_call("part", "meal", || client.meal()).map(|_| ())?; execute_call("part", "napkin", || client.napkin()).map(|_| ())?; Ok(()) } fn exec_full_meal_client( i_prot: Box, o_prot: Box, ) -> thrift::Result<()> { let mut client = FullMealServiceSyncClient::new(i_prot, o_prot); execute_call("full", "ramen", || client.ramen(100)).map(|_| ())?; execute_call("full", "meal", || client.meal()).map(|_| ())?; execute_call("full", "napkin", || client.napkin()).map(|_| ())?; execute_call("full", "full meal", || client.full_meal()).map(|_| ())?; Ok(()) } fn exec_recursive_client( i_prot: Box, o_prot: Box, ) -> thrift::Result<()> { let mut client = recursive::TestServiceSyncClient::new(i_prot, o_prot); let tree = RecTree { children: Some(vec![Box::new(RecTree { children: Some(vec![ Box::new(RecTree { children: None, item: Some(3), }), Box::new(RecTree { children: None, item: Some(4), }), ]), item: Some(2), })]), item: Some(1), }; let expected_tree = RecTree { children: Some(vec![Box::new(RecTree { children: Some(vec![ Box::new(RecTree { children: Some(Vec::new()), // remote returns an empty list item: Some(3), }), Box::new(RecTree { children: Some(Vec::new()), // remote returns an empty list item: Some(4), }), ]), item: Some(2), })]), item: Some(1), }; let returned_tree = execute_call("recursive", "echo_tree", || client.echo_tree(tree.clone()))?; if returned_tree != expected_tree { return Err(format!( "mismatched recursive tree {:?} {:?}", expected_tree, returned_tree ) .into()); } let list = RecList { nextitem: Some(Box::new(RecList { nextitem: Some(Box::new(RecList { nextitem: None, item: Some(3), })), item: Some(2), })), item: Some(1), }; let returned_list = execute_call("recursive", "echo_list", || client.echo_list(list.clone()))?; if returned_list != list { return Err(format!("mismatched recursive list {:?} {:?}", list, returned_list).into()); } let co_rec = CoRec { other: Some(Box::new(CoRec2 { other: Some(CoRec { other: Some(Box::new(CoRec2 { other: None })), }), })), }; let returned_co_rec = execute_call("recursive", "echo_co_rec", || { client.echo_co_rec(co_rec.clone()) })?; if returned_co_rec != co_rec { return Err(format!("mismatched co_rec {:?} {:?}", co_rec, returned_co_rec).into()); } Ok(()) } fn execute_call(service_type: &str, call_name: &str, mut f: F) -> thrift::Result where F: FnMut() -> thrift::Result, { let res = f(); match res { Ok(_) => println!("{}: completed {} call", service_type, call_name), Err(ref e) => println!( "{}: failed {} call with error {:?}", service_type, call_name, e ), } res } thrift-0.16.0/lib/rs/test/src/bin/kitchen_sink_server.rs000066400000000000000000000226311420101504100232030ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use clap::{clap_app, value_t}; use thrift; use thrift::protocol::{ TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory, TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory, }; use thrift::server::TServer; use thrift::transport::{ TFramedReadTransportFactory, TFramedWriteTransportFactory, TReadTransportFactory, TWriteTransportFactory, }; use kitchen_sink::base_one::Noodle; use kitchen_sink::base_two::{ BrothType, Napkin, NapkinServiceSyncHandler, Ramen, RamenServiceSyncHandler, }; use kitchen_sink::midlayer::{ Dessert, Meal, MealServiceSyncHandler, MealServiceSyncProcessor, Pie, }; use kitchen_sink::recursive; use kitchen_sink::ultimate::FullMealAndDrinksServiceSyncHandler; use kitchen_sink::ultimate::{ Drink, FullMeal, FullMealAndDrinks, FullMealAndDrinksServiceSyncProcessor, FullMealServiceSyncHandler, }; fn main() { match run() { Ok(()) => println!("kitchen sink server completed successfully"), Err(e) => { println!("kitchen sink server failed with error {:?}", e); std::process::exit(1); } } } fn run() -> thrift::Result<()> { let matches = clap_app!(rust_kitchen_sink_server => (version: "0.1.0") (author: "Apache Thrift Developers ") (about: "Thrift Rust kitchen sink test server") (@arg port: --port +takes_value "port on which the test server listens") (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")") (@arg service: --service +takes_value "Service type to contact (\"part\", \"full\", \"recursive\")") ) .get_matches(); let port = value_t!(matches, "port", u16).unwrap_or(9090); let protocol = matches.value_of("protocol").unwrap_or("compact"); let service = matches.value_of("service").unwrap_or("part"); let listen_address = format!("127.0.0.1:{}", port); println!("binding to {}", listen_address); let r_transport_factory = TFramedReadTransportFactory::new(); let w_transport_factory = TFramedWriteTransportFactory::new(); let (i_protocol_factory, o_protocol_factory): ( Box, Box, ) = match &*protocol { "binary" => ( Box::new(TBinaryInputProtocolFactory::new()), Box::new(TBinaryOutputProtocolFactory::new()), ), "compact" => ( Box::new(TCompactInputProtocolFactory::new()), Box::new(TCompactOutputProtocolFactory::new()), ), unknown => { return Err(format!("unsupported transport type {}", unknown).into()); } }; // FIXME: should processor be boxed as well? // // [sigh] I hate Rust generics implementation // // I would have preferred to build a server here, return it, and then do // the common listen-and-handle stuff, but since the server doesn't have a // common type (because each match arm instantiates a server with a // different processor) this isn't possible. // // Since what I'm doing is uncommon I'm just going to duplicate the code match &*service { "part" => run_meal_server( &listen_address, r_transport_factory, i_protocol_factory, w_transport_factory, o_protocol_factory, ), "full" => run_full_meal_server( &listen_address, r_transport_factory, i_protocol_factory, w_transport_factory, o_protocol_factory, ), "recursive" => run_recursive_server( &listen_address, r_transport_factory, i_protocol_factory, w_transport_factory, o_protocol_factory, ), unknown => Err(format!("unsupported service type {}", unknown).into()), } } fn run_meal_server( listen_address: &str, r_transport_factory: RTF, i_protocol_factory: IPF, w_transport_factory: WTF, o_protocol_factory: OPF, ) -> thrift::Result<()> where RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static, { let processor = MealServiceSyncProcessor::new(PartHandler {}); let mut server = TServer::new( r_transport_factory, i_protocol_factory, w_transport_factory, o_protocol_factory, processor, 1, ); server.listen(listen_address) } fn run_full_meal_server( listen_address: &str, r_transport_factory: RTF, i_protocol_factory: IPF, w_transport_factory: WTF, o_protocol_factory: OPF, ) -> thrift::Result<()> where RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static, { let processor = FullMealAndDrinksServiceSyncProcessor::new(FullHandler {}); let mut server = TServer::new( r_transport_factory, i_protocol_factory, w_transport_factory, o_protocol_factory, processor, 1, ); server.listen(listen_address) } struct PartHandler; impl MealServiceSyncHandler for PartHandler { fn handle_meal(&self) -> thrift::Result { println!("part: handling meal call"); Ok(meal()) } } impl RamenServiceSyncHandler for PartHandler { fn handle_ramen(&self, _: i32) -> thrift::Result { println!("part: handling ramen call"); Ok(ramen()) } } impl NapkinServiceSyncHandler for PartHandler { fn handle_napkin(&self) -> thrift::Result { println!("part: handling napkin call"); Ok(napkin()) } } // full service // struct FullHandler; impl FullMealAndDrinksServiceSyncHandler for FullHandler { fn handle_full_meal_and_drinks(&self) -> thrift::Result { println!("full_meal_and_drinks: handling full meal and drinks call"); Ok(FullMealAndDrinks::new(full_meal(), Drink::CANADIAN_WHISKY)) } fn handle_best_pie(&self) -> thrift::Result { println!("full_meal_and_drinks: handling pie call"); Ok(Pie::MISSISSIPPI_MUD) // I prefer Pie::Pumpkin, but I have to check that casing works } } impl FullMealServiceSyncHandler for FullHandler { fn handle_full_meal(&self) -> thrift::Result { println!("full: handling full meal call"); Ok(full_meal()) } } impl MealServiceSyncHandler for FullHandler { fn handle_meal(&self) -> thrift::Result { println!("full: handling meal call"); Ok(meal()) } } impl RamenServiceSyncHandler for FullHandler { fn handle_ramen(&self, _: i32) -> thrift::Result { println!("full: handling ramen call"); Ok(ramen()) } } impl NapkinServiceSyncHandler for FullHandler { fn handle_napkin(&self) -> thrift::Result { println!("full: handling napkin call"); Ok(napkin()) } } fn full_meal() -> FullMeal { FullMeal::new(meal(), Dessert::Port("Graham's Tawny".to_owned())) } fn meal() -> Meal { Meal::new(noodle(), ramen()) } fn noodle() -> Noodle { Noodle::new("spelt".to_owned(), 100) } fn ramen() -> Ramen { Ramen::new("Mr Ramen".to_owned(), 72, BrothType::MISO) } fn napkin() -> Napkin { Napkin {} } fn run_recursive_server( listen_address: &str, r_transport_factory: RTF, i_protocol_factory: IPF, w_transport_factory: WTF, o_protocol_factory: OPF, ) -> thrift::Result<()> where RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static, { let processor = recursive::TestServiceSyncProcessor::new(RecursiveTestServerHandler {}); let mut server = TServer::new( r_transport_factory, i_protocol_factory, w_transport_factory, o_protocol_factory, processor, 1, ); server.listen(listen_address) } struct RecursiveTestServerHandler; impl recursive::TestServiceSyncHandler for RecursiveTestServerHandler { fn handle_echo_tree(&self, tree: recursive::RecTree) -> thrift::Result { println!("{:?}", tree); Ok(tree) } fn handle_echo_list(&self, lst: recursive::RecList) -> thrift::Result { println!("{:?}", lst); Ok(lst) } fn handle_echo_co_rec(&self, item: recursive::CoRec) -> thrift::Result { println!("{:?}", item); Ok(item) } } thrift-0.16.0/lib/rs/test/src/lib.rs000066400000000000000000000030531420101504100171370ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. pub mod base_one; pub mod base_two; pub mod midlayer; pub mod ultimate; pub mod recursive; #[cfg(test)] mod tests { use std::default::Default; use super::*; #[test] fn must_be_able_to_use_constructor() { let _ = midlayer::Meal::new(Some(base_one::Noodle::default()), None); } #[test] fn must_be_able_to_use_constructor_with_no_fields() { let _ = midlayer::Meal::new(None, None); } #[test] fn must_be_able_to_use_constructor_without_option_wrap() { let _ = midlayer::Meal::new(base_one::Noodle::default(), None); } #[test] fn must_be_able_to_use_defaults() { let _ = midlayer::Meal { noodle: Some(base_one::Noodle::default()), ..Default::default() }; } } thrift-0.16.0/lib/rs/test/thrifts/000077500000000000000000000000001420101504100167165ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test/thrifts/Base_One.thrift000066400000000000000000000041671420101504100216230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ typedef i64 Temperature typedef i8 Size typedef string Location const i32 BoilingPoint = 100 const list Temperatures = [10, 11, 22, 33] // IMPORTANT: temps should end with ".0" because this tests // that we don't have a problem with const float list generation const list CommonTemperatures = [300.0, 450.0] const double MealsPerDay = 2.5; const string DefaultRecipeName = "Soup-rise of the Day" const binary DefaultRecipeBinary = "Soup-rise of the 01010101" struct Noodle { 1: string flourType 2: Temperature cookTemp } struct Spaghetti { 1: optional list noodles } const Noodle SpeltNoodle = { "flourType": "spelt", "cookTemp": 110 } struct MeasuringSpoon { 1: Size size } struct MeasuringCup { 1: double millis } union MeasuringAids { 1: MeasuringSpoon spoon 2: MeasuringCup cup } struct CookingTemperatures { 1: set commonTemperatures 2: list usedTemperatures 3: map fahrenheitToCentigradeConversions } struct Recipe { 1: string recipeName 2: string cuisine 3: i8 page } union CookingTools { 1: set measuringSpoons 2: map measuringCups, 3: list recipes } thrift-0.16.0/lib/rs/test/thrifts/Base_Two.thrift000066400000000000000000000024731420101504100216510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ const i32 WaterWeight = 200 enum brothType { Miso, shouyu, } struct Ramen { 1: optional string ramenType 2: required i32 noodleCount 3: brothType broth } struct Napkin { // empty } service NapkinService { Napkin napkin() } service RamenService extends NapkinService { Ramen ramen(1: i32 requestedNoodleCount) } /* const struct CookedRamen = { "bar": 10 } */ thrift-0.16.0/lib/rs/test/thrifts/Midlayer.thrift000066400000000000000000000036201420101504100217070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ include "Base_One.thrift" include "Base_Two.thrift" const i32 WaterBoilingPoint = Base_One.BoilingPoint const map TemperatureNames = { "freezing": 0, "boiling": 100 } const map, map, string>> MyConstNestedMap = { [0, 1, 2, 3]: { ["foo"]: "bar" }, [20]: { ["nut", "ton"] : "bar" }, [30, 40]: { ["bouncy", "tinkly"]: "castle" } } const list> MyConstNestedList = [ [0, 1, 2], [3, 4, 5], [6, 7, 8] ] const set> MyConstNestedSet = [ [0, 1, 2], [3, 4, 5], [6, 7, 8] ] enum Pie { PUMPKIN, apple, // intentionally poorly cased STRAWBERRY_RHUBARB, Key_Lime, // intentionally poorly cased coconut_Cream, // intentionally poorly cased mississippi_mud, // intentionally poorly cased } struct Meal { 1: Base_One.Noodle noodle 2: Base_Two.Ramen ramen } union Dessert { 1: string port 2: string iceWine } service MealService extends Base_Two.RamenService { Meal meal() } thrift-0.16.0/lib/rs/test/thrifts/Ultimate.thrift000066400000000000000000000035501420101504100217270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ include "Midlayer.thrift" enum Drink { WATER, WHISKEY, WINE, scotch, // intentionally poorly cased LATE_HARVEST_WINE, India_Pale_Ale, // intentionally poorly cased apple_cider, // intentially poorly cased belgian_Ale, // intentionally poorly cased Canadian_whisky, // intentionally poorly cased } const map RankedPies = { 1: Midlayer.Pie.PUMPKIN, 2: Midlayer.Pie.STRAWBERRY_RHUBARB, 3: Midlayer.Pie.apple, 4: Midlayer.Pie.mississippi_mud, 5: Midlayer.Pie.coconut_Cream, 6: Midlayer.Pie.Key_Lime, } struct FullMeal { 1: required Midlayer.Meal meal 2: required Midlayer.Dessert dessert } struct FullMealAndDrinks { 1: required FullMeal fullMeal 2: optional Drink drink } service FullMealService extends Midlayer.MealService { FullMeal fullMeal() } service FullMealAndDrinksService extends FullMealService { FullMealAndDrinks fullMealAndDrinks() Midlayer.Pie bestPie() } thrift-0.16.0/lib/rs/test_recursive/000077500000000000000000000000001420101504100173225ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test_recursive/Cargo.toml000066400000000000000000000004371420101504100212560ustar00rootroot00000000000000[package] name = "thrift_4098_custom_rust_namespace_support" description = "Test namespace support in generated thrift files using recursive Make generation" version = "0.1.0" authors = ["Allen George "] edition = "2018" [dependencies] thrift = { path = "../" } thrift-0.16.0/lib/rs/test_recursive/Makefile.am000066400000000000000000000017311420101504100213600ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = src check: $(CARGO) fmt --all -- --check $(CARGO) clippy --all -- -D warnings $(CARGO) build $(CARGO) test clean-local: $(CARGO) clean -$(RM) Cargo.lock EXTRA_DIST = \ Cargo.toml thrift-0.16.0/lib/rs/test_recursive/src/000077500000000000000000000000001420101504100201115ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test_recursive/src/Makefile.am000066400000000000000000000020151420101504100221430ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . transit maintenance THRIFT = $(top_builddir)/compiler/cpp/thrift stubs: Vehicles.thrift $(THRIFT) $(THRIFT) -I . -out . --gen rs Vehicles.thrift check: stubs clean-local: -$(RM) vehicles.rs EXTRA_DIST = \ lib.rs \ Vehicles.thrift thrift-0.16.0/lib/rs/test_recursive/src/Vehicles.thrift000066400000000000000000000021471420101504100231010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ typedef i16 Capacity enum Material { Steel = 0 Aluminum = 1 } struct VehicleIdentifier { 1: string manufacturer 2: string model 3: list qualifiers } thrift-0.16.0/lib/rs/test_recursive/src/lib.rs000066400000000000000000000234251420101504100212330ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #![allow(dead_code)] pub mod transit; pub mod vehicles; pub mod maintenance; mod server { use crate::maintenance::maintenance_facility::{ BigBarnSyncHandler, MultimodalFacilitySyncHandler, }; use crate::transit::buses::{Bus, GarageSyncHandler}; use crate::transit::buses::{Powertrain, Route as BusRoute}; use crate::transit::light::streetcars::{ BarnSyncHandler, Flexity, RollingStock, Route, RouteNumber, Streetcar, }; use crate::transit::services::city_services::TransitImprovements; use crate::transit::trains::Locomotive; use crate::transit::transporters::{FlatcarConsist, SingleVehicleTransporter}; use crate::vehicles::Material; use thrift::Result; // // implement a whole bunch of handler methods just to make sure I can, and that everything compiles // pub struct AllInOneHandler; impl BigBarnSyncHandler for AllInOneHandler { fn handle_add_streetcar(&self, route: Route) -> Result { if let Some(route_number) = route.id { match route_number { RouteNumber::LAKESHORE => Ok(Streetcar { id: Some(4417), stock: Some(RollingStock::Flexity(Flexity { materials: Some(vec![Material::STEEL, Material::ALUMINUM]), locomotive: Some(Locomotive::ELECTRIC_PANTOGRAPH), })), route: Some(Route { id: Some(RouteNumber::LAKESHORE), improvements: None, }), }), _ => Err(thrift::Error::from(format!( "Cannot create streetcar for route number {}", route_number.0 ))), } } else { Err(thrift::Error::from("Can't add a streetcar")) } } } impl BarnSyncHandler for AllInOneHandler { fn handle_upgrade_streetcar(&self, streetcar: Streetcar) -> Result { if let Some(rolling_stock) = streetcar.stock { match rolling_stock { RollingStock::Clrv(_) => Ok(Streetcar { stock: Some(RollingStock::Flexity(Flexity { materials: Some(vec![Material::STEEL, Material::ALUMINUM]), locomotive: Some(Locomotive::ELECTRIC_PANTOGRAPH), })), ..streetcar }), RollingStock::Flexity(_) => { Err(thrift::Error::from("Streetcar already upgraded")) } } } else { Err(thrift::Error::from("Can't upgrade streetcar")) } } } impl MultimodalFacilitySyncHandler for AllInOneHandler { fn handle_build_transporter( &self, source: String, destination: String, consist: FlatcarConsist, ) -> Result { Ok(SingleVehicleTransporter { consist: Some(consist), source: Some(source), destination: Some(destination), }) } } impl GarageSyncHandler for AllInOneHandler { fn handle_upgrade_bus(&self, bus: Bus) -> Result { if let Some(p) = bus.powertrain { match p { Powertrain::COMPRESSED_NATURAL_GAS => Ok(Bus { powertrain: Some(Powertrain::DIESEL), ..bus }), _ => Err(thrift::Error::from("Cannot upgrade from this powertrain")), } } else { Err(thrift::Error::from("Cannot upgrade bus")) } } fn handle_improvements_for_route( &self, route: BusRoute, ) -> Result> { Ok(route .improvements .expect("Expecting a list of improvements")) } } } #[cfg(test)] mod tests { // // TODO: consider using the generated client/server and doing a round-trip // use crate::server::AllInOneHandler; use crate::transit::buses::{Bus, Powertrain, Route as BusRoute, DEFAULT4WHEELCAPACITY}; use crate::transit::light::light_rail::Lrt; use crate::transit::light::streetcars::{ BarnSyncHandler, Flexity, RollingStock, Route, RouteNumber, Streetcar, CLRV, }; use crate::transit::services::city_services::TransitImprovements; use crate::transit::trains::Locomotive; use crate::transit::transporters::{FlatcarConsist, SingleVehicleTransporter}; use crate::vehicles::{Material, VehicleIdentifier}; use crate::maintenance::maintenance_facility::{ BigBarnSyncHandler, MultimodalFacilitySyncHandler, }; use crate::transit::buses::GarageSyncHandler; #[test] fn handle_add_streetcar_compiles_and_returns_expected_value() { let expected = Streetcar { id: Some(4417), stock: Some(RollingStock::Flexity(Flexity { materials: Some(vec![Material::STEEL, Material::ALUMINUM]), locomotive: Some(Locomotive::ELECTRIC_PANTOGRAPH), })), route: Some(Route { id: Some(RouteNumber::LAKESHORE), improvements: None, }), }; let handler = AllInOneHandler {}; let actual = handler .handle_add_streetcar(Route { id: Some(RouteNumber::LAKESHORE), improvements: None, }) .expect("Expected a result"); assert_eq!(expected, actual) } #[test] fn handle_upgrade_streetcar_compiles_and_returns_expected_value() { let input = Streetcar { stock: Some(RollingStock::Clrv(CLRV { materials: Some(vec![Material::STEEL, Material::ALUMINUM]), locomotive: Some(Locomotive::ELECTRIC_POLE), })), id: Some(4415), route: Some(Route { id: Some(RouteNumber::SPADINA), improvements: Some(vec![TransitImprovements::DEDICATED_RIGHT_OF_WAY]), }), }; let expected = Streetcar { stock: Some(RollingStock::Flexity(Flexity { materials: Some(vec![Material::STEEL, Material::ALUMINUM]), locomotive: Some(Locomotive::ELECTRIC_PANTOGRAPH), })), id: Some(4415), route: Some(Route { id: Some(RouteNumber::SPADINA), improvements: Some(vec![TransitImprovements::DEDICATED_RIGHT_OF_WAY]), }), }; let handler = AllInOneHandler {}; let actual = handler .handle_upgrade_streetcar(input) .expect("Expected an upgraded streetcar"); assert_eq!(expected, actual) } #[test] fn handle_build_transporter_compiles_and_returns_expected_value() { let consist = FlatcarConsist::Lrt(Lrt { materials: Some(vec![Material::STEEL, Material::ALUMINUM]), locomotive: Some(Locomotive::ELECTRIC_PANTOGRAPH), }); let expected = SingleVehicleTransporter { consist: Some(consist.clone()), source: Some("905".to_owned()), destination: Some("416".to_owned()), }; let handler = AllInOneHandler {}; let actual = handler .handle_build_transporter("905".to_owned(), "416".to_owned(), consist) .expect("Expected a transporter"); assert_eq!(expected, actual) } #[test] fn handle_upgrade_bus_compiles_and_returns_expected_value() { let bus = Bus { identifier: Some(VehicleIdentifier { manufacturer: Some("Orion".to_owned()), model: Some("Orion 07.501 NG HEV".to_owned()), qualifiers: None, }), capacity: Some(DEFAULT4WHEELCAPACITY), powertrain: Some(Powertrain::COMPRESSED_NATURAL_GAS), materials: Some(vec![Material::STEEL, Material::ALUMINUM]), }; let expected = Bus { powertrain: Some(Powertrain::DIESEL), ..(bus.clone()) }; let handler = AllInOneHandler {}; let actual = handler .handle_upgrade_bus(bus) .expect("Expected improved bus"); assert_eq!(expected, actual) } #[test] fn handle_improvements_for_route_compiles_and_returns_expected_value() { let expected = vec![TransitImprovements::TRANSIT_SIGNAL_PRIORITY]; let bus_route = BusRoute { route_id: Some("320".to_owned()), improvements: Some(expected.clone()), }; let handler = AllInOneHandler {}; let actual = handler .handle_improvements_for_route(bus_route) .expect("Expected list of transit improvements"); assert_eq!(expected, actual) } } thrift-0.16.0/lib/rs/test_recursive/src/maintenance/000077500000000000000000000000001420101504100223735ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test_recursive/src/maintenance/MaintenanceFacility.thrift000066400000000000000000000025621420101504100275310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace rs maintenance include "Buses.thrift" include "LightRail.thrift" include "Streetcars.thrift" include "Transporters.thrift" service BigBarn extends Streetcars.Barn { Streetcars.Streetcar addStreetcar(1: Streetcars.Route route) } service MultimodalFacility extends Buses.Garage { Transporters.SingleVehicleTransporter buildTransporter(1: string source, 2: string destination, 3: Transporters.FlatcarConsist consist) }thrift-0.16.0/lib/rs/test_recursive/src/maintenance/Makefile.am000066400000000000000000000024331420101504100244310ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . THRIFT = $(top_builddir)/compiler/cpp/thrift stubs: ../Vehicles.thrift ../transit/Buses.thrift ../transit/Trains.thrift ../transit/Transporters.thrift ../transit/services/CityServices.thrift ../transit/light/LightRail.thrift ../transit/light/Streetcars.thrift $(THRIFT) $(THRIFT) -I . -I ../ -I ../transit -I ../transit/services -I ../transit/light -out . --gen rs MaintenanceFacility.thrift check: stubs clean-local: -$(RM) maintenance_facility.rs EXTRA_DIST = \ mod.rs \ MaintenanceFacility.thrift thrift-0.16.0/lib/rs/test_recursive/src/maintenance/mod.rs000066400000000000000000000014741420101504100235260ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. pub mod maintenance_facility; thrift-0.16.0/lib/rs/test_recursive/src/transit/000077500000000000000000000000001420101504100215755ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test_recursive/src/transit/Buses.thrift000066400000000000000000000030701420101504100241000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace rs transit include "CityServices.thrift" include "Vehicles.thrift" const Vehicles.Capacity DEFAULT4WHEELCAPACITY = 30 enum Powertrain { DIESEL = 0 BIO_DIESEL = 1 COMPRESSED_NATURAL_GAS = 2 TROLLEY = 3 HYBRID = 4 BATTERY = 5 } struct Bus { 1: Vehicles.VehicleIdentifier identifier 2: Vehicles.Capacity capacity 3: Powertrain powertrain 4: list materials } struct Route { 1: string routeId 2: list improvements } service Garage { Bus upgradeBus(1: Bus bus) list improvementsForRoute(1: Route route) }thrift-0.16.0/lib/rs/test_recursive/src/transit/Makefile.am000066400000000000000000000027231420101504100236350ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # intentionally added a cyclic dependency between '.' and 'light' SUBDIRS = . light services THRIFT = $(top_builddir)/compiler/cpp/thrift stubs: ../Vehicles.thrift Buses.thrift Trains.thrift Transporters.thrift services/CityServices.thrift light/LightRail.thrift light/Streetcars.thrift $(THRIFT) $(THRIFT) -I . -I ../ -I ./services -I ./light -out . --gen rs Buses.thrift $(THRIFT) -I . -I ../ -I ./services -I ./light -out . --gen rs Trains.thrift $(THRIFT) -I . -I ../ -I ./services -I ./light -out . --gen rs Transporters.thrift check: stubs clean-local: -$(RM) buses.rs -$(RM) trains.rs -$(RM) transporters.rs EXTRA_DIST = \ mod.rs \ Buses.thrift \ Trains.thrift \ Transporters.thrift thrift-0.16.0/lib/rs/test_recursive/src/transit/Trains.thrift000066400000000000000000000021441420101504100242600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace rs transit enum Locomotive { Steam = 0 ElectricPole = 1 ElectricPantograph = 2 ElectricThirdRail = 3 DieselMechanical = 4 DieselElectric = 5 } thrift-0.16.0/lib/rs/test_recursive/src/transit/Transporters.thrift000066400000000000000000000023661420101504100255340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace rs transit include "Buses.thrift" include "LightRail.thrift" include "Streetcars.thrift" union FlatcarConsist { 1: LightRail.Lrt lrt 2: Streetcars.Streetcar streetcar 3: Buses.Bus bus } struct SingleVehicleTransporter { 1: FlatcarConsist consist 2: string source 3: string destination } thrift-0.16.0/lib/rs/test_recursive/src/transit/light/000077500000000000000000000000001420101504100227045ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test_recursive/src/transit/light/LightRail.thrift000066400000000000000000000025621420101504100260120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ include "CityServices.thrift" include "Trains.thrift" include "Vehicles.thrift" namespace rs transit.light struct Lrt { 1: list materials 2: Trains.Locomotive locomotive } enum Route { EglintonCrosstown = 0 FinchWest = 1 } struct Line { 1: Lrt lrt 2: Route route 3: list improvements = [] // ABSOLUTELY NONE BY DEFAULT! } service Msf { Lrt fixLrt(1: Lrt lrt) }thrift-0.16.0/lib/rs/test_recursive/src/transit/light/Makefile.am000066400000000000000000000023641420101504100247450ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . THRIFT = $(top_builddir)/compiler/cpp/thrift stubs: ../../Vehicles.thrift ../Trains.thrift ../services/CityServices.thrift LightRail.thrift Streetcars.thrift $(THRIFT) $(THRIFT) -I . -I ../../ -I ../ -I ../services -out . --gen rs LightRail.thrift $(THRIFT) -I . -I ../../ -I ../ -I ../services -out . --gen rs Streetcars.thrift check: stubs clean-local: -$(RM) light_rail.rs -$(RM) streetcars.rs EXTRA_DIST = \ mod.rs \ LightRail.thrift \ Streetcars.thrift thrift-0.16.0/lib/rs/test_recursive/src/transit/light/Streetcars.thrift000066400000000000000000000033651420101504100262540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ include "CityServices.thrift" include "Trains.thrift" include "Vehicles.thrift" namespace rs transit.light struct CLRV { 1: list materials 2: Trains.Locomotive locomotive } struct Flexity { 1: list materials 2: Trains.Locomotive locomotive } union RollingStock { 1: CLRV clrv 2: Flexity flexity } enum RouteNumber { Queen = 501 Downtowner = 502 Kingston = 503 King = 504 Dundas = 505 Carlton = 506 Lakeshore = 508 Harbourfront = 509 Spadina = 510 Bathurst = 511 StClair = 512 } struct Route { 1: RouteNumber id 2: list improvements = [] // ABSOLUTELY NONE! } struct Streetcar { 1: i16 id 2: RollingStock stock 3: Route route } service Barn { Streetcar upgradeStreetcar(1: Streetcar streetcar) }thrift-0.16.0/lib/rs/test_recursive/src/transit/light/mod.rs000066400000000000000000000015061420101504100240330ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. pub mod light_rail; pub mod streetcars; thrift-0.16.0/lib/rs/test_recursive/src/transit/mod.rs000066400000000000000000000015641420101504100227300ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. pub mod buses; pub mod light; pub mod services; pub mod trains; pub mod transporters; thrift-0.16.0/lib/rs/test_recursive/src/transit/services/000077500000000000000000000000001420101504100234205ustar00rootroot00000000000000thrift-0.16.0/lib/rs/test_recursive/src/transit/services/CityServices.thrift000066400000000000000000000020601420101504100272540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace rs transit.services enum TransitImprovements { TransitSignalPriority = 1 DedicatedRightOfWay = 2 } thrift-0.16.0/lib/rs/test_recursive/src/transit/services/Makefile.am000066400000000000000000000020121420101504100254470ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . THRIFT = $(top_builddir)/compiler/cpp/thrift stubs: CityServices.thrift $(THRIFT) $(THRIFT) -I . -out . --gen rs CityServices.thrift check: stubs clean-local: -$(RM) city_services.rs EXTRA_DIST = \ mod.rs \ CityServices.thrift thrift-0.16.0/lib/rs/test_recursive/src/transit/services/mod.rs000066400000000000000000000014651420101504100245530ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. pub mod city_services; thrift-0.16.0/lib/st/000077500000000000000000000000001420101504100142565ustar00rootroot00000000000000thrift-0.16.0/lib/st/README.md000066400000000000000000000024031420101504100155340ustar00rootroot00000000000000Thrift SmallTalk Software Library Last updated Nov 2007 License ======= Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Contains some contributions under the Thrift Software License. Please see doc/old-thrift-license.txt in the Thrift distribution for details. Library ======= To get started, just file in thrift.st with Squeak, run thrift -st on the tutorial .thrift files (and file in the resulting code), and then: calc := CalculatorClient binaryOnHost: 'localhost' port: '9090' calc addNum1: 10 num2: 15 Tested in Squeak 3.7, but should work fine with anything later. thrift-0.16.0/lib/st/coding_standards.md000066400000000000000000000001031420101504100201000ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/st/package.xml000066400000000000000000000016751420101504100164040ustar00rootroot00000000000000 libthrift-st thrift.st thrift.st thrift-0.16.0/lib/st/thrift.st000066400000000000000000000546401420101504100161370ustar00rootroot00000000000000" Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the License); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Contains some contributions under the Thrift Software License. Please see doc/old-thrift-license.txt in the Thrift distribution for details. " SystemOrganization addCategory: #Thrift! SystemOrganization addCategory: #'Thrift-Protocol'! SystemOrganization addCategory: #'Thrift-Transport'! Error subclass: #TError instanceVariableNames: 'code' classVariableNames: '' poolDictionaries: '' category: 'Thrift'! !TError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! signalWithCode: anInteger self new code: anInteger; signal! ! !TError methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! code ^ code! ! !TError methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! code: anInteger code := anInteger! ! TError subclass: #TProtocolError instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! !TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:39'! badVersion ^ 4! ! !TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:39'! invalidData ^ 1! ! !TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:39'! negativeSize ^ 2! ! !TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:40'! sizeLimit ^ 3! ! !TProtocolError class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:40'! unknown ^ 0! ! TError subclass: #TTransportError instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Transport'! TTransportError subclass: #TTransportClosedError instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Transport'! Object subclass: #TClient instanceVariableNames: 'iprot oprot seqid remoteSeqid' classVariableNames: '' poolDictionaries: '' category: 'Thrift'! !TClient class methodsFor: 'as yet unclassified' stamp: 'pc 11/7/2007 06:00'! binaryOnHost: aString port: anInteger | sock | sock := TSocket new host: aString; port: anInteger; open; yourself. ^ self new inProtocol: (TBinaryProtocol new transport: sock); yourself! ! !TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 23:03'! inProtocol: aProtocol iprot := aProtocol. oprot ifNil: [oprot := aProtocol]! ! !TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 04:28'! nextSeqid ^ seqid ifNil: [seqid := 0] ifNotNil: [seqid := seqid + 1]! ! !TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:51'! outProtocol: aProtocol oprot := aProtocol! ! !TClient methodsFor: 'as yet unclassified' stamp: 'pc 10/28/2007 15:32'! validateRemoteMessage: aMsg remoteSeqid ifNil: [remoteSeqid := aMsg seqid] ifNotNil: [(remoteSeqid + 1) = aMsg seqid ifFalse: [TProtocolError signal: 'Bad seqid: ', aMsg seqid asString, '; wanted: ', remoteSeqid asString]. remoteSeqid := aMsg seqid]! ! Object subclass: #TField instanceVariableNames: 'name type id' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! !TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! id ^ id ifNil: [0]! ! !TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:44'! id: anInteger id := anInteger! ! !TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! name ^ name ifNil: ['']! ! !TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:44'! name: anObject name := anObject! ! !TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! type ^ type ifNil: [TType stop]! ! !TField methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:44'! type: anInteger type := anInteger! ! Object subclass: #TMessage instanceVariableNames: 'name seqid type' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! TMessage subclass: #TCallMessage instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! !TCallMessage methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:53'! type ^ 1! ! !TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! name ^ name ifNil: ['']! ! !TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:35'! name: aString name := aString! ! !TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:05'! seqid ^ seqid ifNil: [0]! ! !TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:35'! seqid: anInteger seqid := anInteger! ! !TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:06'! type ^ type ifNil: [0]! ! !TMessage methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:35'! type: anInteger type := anInteger! ! Object subclass: #TProtocol instanceVariableNames: 'transport' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! TProtocol subclass: #TBinaryProtocol instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 04:24'! intFromByteArray: buf | vals | vals := Array new: buf size. 1 to: buf size do: [:n | vals at: n put: ((buf at: n) bitShift: (buf size - n) * 8)]. ^ vals sum! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 18:46'! readBool ^ self readByte isZero not! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/25/2007 00:02'! readByte ^ (self transport read: 1) first! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/28/2007 16:24'! readDouble | val | val := Float new: 2. ^ val basicAt: 1 put: (self readRawInt: 4); basicAt: 2 put: (self readRawInt: 4); yourself! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 20:02'! readFieldBegin | field | field := TField new type: self readByte. ^ field type = TType stop ifTrue: [field] ifFalse: [field id: self readI16; yourself]! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:15'! readI16 ^ self readInt: 2! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:20'! readI32 ^ self readInt: 4! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:20'! readI64 ^ self readInt: 8! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 02:35'! readInt: size | buf val | buf := transport read: size. val := self intFromByteArray: buf. ^ buf first > 16r7F ifTrue: [self unsignedInt: val size: size] ifFalse: [val]! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:57'! readListBegin ^ TList new elemType: self readByte; size: self readI32! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:58'! readMapBegin ^ TMap new keyType: self readByte; valueType: self readByte; size: self readI32! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 04:22'! readMessageBegin | version | version := self readI32. (version bitAnd: self versionMask) = self version1 ifFalse: [TProtocolError signalWithCode: TProtocolError badVersion]. ^ TMessage new type: (version bitAnd: 16r000000FF); name: self readString; seqid: self readI32! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 10/28/2007 16:24'! readRawInt: size ^ self intFromByteArray: (transport read: size)! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 00:59'! readSetBegin "element type, size" ^ TSet new elemType: self readByte; size: self readI32! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 02/07/2009 19:00'! readString | sz | sz := self readI32. ^ sz > 0 ifTrue: [(transport read: sz) asString] ifFalse: ['']! ! !TBinaryProtocol methodsFor: 'reading' stamp: 'pc 11/1/2007 04:22'! unsignedInt: val size: size ^ 0 - ((val - 1) bitXor: ((2 raisedTo: (size * 8)) - 1))! ! !TBinaryProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:13'! version1 ^ 16r80010000 ! ! !TBinaryProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 18:01'! versionMask ^ 16rFFFF0000! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 18:35'! write: aString transport write: aString! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:23'! writeBool: bool bool ifTrue: [self writeByte: 1] ifFalse: [self writeByte: 0]! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/26/2007 09:31'! writeByte: aNumber aNumber > 16rFF ifTrue: [TError signal: 'writeByte too big']. transport write: (Array with: aNumber)! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/28/2007 16:16'! writeDouble: aDouble self writeI32: (aDouble basicAt: 1); writeI32: (aDouble basicAt: 2)! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:56'! writeField: aField self writeByte: aField type; writeI16: aField id! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/25/2007 00:01'! writeFieldBegin: aField self writeByte: aField type. self writeI16: aField id! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 18:04'! writeFieldStop self writeByte: TType stop! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 02:06'! writeI16: i16 self writeInt: i16 size: 2! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 02:06'! writeI32: i32 self writeInt: i32 size: 4! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 02:06'! writeI64: i64 self writeInt: i64 size: 8! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 04:23'! writeInt: val size: size 1 to: size do: [:n | self writeByte: ((val bitShift: (size negated + n) * 8) bitAnd: 16rFF)]! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 00:48'! writeListBegin: aList self writeByte: aList elemType; writeI32: aList size! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:55'! writeMapBegin: aMap self writeByte: aMap keyType; writeByte: aMap valueType; writeI32: aMap size! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 20:36'! writeMessageBegin: msg self writeI32: (self version1 bitOr: msg type); writeString: msg name; writeI32: msg seqid! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 11/1/2007 00:56'! writeSetBegin: aSet self writeByte: aSet elemType; writeI32: aSet size! ! !TBinaryProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 18:35'! writeString: aString self writeI32: aString size; write: aString! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readBool! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readByte! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readDouble! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readFieldBegin! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readFieldEnd! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readI16! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readI32! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readI64! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readListBegin! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readListEnd! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readMapBegin! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readMapEnd! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:39'! readMessageBegin! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:39'! readMessageEnd! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readSetBegin! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readSetEnd! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/25/2007 16:10'! readSimpleType: aType aType = TType bool ifTrue: [^ self readBool]. aType = TType byte ifTrue: [^ self readByte]. aType = TType double ifTrue: [^ self readDouble]. aType = TType i16 ifTrue: [^ self readI16]. aType = TType i32 ifTrue: [^ self readI32]. aType = TType i64 ifTrue: [^ self readI64]. aType = TType list ifTrue: [^ self readBool].! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readString! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readStructBegin ! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/24/2007 19:40'! readStructEnd! ! !TProtocol methodsFor: 'reading' stamp: 'pc 10/26/2007 21:34'! skip: aType aType = TType stop ifTrue: [^ self]. aType = TType bool ifTrue: [^ self readBool]. aType = TType byte ifTrue: [^ self readByte]. aType = TType i16 ifTrue: [^ self readI16]. aType = TType i32 ifTrue: [^ self readI32]. aType = TType i64 ifTrue: [^ self readI64]. aType = TType string ifTrue: [^ self readString]. aType = TType double ifTrue: [^ self readDouble]. aType = TType struct ifTrue: [| field | self readStructBegin. [(field := self readFieldBegin) type = TType stop] whileFalse: [self skip: field type. self readFieldEnd]. ^ self readStructEnd]. aType = TType map ifTrue: [| map | map := self readMapBegin. map size timesRepeat: [self skip: map keyType. self skip: map valueType]. ^ self readMapEnd]. aType = TType list ifTrue: [| list | list := self readListBegin. list size timesRepeat: [self skip: list elemType]. ^ self readListEnd]. aType = TType set ifTrue: [| set | set := self readSetBegin. set size timesRepeat: [self skip: set elemType]. ^ self readSetEnd]. self error: 'Unknown type'! ! !TProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 23:02'! transport ^ transport! ! !TProtocol methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:28'! transport: aTransport transport := aTransport! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeBool: aBool! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeByte: aByte! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! writeDouble: aFloat! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! writeFieldBegin: aField! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeFieldEnd! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeFieldStop! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeI16: i16! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeI32: i32! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeI64: i64! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:39'! writeListBegin: aList! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeListEnd! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:39'! writeMapBegin: aMap! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeMapEnd! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:36'! writeMessageBegin! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:36'! writeMessageEnd! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:39'! writeSetBegin: aSet! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeSetEnd! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! writeString: aString! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:38'! writeStructBegin: aStruct! ! !TProtocol methodsFor: 'writing' stamp: 'pc 10/24/2007 19:37'! writeStructEnd! ! Object subclass: #TResult instanceVariableNames: 'success oprot iprot exception' classVariableNames: '' poolDictionaries: '' category: 'Thrift'! !TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 21:35'! exception ^ exception! ! !TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 21:35'! exception: anError exception := anError! ! !TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 14:43'! success ^ success! ! !TResult methodsFor: 'as yet unclassified' stamp: 'pc 10/26/2007 14:43'! success: anObject success := anObject! ! Object subclass: #TSizedObject instanceVariableNames: 'size' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! TSizedObject subclass: #TList instanceVariableNames: 'elemType' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! !TList methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! elemType ^ elemType ifNil: [TType stop]! ! !TList methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:42'! elemType: anInteger elemType := anInteger! ! TList subclass: #TSet instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! TSizedObject subclass: #TMap instanceVariableNames: 'keyType valueType' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! !TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! keyType ^ keyType ifNil: [TType stop]! ! !TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:45'! keyType: anInteger keyType := anInteger! ! !TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 20:04'! valueType ^ valueType ifNil: [TType stop]! ! !TMap methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:45'! valueType: anInteger valueType := anInteger! ! !TSizedObject methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:03'! size ^ size ifNil: [0]! ! !TSizedObject methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:06'! size: anInteger size := anInteger! ! Object subclass: #TSocket instanceVariableNames: 'host port stream' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Transport'! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:34'! close self isOpen ifTrue: [stream close]! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:23'! connect ^ (self socketStream openConnectionToHost: (NetNameResolver addressForName: host) port: port) timeout: 180; binary; yourself! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:35'! flush stream flush! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:08'! host: aString host := aString! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 20:34'! isOpen ^ stream isNil not and: [stream socket isConnected] and: [stream socket isOtherEndClosed not]! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:22'! open stream := self connect! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:09'! port: anInteger port := anInteger! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:17'! read: size | data | [data := stream next: size. data isEmpty ifTrue: [TTransportError signal: 'Could not read ', size asString, ' bytes']. ^ data] on: ConnectionClosed do: [TTransportClosedError signal]! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:18'! socketStream ^ Smalltalk at: #FastSocketStream ifAbsent: [SocketStream] ! ! !TSocket methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 22:17'! write: aCollection [stream nextPutAll: aCollection] on: ConnectionClosed do: [TTransportClosedError signal]! ! Object subclass: #TStruct instanceVariableNames: 'name' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Protocol'! !TStruct methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:47'! name ^ name! ! !TStruct methodsFor: 'accessing' stamp: 'pc 10/24/2007 19:47'! name: aString name := aString! ! Object subclass: #TTransport instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift-Transport'! !TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! close self subclassResponsibility! ! !TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:22'! flush self subclassResponsibility! ! !TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! isOpen self subclassResponsibility! ! !TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! open self subclassResponsibility! ! !TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:18'! read: anInteger self subclassResponsibility! ! !TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:22'! readAll: anInteger ^ String streamContents: [:str | [str size < anInteger] whileTrue: [str nextPutAll: (self read: anInteger - str size)]]! ! !TTransport methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:22'! write: aString self subclassResponsibility! ! Object subclass: #TType instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Thrift'! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! bool ^ 2! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! byte ^ 3! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/25/2007 15:55'! codeOf: aTypeName self typeMap do: [:each | each first = aTypeName ifTrue: [^ each second]]. ^ nil! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! double ^ 4! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! i16 ^ 6! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! i32 ^ 8! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! i64 ^ 10! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! list ^ 15! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! map ^ 13! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/25/2007 15:56'! nameOf: aTypeCode self typeMap do: [:each | each second = aTypeCode ifTrue: [^ each first]]. ^ nil! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! set ^ 14! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! stop ^ 0! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! string ^ 11! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:04'! struct ^ 12! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/25/2007 15:51'! typeMap ^ #((bool 2) (byte 3) (double 4) (i16 6) (i32 8) (i64 10) (list 15) (map 13) (set 15) (stop 0) (string 11) (struct 12) (void 1))! ! !TType class methodsFor: 'as yet unclassified' stamp: 'pc 10/24/2007 17:03'! void ^ 1! ! thrift-0.16.0/lib/swift/000077500000000000000000000000001420101504100147645ustar00rootroot00000000000000thrift-0.16.0/lib/swift/Makefile.am000066400000000000000000000021031420101504100170140ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . all-local: swift build --configuration release install-exec-hook: swift install clean-local: swift package clean rm -rf .build precross: swift check-local: swift test EXTRA_DIST = \ Package.swift \ Sources \ Tests \ README.md MAINTAINERCLEANFILES = \ Makefile \ Makefile.in thrift-0.16.0/lib/swift/Package.swift000066400000000000000000000021111420101504100173700ustar00rootroot00000000000000// swift-tools-version:5.1 /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import PackageDescription let package = Package( name: "Thrift", products: [ .library(name: "Thrift", targets: ["Thrift"]) ], targets: [ .target(name: "Thrift", path: "Sources"), .testTarget(name: "ThriftTests", dependencies: ["Thrift"]) ] ) thrift-0.16.0/lib/swift/README.md000066400000000000000000000204111420101504100162410ustar00rootroot00000000000000Thrift Swift Library ========================= License ------- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## Build swift build ## Test swift test ## Install Library ##### Cocoapods Add the following to your podfile ```ruby pod 'Thrift-swift3', :git => 'git@github.com:apache/thrift.git', :branch => 'master' ``` ##### SPM Unfortunately due to some limitations in SPM, the Package manifest and Sources directory must be at the root of the project. To get around that for the time being, you can use this mirrored repo. Add the following to your Package.swift ```swift dependencies: [ .Package(url: "https://github.com/apocolipse/Thrift-Swift.git", majorVersion: 1) ] ``` ## Thrift Compiler You can compile IDL sources for Swift 3 with the following command: thrift --gen swift thrift_file ## Client Example ```swift let transport = TSocketTransport(hostname: "localhost", port: 9090)! // var proto = TCompactProtocol(transport: transport) let proto = TBinaryProtocol(on: transport) // var client = HermesClient(inoutProtocol: proto) let client = ThriftTestClient(inoutProtocol: proto) do { try client.testVoid() } catch let error { print("\(error)") } ``` ## Library Notes - Eliminated Protocol Factories, They were only used in async clients and server implementations, where Generics provide a better alternative. - Swifty Errors, All `TError` types have a nested `ErrorCode` Enum as well as some extra flavor where needed. - Value typed everything. `TTransport` operates on value typed `Data` rather than reference typed `NSData` or `UnsafeBufferPointer`s - Swift 3 Named protocols. Swift 3 naming conventions suggest the elimination of redundant words that can be inferred from variable/function signatures. This renaming is applied throughout the Swift 3 library converting most naming conventions used in the Swift2/Cocoa library to Swift 3-esque naming conventions. eg. ```swift func readString() throws -> String func writeString(_ val: String) throws ``` have been renamed to eliminate redundant words: ```swift func read() throws -> String func write(_ val: String) throws ``` - Eliminated `THTTPTransport` that uses `NSURLConnection` due to it being deprecated and not available at all in Swift 3 for Linux. `THTTPSessionTransport` from the Swift2/Cocoa library that uses `NSURLSession` has been renamed to `THTTPTransport` for this library and leverages `URLSession`, providing both synchronous (with semaphores) and asynchronous behavior. - Probably some More things I've missed here. ## Generator Notes #### Generator Flags | Flag | Description | | ------------- |:-------------:| | async_clients | Generate clients which invoke asynchronously via block syntax. Asynchronous classes are appended with `_Async` | | no_strict* | Generates non-strict structs | | debug_descriptions | Allow use of debugDescription so the app can add description via a cateogory/extension | | log_unexpected | Log every time an unexpected field ID or type is encountered. | | safe_enums | Generate enum types with an unknown case to handle unspecified values rather than throw a serialization error | *Most thrift libraries allow empty initialization of Structs, initializing `required` fields with nil/null/None (Python and Node generators). Swift on the other hand requires initializers to initialize all non-Optional fields, and thus the Swift 3 generator does not provide default values (unlike the Swift 2/Cocoa generator). In other languages, this allows the sending of NULL values in fields that are marked `required`, and thus will throw an error in Swift clients attempting to validate fields. The `no_strict` option here will ignore the validation check, as well as behave similar to the Swift2/Cocoa generator and initialize required fields with empty initializers (where possible). ## Whats implemented #### Library ##### Transports - [x] TSocketTransport - CFSocket and PosixSocket variants available. CFSocket variant only currently available for Darwin platforms - [x] THTTPTransport - Currently only available for Darwin platforms, Swift Foundation URLSession implementation needs completion on linux. - [x] TSocketServer - Uses CFSockets only for binding, should be working on linux - [x] TFramedTransport - [x] TMemoryBufferTransport - [x] TFileTransport - A few variants using File handles and file descriptors. - [x] TStreamTransport - Fully functional in Darwin, Foundation backing not yet completed in Linux (This limits TCFSocketTransport to Darwin) - [ ] HTTPServer - Currently there is no lightweight HTTPServer implementation the Swift Standard Library, so other 3rd party alternatives are required and out of scope for the Thrift library. Examples using Perfect will be provided. - [ ] Other (gz, etc) ##### Protocols - [x] TBinaryProtocol - [x] TCompactProtocol - [ ] TJSONProtocol - This will need to be implemented ##### Generator - [x] Code Complete Generator - [x] Async clients - [x] Documentation Generation - Generator will transplant IDL docs to Swift code for easy lookup in Xcode - [ ] Default Values - TODO - [ ] no_strict mode - TODO - [ ] Namespacing - Still haven't nailed down a good paradigm for namespacing. It will likely involve creating subdirectories for different namespaces and expecting the developer to import each subdirectory as separate modules. It could extend to creating SPM Package manifests with sub-modules within the generated module ## Example HTTP Server with Perfect ```swift import PerfectLib import PerfectHTTP import PerfectHTTPServer import Dispatch let logQueue = DispatchQueue(label: "log", qos: .background, attributes: .concurrent) let pQueue = DispatchQueue(label: "log", qos: .userInitiated, attributes: .concurrent) class TPerfectServer { private var server = HTTPServer() private var processor: TProcessor init(address: String? = nil, path: String? = nil, port: Int, processor: TProcessor, inProtocol: InProtocol.Type, outProtocol: OutProtocol.Type) throws { self.processor = processor if let address = address { server.serverAddress = address } server.serverPort = UInt16(port) var routes = Routes() var uri = "/" if let path = path { uri += path } routes.add(method: .post, uri: uri) { request, response in pQueue.async { response.setHeader(.contentType, value: "application/x-thrift") let itrans = TMemoryBufferTransport() if let bytes = request.postBodyBytes { let data = Data(bytes: bytes) itrans.reset(readBuffer: data) } let otrans = TMemoryBufferTransport(flushHandler: { trans, buff in let array = buff.withUnsafeBytes { Array(UnsafeBufferPointer(start: $0, count: buff.count)) } response.status = .ok response.setBody(bytes: array) response.completed() }) let inproto = InProtocol(on: itrans) let outproto = OutProtocol(on: otrans) do { try processor.process(on: inproto, outProtocol: outproto) try otrans.flush() } catch { response.status = .badRequest response.completed() } } } server.addRoutes(routes) } func serve() throws { try server.start() } } ``` #### Example Usage ```swift class ServiceHandler : Service { ... } let server = try? TPerfectServer(port: 9090, processor: ServiceProcessor(service: ServiceHandler()), inProtocol: TBinaryProtocol.self, outProtocol: TBinaryProtocol.self) try? server?.serve() ``` thrift-0.16.0/lib/swift/Sources/000077500000000000000000000000001420101504100164075ustar00rootroot00000000000000thrift-0.16.0/lib/swift/Sources/LinuxHelper.swift000066400000000000000000000031701420101504100217250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation import CoreFoundation #if os(Linux) /// Extensions for Linux for incomplete Foundation API's. /// swift-corelibs-foundation is not yet 1:1 with OSX/iOS Foundation extension CFSocketError { public static let success = kCFSocketSuccess } extension UInt { public static func &(lhs: UInt, rhs: Int) -> UInt { let cast = unsafeBitCast(rhs, to: UInt.self) return lhs & cast } } #else extension CFStreamPropertyKey { static let shouldCloseNativeSocket = CFStreamPropertyKey(kCFStreamPropertyShouldCloseNativeSocket) // Exists as Stream.PropertyKey.socketSecuritylevelKey but doesn't work with CFReadStreamSetProperty static let socketSecurityLevel = CFStreamPropertyKey(kCFStreamPropertySocketSecurityLevel) static let SSLSettings = CFStreamPropertyKey(kCFStreamPropertySSLSettings) } #endif thrift-0.16.0/lib/swift/Sources/TApplicationError.swift000066400000000000000000000133171420101504100230730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ public struct TApplicationError : TError { public enum Code : TErrorCode { case unknown case unknownMethod(methodName: String?) case invalidMessageType case wrongMethodName(methodName: String?) case badSequenceId case missingResult(methodName: String?) case internalError case protocolError case invalidTransform case invalidProtocol case unsupportedClientType /// Initialize a TApplicationError with a Thrift error code /// Normally this would be achieved with RawRepresentable however /// by doing this we can allow for associated properties on enum cases for /// case specific context data in a Swifty, type-safe manner. /// /// - parameter thriftErrorCode: Integer TApplicationError(exception) error code. /// Default to 0 (.unknown) public init(thriftErrorCode: Int) { switch thriftErrorCode { case 1: self = .unknownMethod(methodName: nil) case 2: self = .invalidMessageType case 3: self = .wrongMethodName(methodName: nil) case 4: self = .badSequenceId case 5: self = .missingResult(methodName: nil) case 6: self = .internalError case 7: self = .protocolError case 8: self = .invalidProtocol case 9: self = .invalidTransform case 10: self = .unsupportedClientType default: self = .unknown } } public var thriftErrorCode: Int { switch self { case .unknown: return 0 case .unknownMethod: return 1 case .invalidMessageType: return 2 case .wrongMethodName: return 3 case .badSequenceId: return 4 case .missingResult: return 5 case .internalError: return 6 case .protocolError: return 7 case .invalidProtocol: return 8 case .invalidTransform: return 9 case .unsupportedClientType: return 10 } } public var description: String { /// Output "for #methodName" if method is not nil else empty let methodUnwrap: (String?) -> String = { method in return "\(method == nil ? "" : " for \(method ?? "")")" } switch self { case .unknown: return "Unknown TApplicationError" case .unknownMethod(let method): return "Unknown Method\(methodUnwrap(method))" case .invalidMessageType: return "Invalid Message Type" case .wrongMethodName(let method): return "Wrong Method Name\(methodUnwrap(method))" case .badSequenceId: return "Bad Sequence ID" case .missingResult(let method): return "Missing Result\(methodUnwrap(method))" case .internalError: return "Internal Error" case .protocolError: return "Protocol Error" case .invalidProtocol: return "Invalid Protocol" case .invalidTransform: return "Invalid Transform" case .unsupportedClientType: return "Unsupported Client Type" } } } public init() { } public init(thriftErrorCode code: Int, message: String? = nil) { self.error = Code(thriftErrorCode: code) self.message = message } public var error: Code = .unknown public var message: String? = nil public static var defaultCase: Code { return .unknown } } extension TApplicationError : TSerializable { public static var thriftType: TType { return .struct } public static func read(from proto: TProtocol) throws -> TApplicationError { var errorCode: Int = 0 var message: String? = nil _ = try proto.readStructBegin() fields: while true { let (_, fieldType, fieldID) = try proto.readFieldBegin() switch (fieldID, fieldType) { case (_, .stop): break fields case (1, .string): message = try proto.read() case (2, .i32): errorCode = Int(try proto.read() as Int32) case let (_, unknownType): try proto.skip(type: unknownType) } try proto.readFieldEnd() } try proto.readStructEnd() return TApplicationError(thriftErrorCode: errorCode, message: message) } public func write(to proto: TProtocol) throws { try proto.writeStructBegin(name: "TApplicationException") try proto.writeFieldBegin(name: "message", type: .string, fieldID: 1) try proto.write(message ?? "") try proto.writeFieldEnd() try proto.writeFieldBegin(name: "type", type: .i32, fieldID: 2) let val = Int32(error.thriftErrorCode) try proto.write(val) try proto.writeFieldEnd() try proto.writeFieldStop() try proto.writeStructEnd() } } extension TApplicationError: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(error.thriftErrorCode) hasher.combine(message) } } public func ==(lhs: TApplicationError, rhs: TApplicationError) -> Bool { return lhs.error.thriftErrorCode == rhs.error.thriftErrorCode && lhs.message == rhs.message } thrift-0.16.0/lib/swift/Sources/TBinary.swift000066400000000000000000000021241420101504100210340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation extension Data : TSerializable { public static var thriftType: TType { return .string } public static func read(from proto: TProtocol) throws -> Data { return try proto.read() as Data } public func write(to proto: TProtocol) throws { try proto.write(self) } } thrift-0.16.0/lib/swift/Sources/TBinaryProtocol.swift000066400000000000000000000260561420101504100225700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public struct TBinaryProtocolVersion { static let version1 = Int32(bitPattern: 0x80010000) static let versionMask = Int32(bitPattern: 0xffff0000) } public class TBinaryProtocol: TProtocol { public var messageSizeLimit: UInt32 = 0 public var transport: TTransport // class level properties for setting global config (useful for server in lieu of Factory design) public static var strictRead: Bool = false public static var strictWrite: Bool = true private var strictRead: Bool private var strictWrite: Bool var currentMessageName: String? var currentFieldName: String? public convenience init(transport: TTransport, strictRead: Bool, strictWrite: Bool) { self.init(on: transport) self.strictRead = strictRead self.strictWrite = strictWrite } public required init(on transport: TTransport) { self.transport = transport self.strictWrite = TBinaryProtocol.strictWrite self.strictRead = TBinaryProtocol.strictRead } func readStringBody(_ size: Int) throws -> String { var data = Data() try ProtocolTransportTry(error: TProtocolError(message: "Transport read failed")) { data = try self.transport.readAll(size: size) } return String(data: data, encoding: String.Encoding.utf8) ?? "" } /// Mark: - TProtocol public func readMessageBegin() throws -> (String, TMessageType, Int32) { let size: Int32 = try read() var messageName = "" var type = TMessageType.exception if size < 0 { let version = size & TBinaryProtocolVersion.versionMask if version != TBinaryProtocolVersion.version1 { throw TProtocolError(error: .badVersion(expected: "\(TBinaryProtocolVersion.version1)", got: "\(version)")) } type = TMessageType(rawValue: Int32(size) & 0x00FF) ?? type messageName = try read() } else { if strictRead { let errorMessage = "Missing message version, old client? Message Name: \(currentMessageName ?? "")" throw TProtocolError(error: .invalidData, message: errorMessage) } if messageSizeLimit > 0 && size > Int32(messageSizeLimit) { throw TProtocolError(error: .sizeLimit(limit: Int(messageSizeLimit), got: Int(size))) } messageName = try readStringBody(Int(size)) type = TMessageType(rawValue: Int32(try read() as UInt8)) ?? type } let seqID: Int32 = try read() return (messageName, type, seqID) } public func readMessageEnd() throws { return } public func readStructBegin() throws -> String { return "" } public func readStructEnd() throws { return } public func readFieldBegin() throws -> (String, TType, Int32) { let fieldType = TType(rawValue: Int32(try read() as UInt8)) ?? TType.stop var fieldID: Int32 = 0 if fieldType != .stop { fieldID = Int32(try read() as Int16) } return ("", fieldType, fieldID) } public func readFieldEnd() throws { return } public func readMapBegin() throws -> (TType, TType, Int32) { var raw = Int32(try read() as UInt8) guard let keyType = TType(rawValue: raw) else { throw TProtocolError(message: "Unknown value for keyType TType: \(raw)") } raw = Int32(try read() as UInt8) guard let valueType = TType(rawValue: raw) else { throw TProtocolError(message: "Unknown value for valueType TType: \(raw)") } let size: Int32 = try read() return (keyType, valueType, size) } public func readMapEnd() throws { return } public func readSetBegin() throws -> (TType, Int32) { let raw = Int32(try read() as UInt8) guard let elementType = TType(rawValue: raw) else { throw TProtocolError(message: "Unknown value for elementType TType: \(raw)") } let size: Int32 = try read() return (elementType, size) } public func readSetEnd() throws { return } public func readListBegin() throws -> (TType, Int32) { let raw = Int32(try read() as UInt8) guard let elementType = TType(rawValue: raw) else { throw TProtocolError(message: "Unknown value for elementType TType: \(raw)") } let size: Int32 = try read() return (elementType, size) } public func readListEnd() throws { return } public func read() throws -> String { let data: Data = try read() guard let str = String.init(data: data, encoding: .utf8) else { throw TProtocolError(error: .invalidData, message: "Couldn't encode UTF-8 from data read") } return str } public func read() throws -> Bool { return (try read() as UInt8) == 1 } public func read() throws -> UInt8 { var buff = Data() try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { buff = try self.transport.readAll(size: 1) } return buff[0] } public func read() throws -> Int16 { var buff = Data() try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { buff = try self.transport.readAll(size: 2) } var ret = Int16(buff[0] & 0xff) << 8 ret |= Int16(buff[1] & 0xff) return ret } public func read() throws -> Int32 { var buff = Data() try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { buff = try self.transport.readAll(size: 4) } var ret = Int32(buff[0] & 0xff) << 24 ret |= Int32(buff[1] & 0xff) << 16 ret |= Int32(buff[2] & 0xff) << 8 ret |= Int32(buff[3] & 0xff) return ret } public func read() throws -> Int64 { var buff = Data() try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { buff = try self.transport.readAll(size: 8) } var ret = Int64(buff[0] & 0xff) << 56 ret |= Int64(buff[1] & 0xff) << 48 ret |= Int64(buff[2] & 0xff) << 40 ret |= Int64(buff[3] & 0xff) << 32 ret |= Int64(buff[4] & 0xff) << 24 ret |= Int64(buff[5] & 0xff) << 16 ret |= Int64(buff[6] & 0xff) << 8 ret |= Int64(buff[7] & 0xff) return ret } public func read() throws -> Double { let val = try read() as Int64 return Double(bitPattern: UInt64(bitPattern: val)) } public func read() throws -> Data { let size = Int(try read() as Int32) var data = Data() try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { data = try self.transport.readAll(size: size) } return data } // Write methods public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { if strictWrite { let version = TBinaryProtocolVersion.version1 | Int32(messageType.rawValue) try write(version) try write(name) try write(sequenceID) } else { try write(name) try write(UInt8(messageType.rawValue)) try write(sequenceID) } currentMessageName = name } public func writeMessageEnd() throws { currentMessageName = nil } public func writeStructBegin(name: String) throws { return } public func writeStructEnd() throws { return } public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { try write(UInt8(fieldType.rawValue)) try write(Int16(fieldID)) } public func writeFieldStop() throws { try write(UInt8(TType.stop.rawValue)) } public func writeFieldEnd() throws { return } public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { try write(UInt8(keyType.rawValue)) try write(UInt8(valueType.rawValue)) try write(size) } public func writeMapEnd() throws { return } public func writeSetBegin(elementType: TType, size: Int32) throws { try write(UInt8(elementType.rawValue)) try write(size) } public func writeSetEnd() throws { return } public func writeListBegin(elementType: TType, size: Int32) throws { try write(UInt8(elementType.rawValue)) try write(size) } public func writeListEnd() throws { return } public func write(_ value: String) throws { try write(value.data(using: .utf8)!) } public func write(_ value: Bool) throws { let byteVal: UInt8 = value ? 1 : 0 try write(byteVal) } public func write(_ value: UInt8) throws { let buff = Data([value]) try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { try self.transport.write(data: buff) } } public func write(_ value: Int16) throws { var buff = Data() buff.append(Data([UInt8(0xff & (value >> 8))])) buff.append(Data([UInt8(0xff & (value))])) try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { try self.transport.write(data: buff) } } public func write(_ value: Int32) throws { var buff = Data() buff.append(Data([UInt8(0xff & (value >> 24))])) buff.append(Data([UInt8(0xff & (value >> 16))])) buff.append(Data([UInt8(0xff & (value >> 8))])) buff.append(Data([UInt8(0xff & (value))])) try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { try self.transport.write(data: buff) } } public func write(_ value: Int64) throws { var buff = Data() buff.append(Data([UInt8(0xff & (value >> 56))])) buff.append(Data([UInt8(0xff & (value >> 48))])) buff.append(Data([UInt8(0xff & (value >> 40))])) buff.append(Data([UInt8(0xff & (value >> 32))])) buff.append(Data([UInt8(0xff & (value >> 24))])) buff.append(Data([UInt8(0xff & (value >> 16))])) buff.append(Data([UInt8(0xff & (value >> 8))])) buff.append(Data([UInt8(0xff & (value))])) try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { try self.transport.write(data: buff) } } public func write(_ value: Double) throws { // Notably unsafe, since Double and Int64 are the same size, this should work fine try self.write(Int64(bitPattern: value.bitPattern)) } public func write(_ data: Data) throws { try write(Int32(data.count)) try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { try self.transport.write(data: data) } } } thrift-0.16.0/lib/swift/Sources/TClient.swift000066400000000000000000000025471420101504100210370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ open class TClient { public let inProtocol: TProtocol public let outProtocol: TProtocol required public init(inoutProtocol: TProtocol) { self.inProtocol = inoutProtocol self.outProtocol = inoutProtocol } required public init(inProtocol: TProtocol, outProtocol: TProtocol) { self.inProtocol = inProtocol self.outProtocol = outProtocol } } open class TAsyncClient { public var factory: Factory public init(with protocol: Protocol.Type, factory: Factory) { self.factory = factory } } thrift-0.16.0/lib/swift/Sources/TCompactProtocol.swift000066400000000000000000000402161420101504100227240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation import CoreFoundation public enum TCType: UInt8 { case stop = 0x00 case boolean_TRUE = 0x01 case boolean_FALSE = 0x02 case i8 = 0x03 case i16 = 0x04 case i32 = 0x05 case i64 = 0x06 case double = 0x07 case binary = 0x08 case list = 0x09 case set = 0x0A case map = 0x0B case `struct` = 0x0C public static let typeMask: UInt8 = 0xE0 // 1110 0000 public static let typeBits: UInt8 = 0x07 // 0000 0111 public static let typeShiftAmount = 5 } public class TCompactProtocol: TProtocol { public static let protocolID: UInt8 = 0x82 public static let version: UInt8 = 1 public static let versionMask: UInt8 = 0x1F // 0001 1111 public var transport: TTransport var lastField: [UInt8] = [] var lastFieldId: UInt8 = 0 var boolFieldName: String? var boolFieldType: TType? var boolFieldId: Int32? var booleanValue: Bool? var currentMessageName: String? public required init(on transport: TTransport) { self.transport = transport } /// Mark: - TCompactProtocol helpers func writebyteDirect(_ byte: UInt8) throws { let byte = Data([byte]) try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { try self.transport.write(data: byte) } } func writeVarint32(_ val: UInt32) throws { var val = val var i32buf = [UInt8](repeating: 0, count: 5) var idx = 0 while true { if (val & ~0x7F) == 0 { i32buf[idx] = UInt8(val) idx += 1 break } else { i32buf[idx] = UInt8((val & 0x7F) | 0x80) idx += 1 val >>= 7 } } try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { try self.transport.write(data: Data(i32buf[0..>= 7 } } try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { try self.transport.write(data: Data(varint64out[0.. Data { var result = Data() if size != 0 { try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { result = try self.transport.readAll(size: size) } } return result } func readVarint32() throws -> UInt32 { var result: UInt32 = 0 var shift: UInt32 = 0 while true { let byte: UInt8 = try read() result |= UInt32(byte & 0x7F) << shift if (byte & 0x80) == 0 { break } shift += 7 } return result } func readVarint64() throws -> UInt64 { var result: UInt64 = 0 var shift: UInt64 = 0 while true { let byte: UInt8 = try read() result |= UInt64(byte & 0x7F) << shift if (byte & 0x80) == 0 { break } shift += 7 } return result } func ttype(_ compactTypeVal: UInt8) throws -> TType { guard let compactType = TCType(rawValue: compactTypeVal) else { throw TProtocolError(message: "Unknown TCType value: \(compactTypeVal)") } switch compactType { case .stop: return .stop; case .boolean_FALSE, .boolean_TRUE: return .bool; case .i8: return .i8; case .i16: return .i16; case .i32: return .i32; case .i64: return .i64; case .double: return .double; case .binary: return .string; case .list: return .list; case .set: return .set; case .map: return .map; case .struct: return .struct; } } func compactType(_ ttype: TType) -> TCType { switch ttype { case .stop: return .stop case .void: return .i8 case .bool: return .boolean_FALSE case .i8: return .i8 case .double: return .double case .i16: return .i16 case .i32: return .i32 case .i64: return .i64 case .string: return .binary case .struct: return .struct case .map: return .map case .set: return .set case .list: return .list case .utf8: return .binary case .utf16: return .binary } } /// ZigZag encoding maps signed integers to unsigned integers so that /// numbers with a small absolute value (for instance, -1) have /// a small varint encoded value too. It does this in a way that /// "zig-zags" back and forth through the positive and negative integers, /// so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so /// /// - parameter n: number to zigzag /// /// - returns: zigzaged UInt32 func i32ToZigZag(_ n : Int32) -> UInt32 { return UInt32(bitPattern: Int32(n << 1) ^ Int32(n >> 31)) } func i64ToZigZag(_ n : Int64) -> UInt64 { return UInt64(bitPattern: Int64(n << 1) ^ Int64(n >> 63)) } func zigZagToi32(_ n: UInt32) -> Int32 { return Int32(n >> 1) ^ (-Int32(n & 1)) } func zigZagToi64(_ n: UInt64) -> Int64 { return Int64(n >> 1) ^ (-Int64(n & 1)) } /// Mark: - TProtocol public func readMessageBegin() throws -> (String, TMessageType, Int32) { let protocolId: UInt8 = try read() if protocolId != TCompactProtocol.protocolID { let expected = String(format:"%2X", TCompactProtocol.protocolID) let got = String(format:"%2X", protocolId) throw TProtocolError(message: "Wrong Protocol ID \(got)", extendedError: .mismatchedProtocol(expected: expected, got: got)) } let versionAndType: UInt8 = try read() let version: UInt8 = versionAndType & TCompactProtocol.versionMask if version != TCompactProtocol.version { throw TProtocolError(error: .badVersion(expected: "\(TCompactProtocol.version)", got:"\(version)")) } let type = (versionAndType >> UInt8(TCType.typeShiftAmount)) & TCType.typeBits guard let mtype = TMessageType(rawValue: Int32(type)) else { throw TProtocolError(message: "Unknown TMessageType value: \(type)") } let sequenceId = try readVarint32() let name: String = try read() return (name, mtype, Int32(sequenceId)) } public func readMessageEnd() throws { } public func readStructBegin() throws -> String { lastField.append(lastFieldId) lastFieldId = 0 return "" } public func readStructEnd() throws { lastFieldId = lastField.last ?? 0 lastField.removeLast() } public func readFieldBegin() throws -> (String, TType, Int32) { let byte: UInt8 = try read() guard let type = TCType(rawValue: byte & 0x0F) else { throw TProtocolError(message: "Unknown TCType \(byte & 0x0F)") } // if it's a stop, then we can return immediately, as the struct is over if type == .stop { return ("", .stop, 0) } var fieldId: Int16 = 0 // mask off the 4MSB of the type header. it could contain a field id delta let modifier = (byte & 0xF0) >> 4 if modifier == 0 { // not a delta. look ahead for the zigzag varint field id fieldId = try read() } else { // has a delta. add the delta to the last Read field id. fieldId = Int16(lastFieldId + modifier) } let fieldType = try ttype(type.rawValue) // if this happens to be a boolean field, the value is encoded in the type if type == .boolean_TRUE || type == .boolean_FALSE { // save the boolean value in a special instance variable booleanValue = type == .boolean_TRUE } // push the new field onto the field stack so we can keep the deltas going lastFieldId = UInt8(fieldId) return ("", fieldType, Int32(fieldId)) } public func readFieldEnd() throws { } public func read() throws -> String { let length = try readVarint32() var result: String if length != 0 { let data = try readBinary(Int(length)) result = String(data: data, encoding: String.Encoding.utf8) ?? "" } else { result = "" } return result } public func read() throws -> Bool { if let val = booleanValue { self.booleanValue = nil return val } else { let result = try read() as UInt8 return TCType(rawValue: result) == .boolean_TRUE } } public func read() throws -> UInt8 { var buff: UInt8 = 0 try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { buff = try self.transport.readAll(size: 1)[0] } return buff } public func read() throws -> Int16 { let v = try readVarint32() return Int16(zigZagToi32(v)) } public func read() throws -> Int32 { let v = try readVarint32() return zigZagToi32(v) } public func read() throws -> Int64 { let v = try readVarint64() return zigZagToi64(v) } public func read() throws -> Double { var buff = Data() try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { buff = try self.transport.readAll(size: 8) } let i64: UInt64 = buff.withUnsafeBytes { $0.load(as: UInt64.self) } let bits = CFSwapInt64LittleToHost(i64) return Double(bitPattern: bits) } public func read() throws -> Data { let length = try readVarint32() return try readBinary(Int(length)) } public func readMapBegin() throws -> (TType, TType, Int32) { var keyAndValueType: UInt8 = 8 let size = try readVarint32() if size != 0 { keyAndValueType = try read() } let keyType = try ttype(keyAndValueType >> 4) let valueType = try ttype(keyAndValueType & 0xF) return (keyType, valueType, Int32(size)) } public func readMapEnd() throws { } public func readSetBegin() throws -> (TType, Int32) { return try readListBegin() } public func readSetEnd() throws { } public func readListBegin() throws -> (TType, Int32) { let sizeAndType: UInt8 = try read() var size: UInt32 = UInt32(sizeAndType >> 4) & 0x0f if size == 15 { size = try readVarint32() } let elementType = try ttype(sizeAndType & 0x0F) return (elementType, Int32(size)) } public func readListEnd() throws { } public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { try writebyteDirect(TCompactProtocol.protocolID) let nextByte: UInt8 = (TCompactProtocol.version & TCompactProtocol.versionMask) | (UInt8((UInt32(messageType.rawValue) << UInt32(TCType.typeShiftAmount))) & TCType.typeMask) try writebyteDirect(nextByte) try writeVarint32(UInt32(sequenceID)) try write(name) currentMessageName = name } public func writeMessageEnd() throws { currentMessageName = nil } public func writeStructBegin(name: String) throws { lastField.append(lastFieldId) lastFieldId = 0 } public func writeStructEnd() throws { lastFieldId = lastField.last ?? 0 lastField.removeLast() } public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { if fieldType == .bool { boolFieldName = name boolFieldType = fieldType boolFieldId = fieldID return } else { try writeFieldBeginInternal(name: name, type: fieldType, fieldID: fieldID, typeOverride: 0xFF) } } func writeFieldBeginInternal(name: String, type fieldType: TType, fieldID: Int32, typeOverride: UInt8) throws { let typeToWrite = typeOverride == 0xFF ? compactType(fieldType).rawValue : typeOverride // check if we can use delta encoding for the field id let diff = UInt8(fieldID) - lastFieldId if (UInt8(fieldID) > lastFieldId) && (diff <= 15) { // Write them together try writebyteDirect((UInt8(fieldID) - lastFieldId) << 4 | typeToWrite) } else { // Write them separate try writebyteDirect(typeToWrite) try write(Int16(fieldID)) } lastFieldId = UInt8(fieldID) } public func writeFieldStop() throws { try writebyteDirect(TCType.stop.rawValue) } public func writeFieldEnd() throws { } public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { if size == 0 { try writebyteDirect(0) } else { try writeVarint32(UInt32(size)) let compactedTypes = compactType(keyType).rawValue << 4 | compactType(valueType).rawValue try writebyteDirect(compactedTypes) } } public func writeMapEnd() throws { } public func writeSetBegin(elementType: TType, size: Int32) throws { try writeCollectionBegin(elementType, size: size) } public func writeSetEnd() throws { } public func writeListBegin(elementType: TType, size: Int32) throws { try writeCollectionBegin(elementType, size: size) } public func writeListEnd() throws { } public func write(_ value: String) throws { try write(value.data(using: String.Encoding.utf8)!) } public func write(_ value: Bool) throws { if let boolFieldId = boolFieldId, let boolFieldType = boolFieldType, let boolFieldName = boolFieldName { // we haven't written the field header yet let compactType: TCType = value ? .boolean_TRUE : .boolean_FALSE try writeFieldBeginInternal(name: boolFieldName, type: boolFieldType, fieldID: boolFieldId, typeOverride: compactType.rawValue) self.boolFieldId = nil self.boolFieldType = nil self.boolFieldName = nil } else { // we're not part of a field, so just write the value. try writebyteDirect(value ? TCType.boolean_TRUE.rawValue : TCType.boolean_FALSE.rawValue) } } public func write(_ value: UInt8) throws { try writebyteDirect(value) } public func write(_ value: Int16) throws { try writeVarint32(i32ToZigZag(Int32(value))) } public func write(_ value: Int32) throws { try writeVarint32(i32ToZigZag(value)) } public func write(_ value: Int64) throws { try writeVarint64(i64ToZigZag(value)) } public func write(_ value: Double) throws { var bits = CFSwapInt64HostToLittle(value.bitPattern) let data = withUnsafePointer(to: &bits) { return Data(bytes: UnsafePointer(OpaquePointer($0)), count: MemoryLayout.size) } try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { try self.transport.write(data: data) } } public func write(_ data: Data) throws { try writeVarint32(UInt32(data.count)) try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) { try self.transport.write(data: data) } } } thrift-0.16.0/lib/swift/Sources/TEnum.swift000066400000000000000000000021521420101504100205150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ public protocol TEnum : TSerializable, Hashable { var rawValue: Int32 { get } } extension TEnum { public static var thriftType: TType { return .i32 } public func hash(into hasher: inout Hasher) { hasher.combine(rawValue) } public func write(to proto: TProtocol) throws { try proto.write(rawValue) } } thrift-0.16.0/lib/swift/Sources/TError.swift000066400000000000000000000046001420101504100207020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /// TErrorCode /// /// Protocol for TError conformers' enum's to conform to. /// Generic Int Thrift error code to allow error cases to have /// associated values. public protocol TErrorCode : CustomStringConvertible { var thriftErrorCode: Int { get } } /// TError /// /// Base protocol for all Thrift Error(Exception) types to conform to public protocol TError : Error, CustomStringConvertible { /// Enum for error cases. Can be typealiased to any conforming enum /// or defined nested. associatedtype Code: TErrorCode /// Error Case, value from internal enum var error: Code { get set } /// Optional additional message var message: String? { get set } /// Default error case for the error type, used for generic init() static var defaultCase: Code { get } init() } extension TError { /// Human readable description of error. Default provided for you in the /// format \(Self.self): \(error.errorDescription) \n message /// eg: /// /// TApplicationError (1): Invalid Message Type /// An unknown Error has occured. public var description: String { var out = "\(Self.self) (\(error.thriftErrorCode)): " + error.description + "\n" if let message = message { out += "Message: \(message)" } return out } /// Simple default Initializer for TError's /// /// - parameter error: ErrorCode value. Default: defaultCase /// - parameter message: Custom message with error. Optional /// /// - returns: <#return value description#> public init(error: Code, message: String? = nil) { self.init() self.error = error self.message = message } } thrift-0.16.0/lib/swift/Sources/TFileHandleTransport.swift000066400000000000000000000031401420101504100235170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public class TFileHandleTransport: TTransport { var inputFileHandle: FileHandle var outputFileHandle: FileHandle public init(inputFileHandle: FileHandle, outputFileHandle: FileHandle) { self.inputFileHandle = inputFileHandle self.outputFileHandle = outputFileHandle } public convenience init(fileHandle: FileHandle) { self.init(inputFileHandle: fileHandle, outputFileHandle: fileHandle) } public func read(size: Int) throws -> Data { var data = Data() while data.count < size { let read = inputFileHandle.readData(ofLength: size - data.count) data.append(read) if read.count == 0 { break } } return data } public func write(data: Data) throws { outputFileHandle.write(data) } public func flush() throws { return } } thrift-0.16.0/lib/swift/Sources/TFileTransport.swift000066400000000000000000000053161420101504100224120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) import Glibc #endif /// TFileTransport /// Foundation-less Swift File transport. /// Uses C fopen/fread/fwrite, /// provided by Glibc in linux and Darwin on OSX/iOS public class TFileTransport: TTransport { var fileHandle: UnsafeMutablePointer? = nil public init (fileHandle: UnsafeMutablePointer) { self.fileHandle = fileHandle } public convenience init(filename: String) throws { var fileHandle: UnsafeMutablePointer? filename.withCString({ cFilename in "rw".withCString({ cMode in fileHandle = fopen(cFilename, cMode) }) }) if let fileHandle = fileHandle { self.init(fileHandle: fileHandle) } else { throw TTransportError(error: .notOpen) } } deinit { fclose(self.fileHandle) } public func readAll(size: Int) throws -> Data { let read = try self.read(size: size) if read.count != size { throw TTransportError(error: .endOfFile) } return read } public func read(size: Int) throws -> Data { // set up read buffer, position 0 var read = Data(capacity: size) var position = 0 // read character buffer var nextChar: UInt8 = 0 // continue until we've read size bytes while read.count < size { if fread(&nextChar, 1, 1, self.fileHandle) == 1 { read[position] = nextChar // Increment output byte pointer position += 1 } else { throw TTransportError(error: .endOfFile) } } return read } public func write(data: Data) throws { let bytesWritten = data.withUnsafeBytes { fwrite($0.baseAddress!, 1, data.count, self.fileHandle) } if bytesWritten != data.count { throw TTransportError(error: .unknown) } } public func flush() throws { return } } thrift-0.16.0/lib/swift/Sources/TFramedTransport.swift000066400000000000000000000063271420101504100227340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public class TFramedTransport: TTransport { public static let headerSize = 4 public static let initFrameSize = 1024 private static let defaultMaxLength = 16384000 public var transport: TTransport private var writeBuffer = Data() private var maxSize = TFramedTransport.defaultMaxLength private var remainingBytes = 0 public init(transport: TTransport, maxSize: Int) { self.transport = transport self.maxSize = maxSize } public convenience init(transport: TTransport) { self.init(transport: transport, maxSize: TFramedTransport.defaultMaxLength) } func readHeader() throws { let read = try transport.readAll(size: TFramedTransport.headerSize) remainingBytes = Int(decodeFrameSize(data: read)) } /// Mark: - TTransport public func read(size: Int) throws -> Data { while (remainingBytes <= 0) { try readHeader() } let toRead = min(size, remainingBytes) if toRead < 0 { try close() throw TTransportError(error: .negativeSize, message: "Read a negative frame size (\(toRead))!") } if toRead > maxSize { try close() throw TTransportError(error: .sizeLimit(limit: maxSize, got: toRead)) } let data = try transport.readAll(size: toRead) remainingBytes -= data.count return data } public func flush() throws { // copy buffer and reset let buff = writeBuffer writeBuffer = Data() let frameSize = encodeFrameSize(size: UInt32(buff.count)) try transport.write(data: frameSize) try transport.write(data: buff) try transport.flush() } public func write(data: Data) throws { writeBuffer.append(data) } private func encodeFrameSize(size: UInt32) -> Data { var data = Data() data.append(Data([UInt8(0xff & (size >> 24))])) data.append(Data([UInt8(0xff & (size >> 16))])) data.append(Data([UInt8(0xff & (size >> 8))])) data.append(Data([UInt8(0xff & (size))])) return data } private func decodeFrameSize(data: Data) -> UInt32 { var size: UInt32 size = (UInt32(data[0] & 0xff) << 24) size |= (UInt32(data[1] & 0xff) << 16) size |= (UInt32(data[2] & 0xff) << 8) size |= (UInt32(data[3] & 0xff)) return size } public func close() throws { try transport.close() } public func open() throws { try transport.open() } public func isOpen() throws -> Bool { return try transport.isOpen() } } thrift-0.16.0/lib/swift/Sources/THTTPSessionTransport.swift000066400000000000000000000133501420101504100236530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation // Conditional import for URLRequest // It was moved from Foundation to FoundationNetworking in 5.1, but // not on Darwin. See https://stackoverflow.com/a/58606520 #if canImport(FoundationNetworking) import FoundationNetworking #endif import Dispatch public class THTTPSessionTransport: TAsyncTransport { public class Factory : TAsyncTransportFactory { public var responseValidate: ((HTTPURLResponse?, Data?) throws -> Void)? var session: URLSession var url: URL public class func setupDefaultsForSessionConfiguration(_ config: URLSessionConfiguration, withProtocolName protocolName: String?) { var thriftContentType = "application/x-thrift" if let protocolName = protocolName { thriftContentType += "; p=\(protocolName)" } config.requestCachePolicy = .reloadIgnoringLocalCacheData config.urlCache = nil config.httpShouldUsePipelining = true config.httpShouldSetCookies = true config.httpAdditionalHeaders = ["Content-Type": thriftContentType, "Accept": thriftContentType, "User-Agent": "Thrift/Swift (Session)"] } public init(session: URLSession, url: URL) { self.session = session self.url = url } public func newTransport() -> THTTPSessionTransport { return THTTPSessionTransport(factory: self) } func validateResponse(_ response: HTTPURLResponse?, data: Data?) throws { try responseValidate?(response, data) } func taskWithRequest(_ request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> ()) throws -> URLSessionTask { let newTask: URLSessionTask? = session.dataTask(with: request, completionHandler: completionHandler) if let newTask = newTask { return newTask } else { throw TTransportError(error: .unknown, message: "Failed to create session data task") } } } var factory: Factory var requestData = Data() var responseData = Data() var responseDataOffset: Int = 0 init(factory: Factory) { self.factory = factory } public func readAll(size: Int) throws -> Data { let read = try self.read(size: size) if read.count != size { throw TTransportError(error: .endOfFile) } return read } public func read(size: Int) throws -> Data { let avail = responseData.count - responseDataOffset let (start, stop) = (responseDataOffset, responseDataOffset + min(size, avail)) let read = responseData.subdata(in: start.. Void) { var error: Error? var task: URLSessionTask? var request = URLRequest(url: factory.url) request.httpMethod = "POST" request.httpBody = requestData requestData = Data() do { task = try factory.taskWithRequest(request, completionHandler: { (data, response, taskError) in // Check if there was an error with the network if taskError != nil { error = TTransportError(error: .timedOut) completed(self, error) return } // Check response type if taskError == nil && !(response is HTTPURLResponse) { error = THTTPTransportError(error: .invalidResponse) completed(self, error) return } // Check status code if let httpResponse = response as? HTTPURLResponse { if taskError == nil && httpResponse.statusCode != 200 { if httpResponse.statusCode == 401 { error = THTTPTransportError(error: .authentication) } else { error = THTTPTransportError(error: .invalidStatus(statusCode: httpResponse.statusCode)) } } // Allow factory to check if error != nil { do { try self.factory.validateResponse(httpResponse, data: data) } catch let validateError { error = validateError } } self.responseDataOffset = 0 if error != nil { self.responseData = Data() } else { self.responseData = data ?? Data() } completed(self, error) } }) } catch let taskError { error = taskError } if let error = error, task == nil { completed(self, error) } task?.resume() } public func flush() throws { let completed = DispatchSemaphore(value: 0) var internalError: Error? flush() { _, error in internalError = error completed.signal() } _ = completed.wait(timeout: DispatchTime.distantFuture) if let error = internalError { throw error } } } thrift-0.16.0/lib/swift/Sources/TList.swift000066400000000000000000000073551420101504100205360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ public struct TList : RandomAccessCollection, MutableCollection, ExpressibleByArrayLiteral, TSerializable, Hashable { public typealias Storage = Array public typealias Indices = Storage.Indices internal var storage = Storage() public init() { } public init(arrayLiteral elements: Element...) { self.storage = Storage(elements) } public init(_ sequence: Source) where Source.Iterator.Element == Element { storage = Storage(sequence) } /// Mark: Hashable public func hash(into hasher: inout Hasher) { hasher.combine(storage) } /// Mark: TSerializable public static var thriftType : TType { return .list } public static func read(from proto: TProtocol) throws -> TList { let (elementType, size) = try proto.readListBegin() if elementType != Element.thriftType { throw TProtocolError(error: .invalidData, extendedError: .unexpectedType(type: elementType)) } var list = TList() for _ in 0.. Element { get { return storage[position] } set { storage[position] = newValue } } public subscript(range: Range) -> SubSequence { get { return storage[range] } set { storage[range] = newValue } } public var startIndex: Index { return storage.startIndex } public var endIndex: Index { return storage.endIndex } public func formIndex(after i: inout Index) { storage.formIndex(after: &i) } public func formIndex(before i: inout Int) { storage.formIndex(before: &i) } public func index(after i: Index) -> Index { return storage.index(after: i) } public func index(before i: Int) -> Int { return storage.index(before: i) } } extension TList : RangeReplaceableCollection { public mutating func replaceSubrange(_ subrange: Range, with newElements: C) where C.Iterator.Element == Element { storage.replaceSubrange(subrange, with: newElements) } } extension TList : CustomStringConvertible, CustomDebugStringConvertible { public var description : String { return storage.description } public var debugDescription : String { return storage.debugDescription } } public func ==(lhs: TList, rhs: TList) -> Bool { return lhs.storage.elementsEqual(rhs.storage) { $0 == $1 } } thrift-0.16.0/lib/swift/Sources/TMap.swift000066400000000000000000000122771420101504100203370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ public struct TMap: Collection, ExpressibleByDictionaryLiteral, Hashable, TSerializable { public typealias Storage = Dictionary public typealias Element = Storage.Element public typealias Index = Storage.Index public typealias IndexDistance = Int public typealias Indices = Storage.Indices public typealias SubSequence = Storage.SubSequence internal var storage = Storage() /// Mark: Be Like Dictionary public func indexForKey(_ key: Key) -> Index? { return storage.index(forKey: key) } public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? { return storage.updateValue(value, forKey: key) } public mutating func removeValueForKey(_ key: Key) -> Value? { return storage.removeValue(forKey: key) } public init(minimumCapacity: Int) { storage = Storage(minimumCapacity: minimumCapacity) } /// init from Dictionary public init(_ dict: [Key: Value]) { storage = dict } /// read only access to storage if needed as Dictionary public var dictionary: [Key: Value] { return storage } public subscript (key: Key) -> Value? { get { return storage[key] } set { storage[key] = newValue } } /// Mark: Collection public var indices: Indices { return storage.indices } public func distance(from start: Index, to end: Index) -> IndexDistance { return storage.distance(from: start, to: end) } public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { return storage.index(i, offsetBy: n) } public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? { return storage.index(i, offsetBy: n, limitedBy: limit) } public subscript(position: Index) -> Element { return storage[position] } /// Mark: IndexableBase public var startIndex: Index { return storage.startIndex } public var endIndex: Index { return storage.endIndex } public func index(after i: Index) -> Index { return storage.index(after: i) } public func formIndex(after i: inout Index) { storage.formIndex(after: &i) } public subscript(bounds: Range) -> SubSequence { return storage[bounds] } /// Mark: DictionaryLiteralConvertible public init(dictionaryLiteral elements: (Key, Value)...) { storage = Storage() for (key, value) in elements { storage[key] = value } } /// Mark: Hashable public func hash(into hasher: inout Hasher) { hasher.combine(storage) } /// Mark: TSerializable public static var thriftType : TType { return .map } public init() { storage = Storage() } public static func read(from proto: TProtocol) throws -> TMap { let (keyType, valueType, size) = try proto.readMapBegin() if size > 0 { if keyType != Key.thriftType { throw TProtocolError(error: .invalidData, message: "Unexpected TMap Key Type", extendedError: .unexpectedType(type: keyType)) } if valueType != Value.thriftType { throw TProtocolError(error: .invalidData, message: "Unexpected TMap Value Type", extendedError: .unexpectedType(type: valueType)) } } var map = TMap() for _ in 0..(lhs: TMap, rhs: TMap) -> Bool { if lhs.count != rhs.count { return false } return lhs.storage.elementsEqual(rhs.storage) { $0.key == $1.key && $0.value == $1.value } } thrift-0.16.0/lib/swift/Sources/TMemoryBufferTransport.swift000066400000000000000000000042631420101504100241350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public class TMemoryBufferTransport : TTransport { public private(set) var readBuffer = Data() public private(set) var writeBuffer = Data() public private(set) var position = 0 public var bytesRemainingInBuffer: Int { return readBuffer.count - position } public func consumeBuffer(size: Int) { position += size } public func clear() { readBuffer = Data() writeBuffer = Data() } private var flushHandler: ((TMemoryBufferTransport, Data) -> ())? public init(flushHandler: ((TMemoryBufferTransport, Data) -> ())? = nil) { self.flushHandler = flushHandler } public convenience init(readBuffer: Data, flushHandler: ((TMemoryBufferTransport, Data) -> ())? = nil) { self.init() self.readBuffer = readBuffer } public func reset(readBuffer: Data = Data(), writeBuffer: Data = Data()) { self.readBuffer = readBuffer self.writeBuffer = writeBuffer } public func read(size: Int) throws -> Data { let amountToRead = min(bytesRemainingInBuffer, size) if amountToRead > 0 { let ret = readBuffer.subdata(in: Range(uncheckedBounds: (lower: position, upper: position + amountToRead))) position += ret.count return ret } return Data() } public func write(data: Data) throws { writeBuffer.append(data) } public func flush() throws { flushHandler?(self, writeBuffer) } } thrift-0.16.0/lib/swift/Sources/TMultiplexedProcessor.swift000066400000000000000000000065101420101504100240070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** `TMultiplexedProcessor` is a `TProcessor` allowing a single `TServer` to provide multiple services. To do so, you instantiate the processor and then register additional processors with it, as shown in the following example: let processor = MultiplexedProcessor() processor.register(CalculatorProcessor(service: CalculatorService()), for: "Calculator") processor.register(WeatherProcessor(service: CalculatorService()), for: "Weather") let server = TPerfectServer(port: 9090, processor: processor, TCompactProtocol.self, TCompactProtocol.self) try server.start() */ public class MultiplexedProcessor: TProcessor { enum Error: Swift.Error { case incompatibleMessageType(TMessageType) case missingProcessor(String) case missingDefaultProcessor } private var processors = [String: TProcessor]() private var defaultProcessor: TProcessor? public init(defaultProcessor: TProcessor? = nil) { self.defaultProcessor = defaultProcessor } public func register(defaultProcessor processor: TProcessor) { defaultProcessor = processor } public func register(processor: TProcessor, for service: String) { processors[service] = processor } public func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws { let message = try inProtocol.readMessageBegin() guard message.1 == .call || message.1 == .oneway else { throw Error.incompatibleMessageType(message.1) } if let separatorIndex = message.0.firstIndex(of: Character(.multiplexSeparator)) { let serviceName = String(message.0.prefix(upTo: separatorIndex)) let messageName = String(message.0.suffix(from: message.0.index(after: separatorIndex))) guard let processor = processors[serviceName] else { throw Error.missingProcessor(serviceName)} let storedMessage = StoredMessage(message: (messageName, message.1, message.2), proto: inProtocol) try processor.process(on: storedMessage, outProtocol: outProtocol) } else { guard let processor = defaultProcessor else { throw Error.missingDefaultProcessor } try processor.process(on: inProtocol, outProtocol: outProtocol) } } } private final class StoredMessage: TProtocolDecorator { private let message: (String, TMessageType, Int32) init(message: (String, TMessageType, Int32), proto: TProtocol) { self.message = message super.init(proto: proto) } required init(on transport: TTransport) { fatalError("init(on:) has not been implemented") } override func readMessageBegin() throws -> (String, TMessageType, Int32) { return message } } thrift-0.16.0/lib/swift/Sources/TMultiplexedProtocol.swift000066400000000000000000000043221420101504100236300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ extension String { static let multiplexSeparator = ":" } /** `TMultiplexedProtocol` is a protocol-independent concrete decorator that allows a Thrift client to communicate with a multiplexing Thrift server, by prepending the service name to the function name during function calls. - Note: THIS IS NOT USED BY SERVERS. On the server, use `TMultiplexedProcessor` to handle request from a multiplexing client. */ public class TMultiplexedProtocol: TWrappedProtocol { public var serviceName = "" public convenience init(on transport: TTransport, serviceName: String) { self.init(on: transport) self.serviceName = serviceName } override public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { switch messageType { case .call, .oneway: var serviceFunction = serviceName serviceFunction += serviceName == "" ? "" : .multiplexSeparator serviceFunction += name return try super.writeMessageBegin(name: serviceFunction, type: messageType, sequenceID: sequenceID) default: return try super.writeMessageBegin(name: name, type: messageType, sequenceID: sequenceID) } } } thrift-0.16.0/lib/swift/Sources/TProcessor.swift000066400000000000000000000015731420101504100215760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ public protocol TProcessor { func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws } thrift-0.16.0/lib/swift/Sources/TProtocol.swift000066400000000000000000000122751420101504100214210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public enum TMessageType: Int32 { case call = 1 case reply = 2 case exception = 3 case oneway = 4 } public enum TType: Int32 { case stop = 0 case void = 1 case bool = 2 case i8 = 3 case double = 4 case i16 = 6 case i32 = 8 case i64 = 10 case string = 11 case `struct` = 12 case map = 13 case set = 14 case list = 15 case utf8 = 16 case utf16 = 17 } public protocol TProtocol { var transport: TTransport { get set } init(on transport: TTransport) // Reading Methods func readMessageBegin() throws -> (String, TMessageType, Int32) func readMessageEnd() throws func readStructBegin() throws -> String func readStructEnd() throws func readFieldBegin() throws -> (String, TType, Int32) func readFieldEnd() throws func readMapBegin() throws -> (TType, TType, Int32) func readMapEnd() throws func readSetBegin() throws -> (TType, Int32) func readSetEnd() throws func readListBegin() throws -> (TType, Int32) func readListEnd() throws func read() throws -> String func read() throws -> Bool func read() throws -> UInt8 func read() throws -> Int16 func read() throws -> Int32 func read() throws -> Int64 func read() throws -> Double func read() throws -> Data // Writing methods func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws func writeMessageEnd() throws func writeStructBegin(name: String) throws func writeStructEnd() throws func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws func writeFieldStop() throws func writeFieldEnd() throws func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws func writeMapEnd() throws func writeSetBegin(elementType: TType, size: Int32) throws func writeSetEnd() throws func writeListBegin(elementType: TType, size: Int32) throws func writeListEnd() throws func write(_ value: String) throws func write(_ value: Bool) throws func write(_ value: UInt8) throws func write(_ value: Int16) throws func write(_ value: Int32) throws func write(_ value: Int64) throws func write(_ value: Double) throws func write(_ value: Data) throws } public extension TProtocol { func writeFieldValue(_ value: TSerializable, name: String, type: TType, id: Int32) throws { try writeFieldBegin(name: name, type: type, fieldID: id) try value.write(to: self) try writeFieldEnd() } func validateValue(_ value: Any?, named name: String) throws { if value == nil { throw TProtocolError(error: .unknown, message: "Missing required value for field: \(name)") } } func readResultMessageBegin() throws { let (_, type, _) = try readMessageBegin(); if type == .exception { let x = try readException() throw x } return } func readException() throws -> TApplicationError { return try TApplicationError.read(from: self) } func writeException(messageName name: String, sequenceID: Int32, ex: TApplicationError) throws { try writeMessageBegin(name: name, type: .exception, sequenceID: sequenceID) try ex.write(to: self) try writeMessageEnd() } func skip(type: TType) throws { switch type { case .bool: _ = try read() as Bool case .i8: _ = try read() as UInt8 case .i16: _ = try read() as Int16 case .i32: _ = try read() as Int32 case .i64: _ = try read() as Int64 case .double: _ = try read() as Double case .string: _ = try read() as String case .struct: _ = try readStructBegin() while true { let (_, fieldType, _) = try readFieldBegin() if fieldType == .stop { break } try skip(type: fieldType) try readFieldEnd() } try readStructEnd() case .map: let (keyType, valueType, size) = try readMapBegin() for _ in 0.. (String, TMessageType, Int32) { return try proto.readMessageBegin() } func readMessageEnd() throws { try proto.readMessageEnd() } func readStructBegin() throws -> String { return try proto.readStructBegin() } func readStructEnd() throws { try proto.readStructEnd() } func readFieldBegin() throws -> (String, TType, Int32) { return try proto.readFieldBegin() } func readFieldEnd() throws { try proto.readFieldEnd() } func readMapBegin() throws -> (TType, TType, Int32) { return try proto.readMapBegin() } func readMapEnd() throws { try proto.readMapEnd() } func readSetBegin() throws -> (TType, Int32) { return try proto.readSetBegin() } func readSetEnd() throws { try proto.readSetEnd() } func readListBegin() throws -> (TType, Int32) { return try proto.readListBegin() } func readListEnd() throws { try proto.readListEnd() } func read() throws -> String { return try proto.read() } func read() throws -> Bool { return try proto.read() } func read() throws -> UInt8 { return try proto.read() } func read() throws -> Int16 { return try proto.read() } func read() throws -> Int32 { return try proto.read() } func read() throws -> Int64 { return try proto.read() } func read() throws -> Double { return try proto.read() } func read() throws -> Data { return try proto.read() } func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { try proto.writeMessageBegin(name: name, type: messageType, sequenceID: sequenceID) } func writeMessageEnd() throws { try proto.writeMessageEnd() } func writeStructBegin(name: String) throws { try proto.writeStructBegin(name: name) } func writeStructEnd() throws { try proto.writeStructEnd() } func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { try proto.writeFieldBegin(name: name, type: fieldType, fieldID: fieldID) } func writeFieldStop() throws { try proto.writeFieldStop() } func writeFieldEnd() throws { try proto.writeFieldEnd() } func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { try proto.writeMapBegin(keyType: keyType, valueType: valueType, size: size) } func writeMapEnd() throws { try proto.writeMapEnd() } func writeSetBegin(elementType: TType, size: Int32) throws { try proto.writeSetBegin(elementType: elementType, size: size) } func writeSetEnd() throws { try proto.writeSetEnd() } func writeListBegin(elementType: TType, size: Int32) throws { try proto.writeListBegin(elementType: elementType, size: size) } func writeListEnd() throws { try proto.writeListEnd() } func write(_ value: String) throws { try proto.write(value) } func write(_ value: Bool) throws { try proto.write(value) } func write(_ value: UInt8) throws { try proto.write(value) } func write(_ value: Int16) throws { try proto.write(value) } func write(_ value: Int32) throws { try proto.write(value) } func write(_ value: Int64) throws { try proto.write(value) } func write(_ value: Double) throws { try proto.write(value) } func write(_ value: Data) throws { try proto.write(value) } } thrift-0.16.0/lib/swift/Sources/TProtocolError.swift000066400000000000000000000122621420101504100224270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public struct TProtocolError : TError { public init() { } public enum Code : TErrorCode { case unknown case invalidData case negativeSize case sizeLimit(limit: Int, got: Int) case badVersion(expected: String, got: String) case notImplemented case depthLimit public var thriftErrorCode: Int { switch self { case .unknown: return 0 case .invalidData: return 1 case .negativeSize: return 2 case .sizeLimit: return 3 case .badVersion: return 4 case .notImplemented: return 5 case .depthLimit: return 6 } } public var description: String { switch self { case .unknown: return "Unknown TProtocolError" case .invalidData: return "Invalid Data" case .negativeSize: return "Negative Size" case .sizeLimit(let limit, let got): return "Message exceeds size limit of \(limit) (received: \(got)" case .badVersion(let expected, let got): return "Bad Version. (Expected: \(expected), Got: \(got)" case .notImplemented: return "Not Implemented" case .depthLimit: return "Depth Limit" } } } public enum ExtendedErrorCode : TErrorCode { case unknown case missingRequiredField(fieldName: String) case unexpectedType(type: TType) case mismatchedProtocol(expected: String, got: String) public var thriftErrorCode: Int { switch self { case .unknown: return 1000 case .missingRequiredField: return 1001 case .unexpectedType: return 1002 case .mismatchedProtocol: return 1003 } } public var description: String { switch self { case .unknown: return "Unknown TProtocolExtendedError" case .missingRequiredField(let fieldName): return "Missing Required Field: \(fieldName)" case .unexpectedType(let type): return "Unexpected Type \(type.self)" case .mismatchedProtocol(let expected, let got): return "Mismatched Protocol. (Expected: \(expected), got \(got))" } } } public var extendedError: ExtendedErrorCode? = nil public init(error: Code = .unknown, message: String? = nil, extendedError: ExtendedErrorCode? = nil) { self.error = error self.message = message self.extendedError = extendedError } /// Mark: TError public var error: Code = .unknown public var message: String? = nil public static var defaultCase: Code { return .unknown } public var description: String { var out = "\(TProtocolError.self): (\(error.thriftErrorCode) \(error.description)\n" if let extendedError = extendedError { out += "TProtocolExtendedError (\(extendedError.thriftErrorCode)): \(extendedError.description)" } if let message = message { out += "Message: \(message)" } return out } } /// Wrapper for Transport errors in Protocols. Inspired by Thrift-Cocoa PROTOCOL_TRANSPORT_ERROR /// macro. Modified to be more Swift-y. Catches any TError thrown within the block and /// rethrows a given TProtocolError, the original error's description is appended to the new /// TProtocolError's message. sourceFile, sourceLine, sourceMethod are auto-populated and should /// be ignored when calling. /// /// - parameter error: TProtocolError to throw if the block throws /// - parameter sourceFile: throwing file, autopopulated /// - parameter sourceLine: throwing line, autopopulated /// - parameter sourceMethod: throwing method, autopopulated /// - parameter block: throwing block /// /// - throws: TProtocolError Default is TProtocolError.ErrorCode.unknown. Underlying /// error's description appended to TProtocolError.message func ProtocolTransportTry(error: TProtocolError = TProtocolError(), sourceFile: String = #file, sourceLine: Int = #line, sourceMethod: String = #function, block: () throws -> ()) throws { // Need mutable copy var error = error do { try block() } catch let err as TError { var message = error.message ?? "" message += "\nFile: \(sourceFile)\n" message += "Line: \(sourceLine)\n" message += "Method: \(sourceMethod)" message += "\nOriginal Error:\n" + err.description error.message = message throw error } } thrift-0.16.0/lib/swift/Sources/TSSLSocketTransport.swift000066400000000000000000000175341420101504100233520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation import CoreFoundation #if !swift(>=4.2) // Swift 3/4 compatibility fileprivate extension RunLoopMode { static let `default` = defaultRunLoopMode } #endif #if os(Linux) public class TSSLSocketTransport { init(hostname: String, port: UInt16) { // FIXME! assert(false, "Security not available in Linux, TSSLSocketTransport Unavilable for now") } } #else let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian let htons = isLittleEndian ? _OSSwapInt16 : { $0 } let htonl = isLittleEndian ? _OSSwapInt32 : { $0 } public class TSSLSocketTransport: TStreamTransport { var sslHostname: String var sd: Int32 = 0 public init(hostname: String, port: UInt16) throws { sslHostname = hostname var readStream: Unmanaged? var writeStream: Unmanaged? /* create a socket structure */ var pin: sockaddr_in = sockaddr_in() var hp: UnsafeMutablePointer? = nil for i in 0..<10 { hp = gethostbyname(hostname.cString(using: String.Encoding.utf8)!) if hp == nil { print("failed to resolve hostname \(hostname)") herror("resolv") if i == 9 { super.init(inputStream: nil, outputStream: nil) // have to init before throwing throw TSSLSocketTransportError(error: .hostanameResolution(hostname: hostname)) } Thread.sleep(forTimeInterval: 0.2) } else { break } } pin.sin_family = UInt8(AF_INET) pin.sin_addr = in_addr(s_addr: UInt32((hp?.pointee.h_addr_list.pointee?.pointee)!)) // Is there a better way to get this??? pin.sin_port = htons(port) /* create the socket */ sd = socket(Int32(AF_INET), Int32(SOCK_STREAM), Int32(IPPROTO_TCP)) if sd == -1 { super.init(inputStream: nil, outputStream: nil) // have to init before throwing throw TSSLSocketTransportError(error: .socketCreate(port: Int(port))) } /* open a connection */ // need a non-self ref to sd, otherwise the j complains let sd_local = sd let connectResult = withUnsafePointer(to: &pin) { connect(sd_local, UnsafePointer(OpaquePointer($0)), socklen_t(MemoryLayout.size)) } if connectResult == -1 { super.init(inputStream: nil, outputStream: nil) // have to init before throwing throw TSSLSocketTransportError(error: .connect) } CFStreamCreatePairWithSocket(kCFAllocatorDefault, sd, &readStream, &writeStream) CFReadStreamSetProperty(readStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue) CFWriteStreamSetProperty(writeStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue) var inputStream: InputStream? = nil var outputStream: OutputStream? = nil if readStream != nil && writeStream != nil { CFReadStreamSetProperty(readStream?.takeRetainedValue(), .socketSecurityLevel, kCFStreamSocketSecurityLevelTLSv1) let settings: [String: Bool] = [kCFStreamSSLValidatesCertificateChain as String: true] CFReadStreamSetProperty(readStream?.takeRetainedValue(), .SSLSettings, settings as CFTypeRef) CFWriteStreamSetProperty(writeStream?.takeRetainedValue(), .SSLSettings, settings as CFTypeRef) inputStream = readStream!.takeRetainedValue() inputStream?.schedule(in: .current, forMode: .default) inputStream?.open() outputStream = writeStream!.takeRetainedValue() outputStream?.schedule(in: .current, forMode: .default) outputStream?.open() readStream?.release() writeStream?.release() } super.init(inputStream: inputStream, outputStream: outputStream) self.input?.delegate = self self.output?.delegate = self } func recoverFromTrustFailure(_ myTrust: SecTrust, lastTrustResult: SecTrustResultType) -> Bool { let trustTime = SecTrustGetVerifyTime(myTrust) let currentTime = CFAbsoluteTimeGetCurrent() let timeIncrement = 31536000 // from TSSLSocketTransport.m let newTime = currentTime - Double(timeIncrement) if trustTime - newTime != 0 { let newDate = CFDateCreate(nil, newTime) SecTrustSetVerifyDate(myTrust, newDate!) var tr = lastTrustResult let success = withUnsafeMutablePointer(to: &tr) { trPtr -> Bool in if SecTrustEvaluate(myTrust, trPtr) != errSecSuccess { return false } return true } if !success { return false } } if lastTrustResult == .proceed || lastTrustResult == .unspecified { return false } print("TSSLSocketTransport: Unable to recover certificate trust failure") return true } public func isOpen() -> Bool { return sd > 0 } } extension TSSLSocketTransport: StreamDelegate { public func stream(_ aStream: Stream, handle eventCode: Stream.Event) { switch eventCode { case Stream.Event(): break case Stream.Event.hasBytesAvailable: break case Stream.Event.openCompleted: break case Stream.Event.hasSpaceAvailable: var proceed = false var trustResult: SecTrustResultType = .invalid var newPolicies: CFMutableArray? repeat { let trust: SecTrust = aStream.property(forKey: .SSLPeerTrust) as! SecTrust // Add new policy to current list of policies let policy = SecPolicyCreateSSL(false, sslHostname as CFString?) var ppolicy = policy // mutable for pointer let policies: UnsafeMutablePointer? = nil if SecTrustCopyPolicies(trust, policies!) != errSecSuccess { break } withUnsafeMutablePointer(to: &ppolicy) { ptr in newPolicies = CFArrayCreateMutableCopy(nil, 0, policies?.pointee) CFArrayAppendValue(newPolicies, ptr) } // update trust policies if SecTrustSetPolicies(trust, newPolicies!) != errSecSuccess { break } // Evaluate the trust chain let success = withUnsafeMutablePointer(to: &trustResult) { trustPtr -> Bool in if SecTrustEvaluate(trust, trustPtr) != errSecSuccess { return false } return true } if !success { break } switch trustResult { case .proceed: proceed = true case .unspecified: proceed = true case .recoverableTrustFailure: proceed = self.recoverFromTrustFailure(trust, lastTrustResult: trustResult) case .deny: break case .fatalTrustFailure: break case .otherError: break case .invalid: break default: break } } while false if !proceed { print("TSSLSocketTransport: Cannot trust certificate. Result: \(trustResult)") aStream.close() } case Stream.Event.errorOccurred: break case Stream.Event.endEncountered: break default: break } } } #endif thrift-0.16.0/lib/swift/Sources/TSSLSocketTransportError.swift000066400000000000000000000032411420101504100243520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ public struct TSSLSocketTransportError: TError { public enum ErrorCode: TErrorCode { case hostanameResolution(hostname: String) case socketCreate(port: Int) case connect public var thriftErrorCode: Int { switch self { case .hostanameResolution: return -10000 case .socketCreate: return -10001 case .connect: return -10002 } } public var description: String { switch self { case .hostanameResolution(let hostname): return "Failed to resolve hostname: \(hostname)" case .socketCreate(let port): return "Could not create socket on port: \(port)" case .connect: return "Connect error" } } } public var error: ErrorCode = .connect public var message: String? public static var defaultCase: ErrorCode { return .connect } public init() { } } thrift-0.16.0/lib/swift/Sources/TSerializable.swift000066400000000000000000000065031420101504100222230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public protocol TSerializable { /// TType for instance static var thriftType: TType { get } /// Read TSerializable instance from Protocol static func read(from proto: TProtocol) throws -> Self /// Write TSerializable instance to Protocol func write(to proto: TProtocol) throws } extension TSerializable { public static func write(_ value: Self, to proto: TProtocol) throws { try value.write(to: proto) } /// convenience for member access public var thriftType: TType { return Self.thriftType } } /// Default read/write for primitave Thrift types: /// Bool, Int8 (byte), Int16, Int32, Int64, Double, String extension Bool : TSerializable { public static var thriftType: TType { return .bool } public static func read(from proto: TProtocol) throws -> Bool { return try proto.read() } public func write(to proto: TProtocol) throws { try proto.write(self) } } extension Int8 : TSerializable { public static var thriftType: TType { return .i8 } public static func read(from proto: TProtocol) throws -> Int8 { return Int8(try proto.read() as UInt8) } public func write(to proto: TProtocol) throws { try proto.write(UInt8(self)) } } extension Int16 : TSerializable { public static var thriftType: TType { return .i16 } public static func read(from proto: TProtocol) throws -> Int16 { return try proto.read() } public func write(to proto: TProtocol) throws { try proto.write(self) } } extension Int32 : TSerializable { public static var thriftType: TType { return .i32 } public static func read(from proto: TProtocol) throws -> Int32 { return try proto.read() } public func write(to proto: TProtocol) throws { try proto.write(self) } } extension Int64 : TSerializable { public static var thriftType: TType { return .i64 } public static func read(from proto: TProtocol) throws -> Int64 { return try proto.read() } public func write(to proto: TProtocol) throws { try proto.write(self) } } extension Double : TSerializable { public static var thriftType: TType { return .double } public static func read(from proto: TProtocol) throws -> Double { return try proto.read() } public func write(to proto: TProtocol) throws { try proto.write(self) } } extension String : TSerializable { public static var thriftType: TType { return .string } public static func read(from proto: TProtocol) throws -> String { return try proto.read() } public func write(to proto: TProtocol) throws { try proto.write(self) } } thrift-0.16.0/lib/swift/Sources/TSet.swift000066400000000000000000000126741420101504100203560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public struct TSet : SetAlgebra, Hashable, Collection, ExpressibleByArrayLiteral, TSerializable { /// Typealias for Storage type public typealias Storage = Set /// Internal Storage used for TSet (Set\) internal var storage : Storage /// Mark: Collection public typealias Element = Storage.Element public typealias Indices = Storage.Indices public typealias Index = Storage.Index public typealias IndexDistance = Int public typealias SubSequence = Storage.SubSequence public var indices: Indices { return storage.indices } // Must implement isEmpty even though both SetAlgebra and Collection provide it due to their conflciting default implementations public var isEmpty: Bool { return storage.isEmpty } public func distance(from start: Index, to end: Index) -> IndexDistance { return storage.distance(from: start, to: end) } public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { return storage.index(i, offsetBy: n) } public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? { return storage.index(i, offsetBy: n, limitedBy: limit) } #if swift(>=3.2) public subscript (position: Storage.Index) -> Element { return storage[position] } #else public subscript (position: Storage.Index) -> Element? { return storage[position] } #endif /// Mark: SetAlgebra internal init(storage: Set) { self.storage = storage } public func contains(_ member: Element) -> Bool { return storage.contains(member) } public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) { return storage.insert(newMember) } public mutating func remove(_ member: Element) -> Element? { return storage.remove(member) } public func union(_ other: TSet) -> TSet { return TSet(storage: storage.union(other.storage)) } public mutating func formIntersection(_ other: TSet) { return storage.formIntersection(other.storage) } public mutating func formSymmetricDifference(_ other: TSet) { return storage.formSymmetricDifference(other.storage) } public mutating func formUnion(_ other: TSet) { return storage.formUnion(other.storage) } public func intersection(_ other: TSet) -> TSet { return TSet(storage: storage.intersection(other.storage)) } public func symmetricDifference(_ other: TSet) -> TSet { return TSet(storage: storage.symmetricDifference(other.storage)) } public mutating func update(with newMember: Element) -> Element? { return storage.update(with: newMember) } /// Mark: IndexableBase public var startIndex: Index { return storage.startIndex } public var endIndex: Index { return storage.endIndex } public func index(after i: Index) -> Index { return storage.index(after: i) } public func formIndex(after i: inout Storage.Index) { storage.formIndex(after: &i) } public subscript(bounds: Range) -> SubSequence { return storage[bounds] } /// Mark: Hashable public func hash(into hasher: inout Hasher) { hasher.combine(storage) } /// Mark: TSerializable public static var thriftType : TType { return .set } public init() { storage = Storage() } public init(arrayLiteral elements: Element...) { self.storage = Storage(elements) } public init(_ sequence: Source) where Source.Iterator.Element == Element { storage = Storage(sequence) } public static func read(from proto: TProtocol) throws -> TSet { let (elementType, size) = try proto.readSetBegin() if elementType != Element.thriftType { throw TProtocolError(error: .invalidData, extendedError: .unexpectedType(type: elementType)) } var set = TSet() for _ in 0..(lhs: TSet, rhs: TSet) -> Bool { return lhs.storage == rhs.storage } thrift-0.16.0/lib/swift/Sources/TSocketServer.swift000066400000000000000000000144341420101504100222360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) import Glibc import Dispatch #endif import Foundation import CoreFoundation public let TSocketServerClientConnectionFinished = "TSocketServerClientConnectionFinished" public let TSocketServerProcessorKey = "TSocketServerProcessor" public let TSocketServerTransportKey = "TSocketServerTransport" open class TSocketServer { var socketFileHandle: FileHandle var processingQueue = DispatchQueue(label: "TSocketServer.processing", qos: .background, attributes: .concurrent) let processor: Processor public init(port: Int, inProtocol: InProtocol.Type, outProtocol: OutProtocol.Type, processor: Processor) throws { self.processor = processor // create a socket var fd: Int32 = -1 #if os(Linux) let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, Int32(SOCK_STREAM.rawValue), Int32(IPPROTO_TCP), 0, nil, nil) #else let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, nil, nil) #endif if sock != nil { CFSocketSetSocketFlags(sock, CFSocketGetSocketFlags(sock) & ~CFOptionFlags(kCFSocketCloseOnInvalidate)) fd = CFSocketGetNative(sock) var yes = 1 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, UInt32(MemoryLayout.size)) let inPort = in_port_t(UInt16(truncatingIfNeeded: port).bigEndian) #if os(Linux) var addr = sockaddr_in(sin_family: sa_family_t(AF_INET), sin_port: inPort, sin_addr: in_addr(s_addr: in_addr_t(0)), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) #else var addr = sockaddr_in(sin_len: UInt8(MemoryLayout.size), sin_family: sa_family_t(AF_INET), sin_port: inPort, sin_addr: in_addr(s_addr: in_addr_t(0)), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) #endif let ptr = withUnsafePointer(to: &addr) { return UnsafePointer(OpaquePointer($0)) } let address = Data(bytes: ptr, count: MemoryLayout.size) let cfaddr = address.withUnsafeBytes { CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, $0.bindMemory(to: UInt8.self).baseAddress!, address.count, kCFAllocatorNull) } if CFSocketSetAddress(sock, cfaddr) != CFSocketError.success { //kCFSocketSuccess { CFSocketInvalidate(sock) print("TSocketServer: Could not bind to address") throw TTransportError(error: .notOpen, message: "Could not bind to address") } } else { print("TSocketServer: No server socket") throw TTransportError(error: .notOpen, message: "Could not create socket") } // wrap it in a file handle so we can get messages from it socketFileHandle = FileHandle(fileDescriptor: fd, closeOnDealloc: true) // throw away our socket CFSocketInvalidate(sock) // register for notifications of accepted incoming connections _ = NotificationCenter.default.addObserver(forName: .NSFileHandleConnectionAccepted, object: nil, queue: nil) { [weak self] notification in guard let strongSelf = self else { return } guard let clientSocket = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return } strongSelf.connectionAccepted(clientSocket) } // tell socket to listen socketFileHandle.acceptConnectionInBackgroundAndNotify() print("TSocketServer: Listening on TCP port \(port)") } deinit { NotificationCenter.default.removeObserver(self) } func connectionAccepted(_ clientSocket: FileHandle) { // Now that we have a client connected, handle the request on queue processingQueue.async { self.handleClientConnection(clientSocket) } // continue accepting connections socketFileHandle.acceptConnectionInBackgroundAndNotify() } open func createTransport(fileHandle: FileHandle) -> TTransport { return TFileHandleTransport(fileHandle: fileHandle) } func handleClientConnection(_ clientSocket: FileHandle) { let transport = createTransport(fileHandle: clientSocket) let inProtocol = InProtocol(on: transport) let outProtocol = OutProtocol(on: transport) do { while true { try processor.process(on: inProtocol, outProtocol: outProtocol) } } catch let error { print("Error processing request: \(error)") } DispatchQueue.main.async { NotificationCenter.default .post(name: Notification.Name(rawValue: TSocketServerClientConnectionFinished), object: self, userInfo: [TSocketServerProcessorKey: self.processor, TSocketServerTransportKey: transport]) } } } public class TFramedSocketServer: TSocketServer { open override func createTransport(fileHandle: FileHandle) -> TTransport { return TFramedTransport(transport: super.createTransport(fileHandle: fileHandle)) } } thrift-0.16.0/lib/swift/Sources/TSocketTransport.swift000066400000000000000000000151641420101504100227650ustar00rootroot00000000000000 /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) import Glibc import Dispatch #endif import Foundation import CoreFoundation #if !swift(>=4.2) // Swift 3/4 compatibility fileprivate extension RunLoopMode { static let `default` = defaultRunLoopMode } #endif private struct Sys { #if os(Linux) static let read = Glibc.read static let write = Glibc.write static let close = Glibc.close #else static let read = Darwin.read static let write = Darwin.write static let close = Darwin.close #endif } extension in_addr { public init?(hostent: hostent?) { guard let host = hostent, host.h_addr_list != nil, host.h_addr_list.pointee != nil else { return nil } self.init() memcpy(&self, host.h_addr_list.pointee!, Int(host.h_length)) } } #if os(Linux) /// TCFSocketTransport currently unavailable /// remove comments and build to see why/fix /// currently CF[Read|Write]Stream's can't cast to [Input|Output]Streams which breaks thigns #else extension Stream.PropertyKey { static let SSLPeerTrust = Stream.PropertyKey(kCFStreamPropertySSLPeerTrust as String) } /// TCFSocketTransport, uses CFSockets and (NS)Stream's public class TCFSocketTransport: TStreamTransport { public init?(hostname: String, port: Int, secure: Bool = false) { var inputStream: InputStream var outputStream: OutputStream var readStream: Unmanaged? var writeStream: Unmanaged? CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostname as CFString, UInt32(port), &readStream, &writeStream) if let readStream = readStream?.takeRetainedValue(), let writeStream = writeStream?.takeRetainedValue() { CFReadStreamSetProperty(readStream, .shouldCloseNativeSocket, kCFBooleanTrue) CFWriteStreamSetProperty(writeStream, .shouldCloseNativeSocket, kCFBooleanTrue) if secure { CFReadStreamSetProperty(readStream, .socketSecurityLevel, StreamSocketSecurityLevel.negotiatedSSL.rawValue as CFString) CFWriteStreamSetProperty(writeStream, .socketSecurityLevel, StreamSocketSecurityLevel.negotiatedSSL.rawValue as CFString) } inputStream = readStream as InputStream inputStream.schedule(in: .current, forMode: .default) inputStream.open() outputStream = writeStream as OutputStream outputStream.schedule(in: .current, forMode: .default) outputStream.open() } else { if readStream != nil { readStream?.release() } if writeStream != nil { writeStream?.release() } super.init(inputStream: nil, outputStream: nil) return nil } super.init(inputStream: inputStream, outputStream: outputStream) self.input?.delegate = self self.output?.delegate = self } } extension TCFSocketTransport: StreamDelegate { } #endif /// TSocketTransport, posix sockets. Supports IPv4 only for now public class TSocketTransport : TTransport { public var socketDescriptor: Int32 /// Initialize from an already set up socketDescriptor. /// Expects socket thats already bound/connected (i.e. from listening) /// /// - parameter socketDescriptor: posix socket descriptor (Int32) public init(socketDescriptor: Int32) { self.socketDescriptor = socketDescriptor } public convenience init(hostname: String, port: Int) throws { guard let hp = gethostbyname(hostname.cString(using: .utf8)!)?.pointee, let hostAddr = in_addr(hostent: hp) else { throw TTransportError(error: .unknown, message: "Invalid address: \(hostname)") } #if os(Linux) let sock = socket(AF_INET, Int32(SOCK_STREAM.rawValue), 0) var addr = sockaddr_in(sin_family: sa_family_t(AF_INET), sin_port: in_port_t(htons(UInt16(port))), sin_addr: hostAddr, sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) #else let sock = socket(AF_INET, SOCK_STREAM, 0) var addr = sockaddr_in(sin_len: UInt8(MemoryLayout.size), sin_family: sa_family_t(AF_INET), sin_port: in_port_t(htons(UInt16(port))), sin_addr: hostAddr, sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) #endif let addrPtr = withUnsafePointer(to: &addr){ UnsafePointer(OpaquePointer($0)) } let connected = connect(sock, addrPtr, UInt32(MemoryLayout.size)) if connected != 0 { throw TTransportError(error: .notOpen, message: "Error binding to host: \(hostname) \(port)") } self.init(socketDescriptor: sock) } deinit { close() } public func readAll(size: Int) throws -> Data { var out = Data() while out.count < size { out.append(try self.read(size: size)) } return out } public func read(size: Int) throws -> Data { var buff = Array.init(repeating: 0, count: size) let readBytes = Sys.read(socketDescriptor, &buff, size) return Data(buff[0.. 0 { let written = writeBuffer.withUnsafeBytes { Sys.write(socketDescriptor, $0.baseAddress!, writeBuffer.count) } writeBuffer = writeBuffer.subdata(in: written ..< writeBuffer.count) bytesToWrite -= written } } public func flush() throws { // nothing to do } public func close() { shutdown(socketDescriptor, Int32(SHUT_RDWR)) _ = Sys.close(socketDescriptor) } } thrift-0.16.0/lib/swift/Sources/TStreamTransport.swift000066400000000000000000000104271420101504100227650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation import CoreFoundation #if !swift(>=4.2) // Swift 3/4 compatibility fileprivate extension RunLoopMode { static let `default` = defaultRunLoopMode } #endif #if os(Linux) /// Currently unavailable in Linux /// Remove comments and build to fix /// Currently kConstants for CFSockets don't exist in linux and not all have been moved /// to property structs yet #else // Must inherit NSObject for NSStreamDelegate conformance public class TStreamTransport : NSObject, TTransport { public var input: InputStream? = nil public var output: OutputStream? = nil public init(inputStream: InputStream?, outputStream: OutputStream?) { input = inputStream output = outputStream } public convenience init(inputStream: InputStream?) { self.init(inputStream: inputStream, outputStream: nil) } public convenience init(outputStream: OutputStream?) { self.init(inputStream: nil, outputStream: outputStream) } deinit { close() } public func readAll(size: Int) throws -> Data { guard let input = input else { throw TTransportError(error: .unknown) } var read = Data() while read.count < size { var buffer = Array(repeating: 0, count: size - read.count) let bytesRead = buffer.withUnsafeMutableBufferPointer { bufferPtr in return input.read(bufferPtr.baseAddress!, maxLength: size - read.count) } if bytesRead <= 0 { throw TTransportError(error: .notOpen) } read.append(Data(buffer)) } return read } public func read(size: Int) throws -> Data { guard let input = input else { throw TTransportError(error: .unknown) } var read = Data() while read.count < size { var buffer = Array(repeating: 0, count: size - read.count) let bytesRead = buffer.withUnsafeMutableBufferPointer { input.read($0.baseAddress!, maxLength: size - read.count) } if bytesRead <= 0 { break } read.append(Data(buffer)) } return read } public func write(data: Data) throws { guard let output = output else { throw TTransportError(error: .unknown) } var bytesWritten = 0 while bytesWritten < data.count { bytesWritten = data.withUnsafeBytes { output.write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count) } if bytesWritten == -1 { throw TTransportError(error: .notOpen) } else if bytesWritten == 0 { throw TTransportError(error: .endOfFile) } } } public func flush() throws { return } public func close() { if input != nil { // Close and reset inputstream if let cf: CFReadStream = input { CFReadStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue) } input?.delegate = nil input?.close() input?.remove(from: .current, forMode: .default) input = nil } if output != nil { // Close and reset output stream if let cf: CFWriteStream = output { CFWriteStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue) } output?.delegate = nil output?.close() output?.remove(from: .current, forMode: .default) output = nil } } } #endif thrift-0.16.0/lib/swift/Sources/TStruct.swift000066400000000000000000000066121420101504100211020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /// Protocol for Generated Structs to conform to /// Dictionary maps field names to internal IDs and uses Reflection /// to iterate through all fields. /// `writeFieldValue(_:name:type:id:)` calls `TSerializable.write(to:)` internally /// giving a nice recursive behavior for nested TStructs, TLists, TMaps, and TSets public protocol TStruct : TSerializable { static var fieldIds: [String: Int32] { get } static var structName: String { get } } public extension TStruct { static var fieldIds: [String: (id: Int32, type: TType)] { return [:] } static var thriftType: TType { return .struct } func write(to proto: TProtocol) throws { // Write struct name first try proto.writeStructBegin(name: Self.structName) try self.forEach { name, value, id in // Write to protocol try proto.writeFieldValue(value, name: name, type: value.thriftType, id: id) } try proto.writeFieldStop() try proto.writeStructEnd() } /// Provides a block for handling each (available) thrift property using reflection /// Caveat: Skips over optional values /// Provides a block for handling each (available) thrift property using reflection /// /// - parameter block: block for handling property /// /// - throws: rethrows any Error thrown in block private func forEach(_ block: (_ name: String, _ value: TSerializable, _ id: Int32) throws -> Void) rethrows { // Mirror the object, getting (name: String?, value: Any) for every property let mirror = Mirror(reflecting: self) // Iterate through all children, ignore empty property names for (propName, propValue) in mirror.children { guard let propName = propName else { continue } if let tval = unwrap(any: propValue, parent: mirror) as? TSerializable, let id = Self.fieldIds[propName] { try block(propName, tval, id) } } } /// Any can mysteriously be an Optional at the same time, /// this checks and always returns Optional without double wrapping /// we then try to bind value as TSerializable to ignore any extension properties /// and the like and verify the property exists and grab the Thrift /// property ID at the same time /// /// - parameter any: Any instance to attempt to unwrap /// /// - returns: Unwrapped Any as Optional private func unwrap(any: Any, parent: Mirror) -> Any? { let mi = Mirror(reflecting: any) if parent.displayStyle != .enum && mi.displayStyle != .optional { return any } if mi.children.count == 0 { return nil } let (_, some) = mi.children.first! return some } } thrift-0.16.0/lib/swift/Sources/TTransport.swift000066400000000000000000000034151420101504100216100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation public protocol TTransport { // Required func read(size: Int) throws -> Data func write(data: Data) throws func flush() throws // Optional (default provided) func readAll(size: Int) throws -> Data func isOpen() throws -> Bool func open() throws func close() throws } public extension TTransport { func isOpen() throws -> Bool { return true } func open() throws { } func close() throws { } func readAll(size: Int) throws -> Data { var buff = Data() var have = 0 while have < size { let chunk = try self.read(size: size - have) have += chunk.count buff.append(chunk) if chunk.count == 0 { throw TTransportError(error: .endOfFile) } } return buff } } public protocol TAsyncTransport : TTransport { // Factory func flush(_ completion: @escaping (TAsyncTransport, Error?) ->()) } public protocol TAsyncTransportFactory { associatedtype Transport : TAsyncTransport func newTransport() -> Transport } thrift-0.16.0/lib/swift/Sources/TTransportError.swift000066400000000000000000000053401420101504100226210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ public struct TTransportError: TError { public enum ErrorCode: TErrorCode { case unknown case notOpen case alreadyOpen case timedOut case endOfFile case negativeSize case sizeLimit(limit: Int, got: Int) public var thriftErrorCode: Int { switch self { case .unknown: return 0 case .notOpen: return 1 case .alreadyOpen: return 2 case .timedOut: return 3 case .endOfFile: return 4 case .negativeSize: return 5 case .sizeLimit: return 6 } } public var description: String { switch self { case .unknown: return "Unknown TTransportError" case .notOpen: return "Not Open" case .alreadyOpen: return "Already Open" case .timedOut: return "Timed Out" case .endOfFile: return "End Of File" case .negativeSize: return "Negative Size" case .sizeLimit(let limit, let got): return "Message exceeds size limit of \(limit) (received: \(got)" } } } public var error: ErrorCode = .unknown public var message: String? = nil public static var defaultCase: ErrorCode { return .unknown } public init() { } } /// THTTPTransportError /// /// Error's thrown on HTTP Transport public struct THTTPTransportError: TError { public enum ErrorCode: TErrorCode { case invalidResponse case invalidStatus(statusCode: Int) case authentication public var description: String { switch self { case .invalidResponse: return "Invalid HTTP Response" case .invalidStatus(let statusCode): return "Invalid HTTP Status Code (\(statusCode))" case .authentication: return "Authentication Error" } } public var thriftErrorCode: Int { return 0 } } public var error: ErrorCode = .invalidResponse public var message: String? = nil public static var defaultCase: ErrorCode { return .invalidResponse } public init() { } } thrift-0.16.0/lib/swift/Sources/TWrappedProtocol.swift000066400000000000000000000130051420101504100227340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import Foundation // For (NS)Data /// Generic protocol, implementes TProtocol and wraps a concrete protocol. /// Useful for generically subclassing protocols to override specific methods /// (i.e. TMultiplexedProtocol) open class TWrappedProtocol : TProtocol { var concreteProtocol: Protocol public var transport: TTransport { get { return concreteProtocol.transport } set { concreteProtocol.transport = newValue } } public required init(on transport: TTransport) { self.concreteProtocol = Protocol(on: transport) } // Read methods public func readMessageBegin() throws -> (String, TMessageType, Int32) { return try concreteProtocol.readMessageBegin() } public func readMessageEnd() throws { try concreteProtocol.readMessageEnd() } public func readStructBegin() throws -> String { return try concreteProtocol.readStructBegin() } public func readStructEnd() throws { try concreteProtocol.readStructEnd() } public func readFieldBegin() throws -> (String, TType, Int32) { return try concreteProtocol.readFieldBegin() } public func readFieldEnd() throws { try concreteProtocol.readFieldEnd() } public func readMapBegin() throws -> (TType, TType, Int32) { return try concreteProtocol.readMapBegin() } public func readMapEnd() throws { try concreteProtocol.readMapEnd() } public func readSetBegin() throws -> (TType, Int32) { return try concreteProtocol.readSetBegin() } public func readSetEnd() throws { try concreteProtocol.readSetEnd() } public func readListBegin() throws -> (TType, Int32) { return try concreteProtocol.readListBegin() } public func readListEnd() throws { try concreteProtocol.readListEnd() } public func read() throws -> String { return try concreteProtocol.read() } public func read() throws -> Bool { return try concreteProtocol.read() } public func read() throws -> UInt8 { return try concreteProtocol.read() } public func read() throws -> Int16 { return try concreteProtocol.read() } public func read() throws -> Int32 { return try concreteProtocol.read() } public func read() throws -> Int64 { return try concreteProtocol.read() } public func read() throws -> Double { return try concreteProtocol.read() } public func read() throws -> Data { return try concreteProtocol.read() } // Write methods public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { return try concreteProtocol.writeMessageBegin(name: name, type: messageType, sequenceID: sequenceID) } public func writeMessageEnd() throws { try concreteProtocol.writeMessageEnd() } public func writeStructBegin(name: String) throws { try concreteProtocol.writeStructBegin(name: name) } public func writeStructEnd() throws { try concreteProtocol.writeStructEnd() } public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { try concreteProtocol.writeFieldBegin(name: name, type: fieldType, fieldID: fieldID) } public func writeFieldStop() throws { try concreteProtocol.writeFieldStop() } public func writeFieldEnd() throws { try concreteProtocol.writeFieldEnd() } public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { try concreteProtocol.writeMapBegin(keyType: keyType, valueType: valueType, size: size) } public func writeMapEnd() throws { try concreteProtocol.writeMapEnd() } public func writeSetBegin(elementType: TType, size: Int32) throws { try concreteProtocol.writeSetBegin(elementType: elementType, size: size) } public func writeSetEnd() throws { try concreteProtocol.writeSetEnd() } public func writeListBegin(elementType: TType, size: Int32) throws { try concreteProtocol.writeListBegin(elementType: elementType, size: size) } public func writeListEnd() throws { try concreteProtocol.writeListEnd() } public func write(_ value: String) throws { try concreteProtocol.write(value) } public func write(_ value: Bool) throws { try concreteProtocol.write(value) } public func write(_ value: UInt8) throws { try concreteProtocol.write(value) } public func write(_ value: Int16) throws { try concreteProtocol.write(value) } public func write(_ value: Int32) throws { try concreteProtocol.write(value) } public func write(_ value: Int64) throws { try concreteProtocol.write(value) } public func write(_ value: Double) throws { try concreteProtocol.write(value) } public func write(_ data: Data) throws { try concreteProtocol.write(data) } } thrift-0.16.0/lib/swift/Sources/Thrift.swift000066400000000000000000000000511420101504100207210ustar00rootroot00000000000000class Thrift { let version = "0.16.0" } thrift-0.16.0/lib/swift/Tests/000077500000000000000000000000001420101504100160665ustar00rootroot00000000000000thrift-0.16.0/lib/swift/Tests/LinuxMain.swift000066400000000000000000000002731420101504100210520ustar00rootroot00000000000000import XCTest @testable import ThriftTests XCTMain([ testCase(ThriftTests.allTests), testCase(TBinaryProtocolTests.allTests), testCase(TCompactProtocolTests.allTests), ]) thrift-0.16.0/lib/swift/Tests/ThriftTests/000077500000000000000000000000001420101504100203515ustar00rootroot00000000000000thrift-0.16.0/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift000066400000000000000000000120261420101504100255450ustar00rootroot00000000000000// // TBinaryProtocolTests.swift // Thrift // // Created by Christopher Simpson on 8/18/16. // // import XCTest import Foundation @testable import Thrift /// Testing Binary protocol read/write against itself /// Uses separate read/write transport/protocols class TBinaryProtocolTests: XCTestCase { var transport: TMemoryBufferTransport = TMemoryBufferTransport(flushHandler: { $0.reset(readBuffer: $1) }) var proto: TBinaryProtocol! override func setUp() { super.setUp() proto = TBinaryProtocol(on: transport) transport.reset() } override func tearDown() { super.tearDown() transport.reset() } func testInt8WriteRead() { let writeVal: UInt8 = 250 try? proto.write(writeVal) try? transport.flush() let readVal: UInt8 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with UInt8, wrote \(writeVal) but read \(readVal)") } func testInt16WriteRead() { let writeVal: Int16 = 12312 try? proto.write(writeVal) try? transport.flush() let readVal: Int16 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int16, wrote \(writeVal) but read \(readVal)") } func testInt32WriteRead() { let writeVal: Int32 = 2029234 try? proto.write(writeVal) try? transport.flush() let readVal: Int32 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int32, wrote \(writeVal) but read \(readVal)") } func testInt64WriteRead() { let writeVal: Int64 = 234234981374134 try? proto.write(writeVal) try? transport.flush() let readVal: Int64 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int64, wrote \(writeVal) but read \(readVal)") } func testDoubleWriteRead() { let writeVal: Double = 3.1415926 try? proto.write(writeVal) try? transport.flush() let readVal: Double = (try? proto.read()) ?? 0.0 XCTAssertEqual(writeVal, readVal, "Error with Double, wrote \(writeVal) but read \(readVal)") } func testBoolWriteRead() { let writeVal: Bool = true try? proto.write(writeVal) try? transport.flush() let readVal: Bool = (try? proto.read()) ?? false XCTAssertEqual(writeVal, readVal, "Error with Bool, wrote \(writeVal) but read \(readVal)") } func testStringWriteRead() { let writeVal: String = "Hello World" try? proto.write(writeVal) try? transport.flush() let readVal: String! do { readVal = try proto.read() } catch let error { XCTAssertFalse(true, "Error reading \(error)") return } XCTAssertEqual(writeVal, readVal, "Error with String, wrote \(writeVal) but read \(readVal)") } func testDataWriteRead() { let writeVal: Data = "Data World".data(using: .utf8)! try? proto.write(writeVal) try? transport.flush() let readVal: Data = (try? proto.read()) ?? "Goodbye World".data(using: .utf8)! XCTAssertEqual(writeVal, readVal, "Error with Data, wrote \(writeVal) but read \(readVal)") } func testStructWriteRead() { let msg = "Test Protocol Error" let writeVal = TApplicationError(error: .protocolError, message: msg) do { try writeVal.write(to: proto) try? transport.flush() } catch let error { XCTAssertFalse(true, "Caught Error attempting to write \(error)") } do { let readVal = try TApplicationError.read(from: proto) XCTAssertEqual(readVal.error.thriftErrorCode, writeVal.error.thriftErrorCode, "Error case mismatch, expected \(readVal.error) got \(writeVal.error)") XCTAssertEqual(readVal.message, writeVal.message, "Error message mismatch, expected \(readVal.message) got \(writeVal.message)") } catch let error { XCTAssertFalse(true, "Caught Error attempting to read \(error)") } } func testUnsafeBitcastUpdate() { let value: Double = 3.14159 let val: Int64 = 31415926 let uval: UInt64 = 31415926 let i64 = Int64(bitPattern: value.bitPattern) let ubc = unsafeBitCast(value, to: Int64.self) XCTAssertEqual(i64, ubc, "Bitcast Double-> i64 Values don't match") let dbl = Double(bitPattern: UInt64(val)) let ubdb = unsafeBitCast(val, to: Double.self) XCTAssertEqual(dbl, ubdb, "Bitcast i64 -> Double Values don't match") let db2 = Double(bitPattern: uval) let usbc2 = unsafeBitCast(uval, to: Double.self) XCTAssertEqual(db2, usbc2, "Bitcast u64 -> Double Values don't match") } static var allTests : [(String, (TBinaryProtocolTests) -> () throws -> Void)] { return [ ("testInt8WriteRead", testInt8WriteRead), ("testInt16WriteRead", testInt16WriteRead), ("testInt32WriteRead", testInt32WriteRead), ("testInt64WriteRead", testInt64WriteRead), ("testDoubleWriteRead", testDoubleWriteRead), ("testBoolWriteRead", testBoolWriteRead), ("testStringWriteRead", testStringWriteRead), ("testDataWriteRead", testDataWriteRead), ("testStructWriteRead", testStructWriteRead), ("testUnsafeBitcastUpdate", testUnsafeBitcastUpdate) ] } } thrift-0.16.0/lib/swift/Tests/ThriftTests/TCompactProtocolTests.swift000066400000000000000000000163051420101504100257130ustar00rootroot00000000000000// // TCompactProtocolTests.swift // Thrift // // Created by Christopher Simpson on 8/19/16. // // import XCTest import Foundation @testable import Thrift /// Testing Binary protocol read/write against itself /// Uses separate read/write transport/protocols class TCompactProtocolTests: XCTestCase { var transport: TMemoryBufferTransport = TMemoryBufferTransport(flushHandler: { $0.reset(readBuffer: $1) }) var proto: TCompactProtocol! override func setUp() { super.setUp() proto = TCompactProtocol(on: transport) transport.reset() } override func tearDown() { super.tearDown() transport.reset() } func testInt8WriteRead() { let writeVal: UInt8 = 250 try? proto.write(writeVal) try? transport.flush() let readVal: UInt8 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with UInt8, wrote \(writeVal) but read \(readVal)") } func testInt16WriteRead() { let writeVal: Int16 = 12312 try? proto.write(writeVal) try? transport.flush() let readVal: Int16 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int16, wrote \(writeVal) but read \(readVal)") } func testInt32WriteRead() { let writeVal: Int32 = 2029234 try? proto.write(writeVal) try? transport.flush() let readVal: Int32 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int32, wrote \(writeVal) but read \(readVal)") } func testInt64WriteRead() { let writeVal: Int64 = 234234981374134 try? proto.write(writeVal) try? transport.flush() let readVal: Int64 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int64, wrote \(writeVal) but read \(readVal)") } func testDoubleWriteRead() { let writeVal: Double = 3.1415926 try? proto.write(writeVal) try? transport.flush() let readVal: Double = (try? proto.read()) ?? 0.0 XCTAssertEqual(writeVal, readVal, "Error with Double, wrote \(writeVal) but read \(readVal)") } func testBoolWriteRead() { let writeVal: Bool = true try? proto.write(writeVal) try? transport.flush() let readVal: Bool = (try? proto.read()) ?? false XCTAssertEqual(writeVal, readVal, "Error with Bool, wrote \(writeVal) but read \(readVal)") } func testStringWriteRead() { let writeVal: String = "Hello World" try? proto.write(writeVal) try? transport.flush() let readVal: String! do { readVal = try proto.read() } catch let error { XCTAssertFalse(true, "Error reading \(error)") return } XCTAssertEqual(writeVal, readVal, "Error with String, wrote \(writeVal) but read \(readVal)") } func testDataWriteRead() { let writeVal: Data = "Data World".data(using: .utf8)! try? proto.write(writeVal) try? transport.flush() let readVal: Data = (try? proto.read()) ?? "Goodbye World".data(using: .utf8)! XCTAssertEqual(writeVal, readVal, "Error with Data, wrote \(writeVal) but read \(readVal)") } func testStructWriteRead() { let msg = "Test Protocol Error" let writeVal = TApplicationError(error: .protocolError, message: msg) do { try writeVal.write(to: proto) try transport.flush() } catch let error { XCTAssertFalse(true, "Caught Error attempting to write \(error)") } do { let readVal = try TApplicationError.read(from: proto) XCTAssertEqual(readVal.error.thriftErrorCode, writeVal.error.thriftErrorCode, "Error case mismatch, expected \(readVal.error) got \(writeVal.error)") XCTAssertEqual(readVal.message, writeVal.message, "Error message mismatch, expected \(readVal.message) got \(writeVal.message)") } catch let error { XCTAssertFalse(true, "Caught Error attempting to read \(error)") } } func testInt32ZigZag() { let zero: Int32 = 0 let one: Int32 = 1 let nOne: Int32 = -1 let two: Int32 = 2 let nTwo: Int32 = -2 let max = Int32.max let min = Int32.min XCTAssertEqual(proto.i32ToZigZag(zero), UInt32(0), "Error 32bit zigzag on \(zero)") XCTAssertEqual(proto.zigZagToi32(0), zero, "Error 32bit zigzag on \(zero)") XCTAssertEqual(proto.i32ToZigZag(nOne), UInt32(1), "Error 32bit zigzag on \(nOne)") XCTAssertEqual(proto.zigZagToi32(1), nOne, "Error 32bit zigzag on \(nOne)") XCTAssertEqual(proto.i32ToZigZag(one), UInt32(2), "Error 32bit zigzag on \(one)") XCTAssertEqual(proto.zigZagToi32(2), one, "Error 32bit zigzag on \(one)") XCTAssertEqual(proto.i32ToZigZag(nTwo), UInt32(3), "Error 32bit zigzag on \(nTwo)") XCTAssertEqual(proto.zigZagToi32(3), nTwo, "Error 32bit zigzag on \(nTwo)") XCTAssertEqual(proto.i32ToZigZag(two), UInt32(4), "Error 32bit zigzag on \(two)") XCTAssertEqual(proto.zigZagToi32(4), two, "Error 32bit zigzag on \(two)") let uMaxMinusOne: UInt32 = UInt32.max - 1 XCTAssertEqual(proto.i32ToZigZag(max), uMaxMinusOne, "Error 32bit zigzag on \(max)") XCTAssertEqual(proto.zigZagToi32(uMaxMinusOne), max, "Error 32bit zigzag on \(max)") XCTAssertEqual(proto.i32ToZigZag(min), UInt32.max, "Error 32bit zigzag on \(min)") XCTAssertEqual(proto.zigZagToi32(UInt32.max), min, "Error 32bit zigzag on \(min)") } func testInt64ZigZag() { let zero: Int64 = 0 let one: Int64 = 1 let nOne: Int64 = -1 let two: Int64 = 2 let nTwo: Int64 = -2 let max = Int64.max let min = Int64.min XCTAssertEqual(proto.i64ToZigZag(zero), UInt64(0), "Error 64bit zigzag on \(zero)") XCTAssertEqual(proto.zigZagToi64(0), zero, "Error 64bit zigzag on \(zero)") XCTAssertEqual(proto.i64ToZigZag(nOne), UInt64(1), "Error 64bit zigzag on \(nOne)") XCTAssertEqual(proto.zigZagToi64(1), nOne, "Error 64bit zigzag on \(nOne)") XCTAssertEqual(proto.i64ToZigZag(one), UInt64(2), "Error 64bit zigzag on \(one)") XCTAssertEqual(proto.zigZagToi64(2), one, "Error 64bit zigzag on \(one)") XCTAssertEqual(proto.i64ToZigZag(nTwo), UInt64(3), "Error 64bit zigzag on \(nTwo)") XCTAssertEqual(proto.zigZagToi64(3), nTwo, "Error 64bit zigzag on \(nTwo)") XCTAssertEqual(proto.i64ToZigZag(two), UInt64(4), "Error 64bit zigzag on \(two)") XCTAssertEqual(proto.zigZagToi64(4), two, "Error 64bit zigzag on \(two)") let uMaxMinusOne: UInt64 = UInt64.max - 1 XCTAssertEqual(proto.i64ToZigZag(max), uMaxMinusOne, "Error 64bit zigzag on \(max)") XCTAssertEqual(proto.zigZagToi64(uMaxMinusOne), max, "Error 64bit zigzag on \(max)") XCTAssertEqual(proto.i64ToZigZag(min), UInt64.max, "Error 64bit zigzag on \(min)") XCTAssertEqual(proto.zigZagToi64(UInt64.max), min, "Error 64bit zigzag on \(min)") } static var allTests : [(String, (TCompactProtocolTests) -> () throws -> Void)] { return [ ("testInt8WriteRead", testInt8WriteRead), ("testInt16WriteRead", testInt16WriteRead), ("testInt32WriteRead", testInt32WriteRead), ("testInt64WriteRead", testInt64WriteRead), ("testDoubleWriteRead", testDoubleWriteRead), ("testBoolWriteRead", testBoolWriteRead), ("testStringWriteRead", testStringWriteRead), ("testDataWriteRead", testDataWriteRead), ("testStructWriteRead", testStructWriteRead), ("testInt32ZigZag", testInt32ZigZag), ("testInt64ZigZag", testInt64ZigZag) ] } } thrift-0.16.0/lib/swift/Tests/ThriftTests/TFramedTransportTests.swift000066400000000000000000000132771420101504100257230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import XCTest import Foundation @testable import Thrift /// Testig TFramedTransport /// class TFramedTransportTests: XCTestCase { var underlyingTransport: TMemoryBufferTransport = TMemoryBufferTransport(flushHandler: { $0.reset(readBuffer: $1) }) var proto: TBinaryProtocol! var transport: TFramedTransport! override func setUp() { super.setUp() transport = TFramedTransport(transport:underlyingTransport) proto = TBinaryProtocol(on: transport) underlyingTransport.reset() } override func tearDown() { super.tearDown() underlyingTransport.reset() } func testInt8WriteRead() { let writeVal: UInt8 = 250 try? proto.write(writeVal) try? transport.flush() let readVal: UInt8 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with UInt8, wrote \(writeVal) but read \(readVal)") } func testInt16WriteRead() { let writeVal: Int16 = 12312 try? proto.write(writeVal) try? transport.flush() let readVal: Int16 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int16, wrote \(writeVal) but read \(readVal)") } func testInt32WriteRead() { let writeVal: Int32 = 2029234 try? proto.write(writeVal) try? transport.flush() let readVal: Int32 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int32, wrote \(writeVal) but read \(readVal)") } func testInt64WriteRead() { let writeVal: Int64 = 234234981374134 try? proto.write(writeVal) try? transport.flush() let readVal: Int64 = (try? proto.read()) ?? 0 XCTAssertEqual(writeVal, readVal, "Error with Int64, wrote \(writeVal) but read \(readVal)") } func testDoubleWriteRead() { let writeVal: Double = 3.1415926 try? proto.write(writeVal) try? transport.flush() let readVal: Double = (try? proto.read()) ?? 0.0 XCTAssertEqual(writeVal, readVal, "Error with Double, wrote \(writeVal) but read \(readVal)") } func testBoolWriteRead() { let writeVal: Bool = true try? proto.write(writeVal) try? transport.flush() let readVal: Bool = (try? proto.read()) ?? false XCTAssertEqual(writeVal, readVal, "Error with Bool, wrote \(writeVal) but read \(readVal)") } func testStringWriteRead() { let writeVal: String = "Hello World" try? proto.write(writeVal) try? transport.flush() let readVal: String! do { readVal = try proto.read() } catch let error { XCTAssertFalse(true, "Error reading \(error)") return } XCTAssertEqual(writeVal, readVal, "Error with String, wrote \(writeVal) but read \(readVal)") } func testDataWriteRead() { let writeVal: Data = "Data World".data(using: .utf8)! try? proto.write(writeVal) try? transport.flush() let readVal: Data = (try? proto.read()) ?? "Goodbye World".data(using: .utf8)! XCTAssertEqual(writeVal, readVal, "Error with Data, wrote \(writeVal) but read \(readVal)") } func testStructWriteRead() { let msg = "Test Protocol Error" let writeVal = TApplicationError(error: .protocolError, message: msg) do { try writeVal.write(to: proto) try? transport.flush() } catch let error { XCTAssertFalse(true, "Caught Error attempting to write \(error)") } do { let readVal = try TApplicationError.read(from: proto) XCTAssertEqual(readVal.error.thriftErrorCode, writeVal.error.thriftErrorCode, "Error case mismatch, expected \(readVal.error) got \(writeVal.error)") XCTAssertEqual(readVal.message, writeVal.message, "Error message mismatch, expected \(readVal.message) got \(writeVal.message)") } catch let error { XCTAssertFalse(true, "Caught Error attempting to read \(error)") } } func testUnsafeBitcastUpdate() { let value: Double = 3.14159 let val: Int64 = 31415926 let uval: UInt64 = 31415926 let i64 = Int64(bitPattern: value.bitPattern) let ubc = unsafeBitCast(value, to: Int64.self) XCTAssertEqual(i64, ubc, "Bitcast Double-> i64 Values don't match") let dbl = Double(bitPattern: UInt64(val)) let ubdb = unsafeBitCast(val, to: Double.self) XCTAssertEqual(dbl, ubdb, "Bitcast i64 -> Double Values don't match") let db2 = Double(bitPattern: uval) let usbc2 = unsafeBitCast(uval, to: Double.self) XCTAssertEqual(db2, usbc2, "Bitcast u64 -> Double Values don't match") } static var allTests : [(String, (TFramedTransportTests) -> () throws -> Void)] { return [ ("testInt8WriteRead", testInt8WriteRead), ("testInt16WriteRead", testInt16WriteRead), ("testInt32WriteRead", testInt32WriteRead), ("testInt64WriteRead", testInt64WriteRead), ("testDoubleWriteRead", testDoubleWriteRead), ("testBoolWriteRead", testBoolWriteRead), ("testStringWriteRead", testStringWriteRead), ("testDataWriteRead", testDataWriteRead), ("testStructWriteRead", testStructWriteRead), ("testUnsafeBitcastUpdate", testUnsafeBitcastUpdate) ] } } thrift-0.16.0/lib/swift/Tests/ThriftTests/TMultiplexedProcessorTests.swift000066400000000000000000000132121420101504100267710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import XCTest import Foundation @testable import Thrift private protocol CalculatorService { } private class Calculator: CalculatorService { } private class CalculatorProcessor: TProcessor { private let service: CalculatorService init(service: CalculatorService) { self.service = service } var processCalled = false func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws { processCalled = true } } class TMultiplexedProcessorTests: XCTestCase { let sut = MultiplexedProcessor() var transport: TMemoryBufferTransport = TMemoryBufferTransport { $0.reset(readBuffer: $1) } lazy var proto = TMultiplexedProtocol(on: transport) override func setUp() { super.setUp() transport.reset() } override func tearDown() { super.tearDown() transport.reset() } func testExceptionMessageThrowsError() throws { try proto.writeMessageBegin(name: "message", type: .exception, sequenceID: 1) try transport.flush() XCTAssertThrowsError(try sut.process(on: proto, outProtocol: proto)) { error in guard case MultiplexedProcessor.Error.incompatibleMessageType(let type) = error else { XCTFail() return } XCTAssertEqual(type, .exception) } } func testReplyMessageThrowsError() throws { try proto.writeMessageBegin(name: "message", type: .reply, sequenceID: 1) try transport.flush() XCTAssertThrowsError(try sut.process(on: proto, outProtocol: proto)) { error in guard case MultiplexedProcessor.Error.incompatibleMessageType(let type) = error else { XCTFail() return } XCTAssertEqual(type, .reply) } } func testMissingDefaultProcessorThrowsError() throws { try proto.writeMessageBegin(name: "message", type: .call, sequenceID: 1) try transport.flush() XCTAssertThrowsError(try sut.process(on: proto, outProtocol: proto)) { error in guard case MultiplexedProcessor.Error.missingDefaultProcessor = error else { XCTFail() return } } } func testUsesDefaultProcessorForNonMultiplexedMessage() throws { let calculator = Calculator() let calculatorProcessor = CalculatorProcessor(service: calculator) sut.register(defaultProcessor: calculatorProcessor) try proto.writeMessageBegin(name: "message", type: .call, sequenceID: 1) try transport.flush() try sut.process(on: proto, outProtocol: proto) XCTAssertTrue(calculatorProcessor.processCalled) } func testUsesProcessorForMultiplexedMessage() throws { let calculator = Calculator() let calculatorProcessor = CalculatorProcessor(service: calculator) sut.register(processor: calculatorProcessor, for: "Calculator") try proto.writeMessageBegin(name: "Calculator:message", type: .call, sequenceID: 1) try transport.flush() try sut.process(on: proto, outProtocol: proto) XCTAssertTrue(calculatorProcessor.processCalled) } func testMissingProcessorForMultiplexedMessageThrowsError() throws { try proto.writeMessageBegin(name: "Calculator:message", type: .call, sequenceID: 1) try transport.flush() XCTAssertThrowsError(try sut.process(on: proto, outProtocol: proto)) { error in guard case MultiplexedProcessor.Error.missingProcessor(let serviceName) = error else { XCTFail() return } XCTAssertEqual(serviceName, "Calculator") } } func testCallMessageDoesNotThrowError() throws { let calculator = Calculator() let calculatorProcessor = CalculatorProcessor(service: calculator) sut.register(defaultProcessor: calculatorProcessor) try proto.writeMessageBegin(name: "message", type: .call, sequenceID: 1) try transport.flush() try sut.process(on: proto, outProtocol: proto) } func testOneWayMessageDoesNotThrowError() throws { let calculator = Calculator() let calculatorProcessor = CalculatorProcessor(service: calculator) sut.register(defaultProcessor: calculatorProcessor) try proto.writeMessageBegin(name: "message", type: .oneway, sequenceID: 1) try transport.flush() try sut.process(on: proto, outProtocol: proto) } static var allTests : [(String, (TMultiplexedProcessorTests) -> () throws -> Void)] { return [ ("testExceptionMessageThrowsError", testExceptionMessageThrowsError), ("testReplyMessageThrowsError", testReplyMessageThrowsError), ("testMissingDefaultProcessorThrowsError", testMissingDefaultProcessorThrowsError), ("testUsesDefaultProcessorForNonMultiplexedMessage", testUsesDefaultProcessorForNonMultiplexedMessage), ("testUsesProcessorForMultiplexedMessage", testUsesProcessorForMultiplexedMessage), ("testMissingProcessorForMultiplexedMessageThrowsError", testMissingProcessorForMultiplexedMessageThrowsError), ("testCallMessageDoesNotThrowError", testCallMessageDoesNotThrowError), ("testOneWayMessageDoesNotThrowError", testOneWayMessageDoesNotThrowError) ] } } thrift-0.16.0/lib/swift/Tests/ThriftTests/TSocketServerTests.swift000066400000000000000000000033551420101504100252230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import XCTest import Foundation @testable import Thrift private protocol CalculatorService { } private class Calculator: CalculatorService { } private class CalculatorProcessor: TProcessor { private let service: CalculatorService init(service: CalculatorService) { self.service = service } var processCalled = false func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws { processCalled = true } } class TSocketServerTests: XCTestCase { func testInit() throws { let service: CalculatorService = Calculator() let processor: CalculatorProcessor = CalculatorProcessor(service: service) let _: TSocketServer = try TSocketServer(port: 9090, inProtocol: TBinaryProtocol.self, outProtocol: TBinaryProtocol.self, processor: processor) } static var allTests : [(String, (TSocketServerTests) -> () throws -> Void)] { return [ ("testInit", testInit), ] } } thrift-0.16.0/lib/swift/Tests/ThriftTests/ThriftTests.swift000066400000000000000000000004301420101504100237070ustar00rootroot00000000000000import XCTest @testable import Thrift class ThriftTests: XCTestCase { func testVersion() { XCTAssertEqual(Thrift().version, "0.16.0") } static var allTests : [(String, (ThriftTests) -> () throws -> Void)] { return [ ("testVersion", testVersion), ] } } thrift-0.16.0/lib/ts/000077500000000000000000000000001420101504100142565ustar00rootroot00000000000000thrift-0.16.0/lib/ts/Gruntfile.js000066400000000000000000000112241420101504100165530ustar00rootroot00000000000000//To build dist/thrift.js, dist/thrift.min.js and doc/* //run grunt at the command line in this directory. //Prerequisites: // Node Setup - nodejs.org // Grunt Setup - npm install //reads the ./package.json and installs project dependencies // Run grunt - npx grunt // uses project-local installed version of grunt (from package.json) module.exports = function(grunt) { 'use strict'; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), concat: { options: { separator: ';' }, dist: { src: ['src/**/*.js'], dest: 'dist/<%= pkg.name %>.js' } }, shell: { InstallThriftJS: { command: 'mkdir -p test/build/ts/lib; cp ../js/src/thrift.js test/build/ts/thrift.js' }, InstallThriftNodeJSDep: { command: 'cd ../..; npm install' }, InstallTestLibs: { command: 'cd test; ant download_jslibs' }, ThriftGen: { command: [ 'mkdir -p test/gen-js', '../../compiler/cpp/thrift -gen js:ts --out test/gen-js ../../test/ThriftTest.thrift', 'mkdir -p test/gen-nodejs', '../../compiler/cpp/thrift -gen js:node,ts --out test/gen-nodejs ../../test/ThriftTest.thrift', ].join(' && ') }, ThriftBrowserifyNodeInt64: { command: [ './node_modules/browserify/bin/cmd.js ./node_modules/node-int64/Int64.js -s Int64 -o test/build/js/lib/Int64.js', './node_modules/browserify/bin/cmd.js ../nodejs/lib/thrift/int64_util.js -s Int64Util -o test/build/js/lib/Int64Util.js', './node_modules/browserify/bin/cmd.js ./node_modules/json-int64/index.js -s JSONInt64 -o test/build/js/lib/JSONInt64.js' ].join(' && ') }, ThriftGenInt64: { command: '../../compiler/cpp/thrift -gen js:ts -o test ../../test/Int64Test.thrift' }, ThriftTestServer: { options: { async: true, execOptions: { cwd: "./test", env: {NODE_PATH: "../../nodejs/lib:../../../node_modules"} } }, command: "node server_http.js", }, BuildTS: { options: { execOptions: { cwd: "./test", } }, command : "../node_modules/typescript/bin/tsc --listFiles --outDir build/ts" }, BrowserifyCompiledTS: { command: [ "./node_modules/browserify/bin/cmd.js test/build/ts/test.js -o test/build/ts/lib/test.js --standalone test", "./node_modules/browserify/bin/cmd.js test/build/ts/test-int64.js -o test/build/ts/lib/test-int64.js --standalone testInt64", ].join(" && ") }, InstallGeneratedCode: { command: [ "mkdir -p test/build/ts", "cp -r test/gen-js test/build/ts" ].join(" && ") }, }, qunit: { ThriftJS: { options: { urls: [ 'http://localhost:8089/test.html' ], puppeteer: { headless: true, args: ['--no-sandbox'], }, } }, ThriftJS_Int64: { options: { urls: [ 'http://localhost:8089/test-int64.html' ], puppeteer: { headless: true, args: ['--no-sandbox'], ignoreHTTPSErrors: true, }, } }, }, jshint: { // The main Thrift library file. not es6 yet :( lib: { src: ['../js/src/**/*.js'], }, // The test files use es6 test: { src: ['Gruntfile.js', 'test/*.js'], options: { esversion: 6, } }, gen_js_code: { src: ['test/gen-js/*.js'], }, gen_node_code: { src: ['test/gen-nodejs/*.js'], options: { node: true, } }, }, }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-qunit'); grunt.loadNpmTasks('grunt-shell-spawn'); grunt.registerTask('wait', 'Wait just one second for the server to start', function () { var done = this.async(); setTimeout(function() { done(true); }, 1000); }); grunt.registerTask('installAndGenerate', [ 'shell:InstallThriftJS', 'shell:InstallThriftNodeJSDep', 'shell:ThriftGen', 'shell:ThriftBrowserifyNodeInt64', 'shell:ThriftGenInt64', 'shell:InstallTestLibs', 'shell:BuildTS', 'shell:InstallGeneratedCode', 'shell:BrowserifyCompiledTS', ]); grunt.registerTask('test', [ 'installAndGenerate', 'jshint', 'shell:ThriftTestServer', 'wait', 'qunit:ThriftJS', 'qunit:ThriftJS_Int64', 'shell:ThriftTestServer:kill', ]); grunt.registerTask('default', ['test']); }; thrift-0.16.0/lib/ts/Makefile.am000066400000000000000000000027141420101504100163160ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Make sure this doesn't fail if ant is not configured. # We call install twice to work around npm issues # if HAVE_NPM prereq: $(NPM) install || $(NPM) install $(NPM) list check-local: prereq all ./node_modules/.bin/grunt doc: prereq ./node_modules/.bin/grunt jsdoc endif clean-local: $(RM) -r dist $(RM) -r doc $(RM) -r node_modules $(RM) -r test/build/ $(RM) -r test/gen-*/ dist-hook: $(RM) -r $(distdir)/dist/ $(RM) -r $(distdir)/doc/ $(RM) -r $(distdir)/node_modules/ $(RM) -r $(distdir)/test/build/ $(RM) -r $(distdir)/test/gen-*/ EXTRA_DIST = \ coding_standards.md \ Gruntfile.js \ package.json \ package-lock.json \ thrift.d.ts \ tsconfig.json thrift-0.16.0/lib/ts/coding_standards.md000066400000000000000000000001031420101504100201000ustar00rootroot00000000000000Please follow [General Coding Standards](/doc/coding_standards.md) thrift-0.16.0/lib/ts/dist/000077500000000000000000000000001420101504100152215ustar00rootroot00000000000000thrift-0.16.0/lib/ts/dist/thrift.js000066400000000000000000000000001420101504100170450ustar00rootroot00000000000000thrift-0.16.0/lib/ts/dist/thrift.min.js000066400000000000000000000000311420101504100176330ustar00rootroot00000000000000/*! thrift 07-01-2019 */ thrift-0.16.0/lib/ts/package-lock.json000066400000000000000000004373221420101504100175050ustar00rootroot00000000000000{ "name": "thrift", "version": "0.16.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/parser": { "version": "7.15.8", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==" }, "@types/node": { "version": "10.12.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==", "dev": true }, "@types/node-int64": { "version": "0.4.29", "resolved": "https://registry.npmjs.org/@types/node-int64/-/node-int64-0.4.29.tgz", "integrity": "sha512-rHXvenLTj/CcsmNAebaBOhxQ2MqEGl3yXZZcZ21XYR+gzGTTcpOy2N4IxpvTCz48loyQNatHvfn6GhIbbZ1R3Q==", "dev": true, "requires": { "@types/node": "*" } }, "@types/phantom": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/@types/phantom/-/phantom-3.2.5.tgz", "integrity": "sha512-7m36DoKSvZgBGWp0xiJ74eHnuotyrpDyQ6m+lers5iMvW4QX+RvBENn7PCjNix7OVqPWlBM+7AqzYVIQ7NrKrA==", "dev": true }, "@types/qunit": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/@types/qunit/-/qunit-2.5.4.tgz", "integrity": "sha512-VHi2lEd4/zp8OOouf43JXGJJ5ZxHvdLL1dU0Yakp6Iy73SjpuXl7yjwAwmh1qhTv8krDgHteSwaySr++uXX9YQ==", "dev": true }, "JSONStream": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", "dev": true, "requires": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" } }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "acorn": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, "acorn-dynamic-import": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", "dev": true }, "acorn-node": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==", "dev": true, "requires": { "acorn": "^6.0.2", "acorn-dynamic-import": "^4.0.0", "acorn-walk": "^6.1.0", "xtend": "^4.0.1" } }, "acorn-walk": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", "dev": true }, "ajv": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", "repeat-string": "^1.5.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { "color-convert": "^2.0.1" }, "dependencies": { "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true } } }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { "sprintf-js": "~1.0.2" }, "dependencies": { "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" } } }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "dev": true }, "array-filter": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", "dev": true }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, "array-map": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", "dev": true }, "array-reduce": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", "dev": true }, "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { "safer-buffer": "~2.1.0" } }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "assert": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", "dev": true, "requires": { "util": "0.10.3" }, "dependencies": { "inherits": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", "dev": true }, "util": { "version": "0.10.3", "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { "inherits": "2.0.1" } } } }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, "async": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==", "dev": true }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, "aws4": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "dev": true, "requires": { "tweetnacl": "^0.14.3" } }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" } }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, "browser-pack": { "version": "6.1.0", "resolved": "http://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", "dev": true, "requires": { "JSONStream": "^1.0.3", "combine-source-map": "~0.8.0", "defined": "^1.0.0", "safe-buffer": "^5.1.1", "through2": "^2.0.0", "umd": "^3.0.0" } }, "browser-resolve": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", "dev": true, "requires": { "resolve": "1.1.7" }, "dependencies": { "resolve": { "version": "1.1.7", "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true } } }, "browserify": { "version": "16.2.3", "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", "dev": true, "requires": { "JSONStream": "^1.0.3", "assert": "^1.4.0", "browser-pack": "^6.0.1", "browser-resolve": "^1.11.0", "browserify-zlib": "~0.2.0", "buffer": "^5.0.2", "cached-path-relative": "^1.0.0", "concat-stream": "^1.6.0", "console-browserify": "^1.1.0", "constants-browserify": "~1.0.0", "crypto-browserify": "^3.0.0", "defined": "^1.0.0", "deps-sort": "^2.0.0", "domain-browser": "^1.2.0", "duplexer2": "~0.1.2", "events": "^2.0.0", "glob": "^7.1.0", "has": "^1.0.0", "htmlescape": "^1.1.0", "https-browserify": "^1.0.0", "inherits": "~2.0.1", "insert-module-globals": "^7.0.0", "labeled-stream-splicer": "^2.0.0", "mkdirp": "^0.5.0", "module-deps": "^6.0.0", "os-browserify": "~0.3.0", "parents": "^1.0.1", "path-browserify": "~0.0.0", "process": "~0.11.0", "punycode": "^1.3.2", "querystring-es3": "~0.2.0", "read-only-stream": "^2.0.0", "readable-stream": "^2.0.2", "resolve": "^1.1.4", "shasum": "^1.0.0", "shell-quote": "^1.6.1", "stream-browserify": "^2.0.0", "stream-http": "^2.0.0", "string_decoder": "^1.1.1", "subarg": "^1.0.0", "syntax-error": "^1.1.1", "through2": "^2.0.0", "timers-browserify": "^1.0.1", "tty-browserify": "0.0.1", "url": "~0.11.0", "util": "~0.10.1", "vm-browserify": "^1.0.0", "xtend": "^4.0.0" } }, "browserify-aes": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.3", "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "browserify-cipher": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", "evp_bytestokey": "^1.0.0" } }, "browserify-des": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, "browserify-rsa": { "version": "4.0.1", "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" } }, "browserify-sign": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { "bn.js": "^4.1.1", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "create-hmac": "^1.1.2", "elliptic": "^6.0.0", "inherits": "^2.0.1", "parse-asn1": "^5.0.0" } }, "browserify-zlib": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { "pako": "~1.0.5" } }, "buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "buffer-shims": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", "dev": true }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, "bufferutil": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.1.tgz", "integrity": "sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA==", "requires": { "node-gyp-build": "~3.7.0" } }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, "cached-path-relative": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==", "dev": true }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", "dev": true }, "camelcase-keys": { "version": "2.1.0", "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { "camelcase": "^2.0.0", "map-obj": "^1.0.0" } }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, "catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", "requires": { "lodash": "^4.17.15" } }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "requires": { "align-text": "^0.1.3", "lazy-cache": "^1.0.3" } }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", "dev": true, "requires": { "exit": "0.1.2", "glob": "^7.1.1" } }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "requires": { "center-align": "^0.1.1", "right-align": "^0.1.1", "wordwrap": "0.0.2" } }, "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "dev": true, "requires": { "color-convert": "^1.9.1", "color-string": "^1.5.2" } }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { "color-name": "1.1.3" } }, "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "color-string": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", "dev": true, "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "colornames": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=", "dev": true }, "colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, "colorspace": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", "dev": true, "requires": { "color": "3.0.x", "text-hex": "1.0.x" } }, "combine-source-map": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", "dev": true, "requires": { "convert-source-map": "~1.1.0", "inline-source-map": "~0.6.0", "lodash.memoize": "~3.0.3", "source-map": "~0.5.3" } }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" } }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, "requires": { "date-now": "^0.1.4" } }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", "dev": true }, "convert-source-map": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", "dev": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" } }, "create-hash": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", "md5.js": "^1.3.4", "ripemd160": "^2.0.1", "sha.js": "^2.4.0" } }, "create-hmac": { "version": "1.1.7", "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", "inherits": "^2.0.1", "ripemd160": "^2.0.0", "safe-buffer": "^5.0.1", "sha.js": "^2.4.8" } }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "dependencies": { "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } } } }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", "create-ecdh": "^4.0.0", "create-hash": "^1.1.0", "create-hmac": "^1.1.0", "diffie-hellman": "^5.0.0", "inherits": "^2.0.1", "pbkdf2": "^3.0.3", "public-encrypt": "^4.0.0", "randombytes": "^2.0.0", "randomfill": "^1.0.3" } }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, "requires": { "array-find-index": "^1.0.1" } }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", "dev": true }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, "deps-sort": { "version": "2.0.0", "resolved": "http://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", "dev": true, "requires": { "JSONStream": "^1.0.3", "shasum": "^1.0.0", "subarg": "^1.0.0", "through2": "^2.0.0" } }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "dev": true, "requires": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, "detective": { "version": "5.1.0", "resolved": "http://registry.npmjs.org/detective/-/detective-5.1.0.tgz", "integrity": "sha512-TFHMqfOvxlgrfVzTEkNBSh9SvSNX/HfF4OFI2QFGCyPm02EsyILqnUeb5P6q7JZ3SFNTBL5t2sePRgrN4epUWQ==", "dev": true, "requires": { "acorn-node": "^1.3.0", "defined": "^1.0.0", "minimist": "^1.1.1" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "diagnostics": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "dev": true, "requires": { "colorspace": "1.1.x", "enabled": "1.0.x", "kuler": "1.0.x" } }, "diffie-hellman": { "version": "5.0.3", "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" } }, "dom-serializer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { "domelementtype": "~1.1.1", "entities": "~1.1.1" }, "dependencies": { "domelementtype": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", "dev": true }, "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true } } }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, "domhandler": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", "dev": true, "requires": { "domelementtype": "1" } }, "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { "dom-serializer": "0", "domelementtype": "1" } }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "requires": { "readable-stream": "^2.0.2" } }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, "elliptic": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dev": true, "requires": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" }, "dependencies": { "bn.js": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true } } }, "enabled": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", "dev": true, "requires": { "env-variable": "0.0.x" } }, "entities": { "version": "1.0.0", "resolved": "http://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", "dev": true }, "env-variable": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==", "dev": true }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "es6-promise": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", "dev": true }, "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { "es6-promise": "^4.0.3" } }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "eventemitter2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", "dev": true }, "events": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", "dev": true }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" } }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, "extract-zip": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", "dev": true, "requires": { "concat-stream": "^1.6.2", "debug": "^2.6.9", "mkdirp": "^0.5.4", "yauzl": "^2.10.0" } }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, "fast-safe-stringify": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==", "dev": true }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, "requires": { "pend": "~1.2.0" } }, "fecha": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==", "dev": true }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { "escape-string-regexp": "^1.0.5", "object-assign": "^4.1.0" } }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" } }, "findup-sync": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", "dev": true, "requires": { "glob": "~5.0.0" }, "dependencies": { "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { "inflight": "^1.0.4", "inherits": "2", "minimatch": "2 || 3", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } } } }, "fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, "requires": { "expand-tilde": "^2.0.2", "is-plain-object": "^2.0.3", "object.defaults": "^1.1.0", "object.pick": "^1.2.0", "parse-filepath": "^1.0.1" } }, "flagged-respawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, "for-own": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { "for-in": "^1.0.1" } }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, "fs-extra": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", "klaw": "^1.0.0" }, "dependencies": { "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { "graceful-fs": "^4.1.9" } } } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "get-assigned-identifiers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", "dev": true }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, "getobject": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { "global-prefix": "^1.0.1", "is-windows": "^1.0.1", "resolve-dir": "^1.0.0" } }, "global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { "expand-tilde": "^2.0.2", "homedir-polyfill": "^1.0.1", "ini": "^1.3.4", "is-windows": "^1.0.1", "which": "^1.2.14" } }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, "grunt": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.4.1.tgz", "integrity": "sha512-ZXIYXTsAVrA7sM+jZxjQdrBOAg7DyMUplOMhTaspMRExei+fD0BTwdWXnn0W5SXqhb/Q/nlkzXclSi3IH55PIA==", "dev": true, "requires": { "dateformat": "~3.0.3", "eventemitter2": "~0.4.13", "exit": "~0.1.2", "findup-sync": "~0.3.0", "glob": "~7.1.6", "grunt-cli": "~1.4.2", "grunt-known-options": "~2.0.0", "grunt-legacy-log": "~3.0.0", "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.4.13", "js-yaml": "~3.14.0", "minimatch": "~3.0.4", "mkdirp": "~1.0.4", "nopt": "~3.0.6", "rimraf": "~3.0.2" }, "dependencies": { "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { "abbrev": "1" } }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } } } }, "grunt-cli": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, "requires": { "grunt-known-options": "~2.0.0", "interpret": "~1.1.0", "liftup": "~3.0.1", "nopt": "~4.0.1", "v8flags": "~3.2.0" } }, "grunt-contrib-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz", "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=", "dev": true, "requires": { "chalk": "^1.0.0", "source-map": "^0.5.3" }, "dependencies": { "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } } }, "grunt-contrib-jshint": { "version": "1.1.0", "resolved": "http://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz", "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=", "dev": true, "requires": { "chalk": "^1.1.1", "hooker": "^0.2.3", "jshint": "~2.9.4" }, "dependencies": { "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } } }, "grunt-contrib-qunit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/grunt-contrib-qunit/-/grunt-contrib-qunit-3.1.0.tgz", "integrity": "sha512-mdk8UltH6mxCD63E0hTXMAts42DOi4z4bBBrY7qnuHiShflMF7IueSMYe0zWaZ2dO8mgujh57Zfny2EbigJhRg==", "dev": true, "requires": { "eventemitter2": "^5.0.1", "p-each-series": "^1.0.0", "puppeteer": "^1.11.0" }, "dependencies": { "eventemitter2": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=", "dev": true } } }, "grunt-contrib-uglify": { "version": "1.0.2", "resolved": "http://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-1.0.2.tgz", "integrity": "sha1-rmekb5FT7dTLEYE6Vetpxw19svs=", "dev": true, "requires": { "chalk": "^1.0.0", "lodash": "^4.0.1", "maxmin": "^1.1.0", "uglify-js": "~2.6.2", "uri-path": "^1.0.0" }, "dependencies": { "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } } }, "grunt-jsdoc": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/grunt-jsdoc/-/grunt-jsdoc-2.4.1.tgz", "integrity": "sha512-S0zxU0wDewRu7z+vijEItOWe/UttxWVmvz0qz2ZVcAYR2GpXjsiski2CAVN0b18t2qeVLdmxZkJaEWCOsKzcAw==", "dev": true, "requires": { "cross-spawn": "^7.0.1", "jsdoc": "^3.6.3" } }, "grunt-known-options": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true }, "grunt-legacy-log": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", "dev": true, "requires": { "colors": "~1.1.2", "grunt-legacy-log-utils": "~2.1.0", "hooker": "~0.2.3", "lodash": "~4.17.19" } }, "grunt-legacy-log-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", "dev": true, "requires": { "chalk": "~4.1.0", "lodash": "~4.17.19" } }, "grunt-legacy-util": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", "dev": true, "requires": { "async": "~3.2.0", "exit": "~0.1.2", "getobject": "~1.0.0", "hooker": "~0.2.3", "lodash": "~4.17.21", "underscore.string": "~3.3.5", "which": "~2.0.2" }, "dependencies": { "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } } } }, "grunt-shell-spawn": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/grunt-shell-spawn/-/grunt-shell-spawn-0.3.12.tgz", "integrity": "sha512-TprZct92sQ4M2Q92piaeLsCrx4+gq/ageuxjZsRG6cglKt7x7rGA3YHt8D30+G789v+/pw4l0tDjEyrkMXx2tA==", "dev": true, "requires": { "grunt": ">=0.4.x" } }, "gzip-size": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", "dev": true, "requires": { "browserify-zlib": "^0.1.4", "concat-stream": "^1.4.1" }, "dependencies": { "browserify-zlib": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", "dev": true, "requires": { "pako": "~0.2.0" } }, "pako": { "version": "0.2.9", "resolved": "http://registry.npmjs.org/pako/-/pako-0.2.9.tgz", "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", "dev": true } } }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", "dev": true }, "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" } }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { "function-bind": "^1.1.1" } }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "hash-base": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, "hasha": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", "dev": true, "requires": { "is-stream": "^1.0.1", "pinkie-promise": "^2.0.0" } }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { "parse-passwd": "^1.0.0" } }, "hooker": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", "dev": true }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "htmlescape": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", "dev": true }, "htmlparser2": { "version": "3.8.3", "resolved": "http://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", "dev": true, "requires": { "domelementtype": "1", "domhandler": "2.3", "domutils": "1.5", "entities": "1.0", "readable-stream": "1.1" }, "dependencies": { "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, "readable-stream": { "version": "1.1.14", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "string_decoder": { "version": "0.10.31", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } } }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, "https-proxy-agent": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" }, "dependencies": { "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "requires": { "es6-promisify": "^5.0.0" } }, "debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" } }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", "dev": true }, "indent-string": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, "requires": { "repeating": "^2.0.0" } }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "inline-source-map": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", "dev": true, "requires": { "source-map": "~0.5.3" } }, "insert-module-globals": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", "dev": true, "requires": { "JSONStream": "^1.0.3", "acorn-node": "^1.5.2", "combine-source-map": "^0.8.0", "concat-stream": "^1.6.1", "is-buffer": "^1.1.0", "path-is-absolute": "^1.0.1", "process": "~0.11.0", "through2": "^2.0.0", "undeclared-identifiers": "^1.1.2", "xtend": "^4.0.0" } }, "interpret": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", "dev": true }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { "is-relative": "^1.0.0", "is-windows": "^1.0.1" } }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { "version": "1.0.0", "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { "builtin-modules": "^1.0.0" } }, "is-core-module": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dev": true, "requires": { "has": "^1.0.3" } }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-finite": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "^3.0.1" } }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" } }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" } }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, "js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" } }, "js2xmlparser": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", "requires": { "xmlcreate": "^2.0.3" } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, "jsdoc": { "version": "3.6.7", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", "requires": { "@babel/parser": "^7.9.4", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.1", "klaw": "^3.0.0", "markdown-it": "^10.0.0", "markdown-it-anchor": "^5.2.7", "marked": "^2.0.3", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", "underscore": "~1.13.1" }, "dependencies": { "escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" } } }, "jshint": { "version": "2.9.7", "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.7.tgz", "integrity": "sha512-Q8XN38hGsVQhdlM+4gd1Xl7OB1VieSuCJf+fEJjpo59JH99bVJhXRXAh26qQ15wfdd1VPMuDWNeSWoNl53T4YA==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", "lodash": "~4.17.10", "minimatch": "~3.0.2", "shelljs": "0.3.x", "strip-json-comments": "1.0.x" }, "dependencies": { "strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", "dev": true } } }, "jslint": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/jslint/-/jslint-0.12.0.tgz", "integrity": "sha512-RoCsyICcKA+6TFsbys9DpKTfPVaC71Mm5QSjvrWA0lDVN+LIvx6apa42FFisMqmCTvJ8DxkcoQGJ0j7m3kTVow==", "dev": true, "requires": { "exit": "~0.1.2", "glob": "~7.1.2", "nopt": "~3.0.1", "readable-stream": "~2.1.5" }, "dependencies": { "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { "abbrev": "1" } }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, "readable-stream": { "version": "2.1.5", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", "dev": true, "requires": { "buffer-shims": "^1.0.0", "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "~1.0.0", "process-nextick-args": "~1.0.6", "string_decoder": "~0.10.x", "util-deprecate": "~1.0.1" } }, "string_decoder": { "version": "0.10.31", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } } }, "json-int64": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-int64/-/json-int64-1.0.0.tgz", "integrity": "sha512-yrTg9swToElhEPETLMdZkEzDhbXLs+cxkw/b2rglMPOBlM1DE0utH1EReSMLcnpYJk5iUvD12r0fP2/xHitF5Q==", "requires": { "node-int64": "0.4.0" } }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", "dev": true, "requires": { "jsonify": "~0.0.0" } }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { "graceful-fs": "^4.1.6" } }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" } }, "kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", "dev": true }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, "klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", "requires": { "graceful-fs": "^4.1.9" } }, "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "dev": true, "requires": { "colornames": "^1.1.1" } }, "labeled-stream-splicer": { "version": "2.0.1", "resolved": "http://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", "dev": true, "requires": { "inherits": "^2.0.1", "isarray": "^2.0.4", "stream-splicer": "^2.0.0" }, "dependencies": { "isarray": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", "dev": true } } }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true }, "liftup": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", "dev": true, "requires": { "extend": "^3.0.2", "findup-sync": "^4.0.0", "fined": "^1.2.0", "flagged-respawn": "^1.0.1", "is-plain-object": "^2.0.4", "object.map": "^1.0.1", "rechoir": "^0.7.0", "resolve": "^1.19.0" }, "dependencies": { "findup-sync": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "dev": true, "requires": { "detect-file": "^1.0.0", "is-glob": "^4.0.0", "micromatch": "^4.0.2", "resolve-dir": "^1.0.1" } }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } } } }, "linkify-it": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "requires": { "uc.micro": "^1.0.1" } }, "load-json-file": { "version": "1.1.0", "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", "pinkie-promise": "^2.0.0", "strip-bom": "^2.0.0" } }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.memoize": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", "dev": true }, "logform": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", "dev": true, "requires": { "colors": "^1.2.1", "fast-safe-stringify": "^2.0.4", "fecha": "^2.3.3", "ms": "^2.1.1", "triple-beam": "^1.2.0" }, "dependencies": { "colors": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", "dev": true }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true } } }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "dev": true, "requires": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.0" } }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { "kind-of": "^6.0.2" } }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true }, "markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "requires": { "argparse": "^1.0.7", "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, "dependencies": { "entities": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" } } }, "markdown-it-anchor": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==" }, "marked": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==" }, "maxmin": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", "dev": true, "requires": { "chalk": "^1.0.0", "figures": "^1.0.1", "gzip-size": "^1.0.0", "pretty-bytes": "^1.0.0" }, "dependencies": { "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } } }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" }, "meow": { "version": "3.7.0", "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { "camelcase-keys": "^2.0.0", "decamelize": "^1.1.2", "loud-rejection": "^1.0.0", "map-obj": "^1.0.1", "minimist": "^1.1.3", "normalize-package-data": "^2.3.4", "object-assign": "^4.0.1", "read-pkg-up": "^1.0.1", "redent": "^1.0.0", "trim-newlines": "^1.0.0" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" } }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" } }, "mime": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", "dev": true }, "mime-db": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", "dev": true }, "mime-types": { "version": "2.1.21", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "dev": true, "requires": { "mime-db": "~1.37.0" } }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { "minimist": "^1.2.5" } }, "module-deps": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz", "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==", "dev": true, "requires": { "JSONStream": "^1.0.3", "browser-resolve": "^1.7.0", "cached-path-relative": "^1.0.0", "concat-stream": "~1.6.0", "defined": "^1.0.0", "detective": "^5.0.2", "duplexer2": "^0.1.2", "inherits": "^2.0.1", "parents": "^1.0.0", "readable-stream": "^2.0.2", "resolve": "^1.4.0", "stream-combiner2": "^1.1.1", "subarg": "^1.0.0", "through2": "^2.0.0", "xtend": "^4.0.0" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "node-gyp-build": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz", "integrity": "sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==" }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" }, "nopt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "requires": { "abbrev": "1", "osenv": "^0.1.4" } }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", "is-builtin-module": "^1.0.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "requires": { "array-each": "^1.0.1", "array-slice": "^1.0.0", "for-own": "^1.0.0", "isobject": "^3.0.0" } }, "object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", "dev": true, "requires": { "for-own": "^1.0.0", "make-iterator": "^1.0.0" } }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { "isobject": "^3.0.1" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" } }, "one-time": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=", "dev": true }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, "p-each-series": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", "dev": true, "requires": { "p-reduce": "^1.0.0" } }, "p-reduce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", "dev": true }, "pako": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.7.tgz", "integrity": "sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ==", "dev": true }, "parents": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", "dev": true, "requires": { "path-platform": "~0.11.15" } }, "parse-asn1": { "version": "5.1.1", "resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "dev": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", "pbkdf2": "^3.0.3" } }, "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "requires": { "is-absolute": "^1.0.0", "map-cache": "^0.2.0", "path-root": "^0.1.1" } }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { "error-ex": "^1.2.0" } }, "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, "path-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { "version": "1.0.1", "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-platform": { "version": "0.11.15", "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", "dev": true }, "path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { "path-root-regex": "^0.1.0" } }, "path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", "dev": true }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", "pinkie-promise": "^2.0.0" } }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "dev": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", "ripemd160": "^2.0.1", "safe-buffer": "^5.0.1", "sha.js": "^2.4.8" } }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, "phantom": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/phantom/-/phantom-6.0.3.tgz", "integrity": "sha512-8bb8urWoUiZ0E+JC4goaYBDPxljTnnxGwogz5cvash2SQovf//QAPoshXQz06kY/tpI+5caBVng0K0oZkVMNIQ==", "dev": true, "requires": { "phantomjs-prebuilt": "^2.1.16", "split": "^1.0.1", "winston": "^3.0.0" } }, "phantomjs-prebuilt": { "version": "2.1.16", "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", "dev": true, "requires": { "es6-promise": "^4.0.3", "extract-zip": "^1.6.5", "fs-extra": "^1.0.0", "hasha": "^2.2.0", "kew": "^0.7.0", "progress": "^1.1.8", "request": "^2.81.0", "request-progress": "^2.0.1", "which": "^1.2.10" }, "dependencies": { "progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true } } }, "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pify": { "version": "2.3.0", "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { "pinkie": "^2.0.0" } }, "pretty-bytes": { "version": "1.0.4", "resolved": "http://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", "dev": true, "requires": { "get-stdin": "^4.0.1", "meow": "^3.1.0" } }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", "dev": true }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", "dev": true }, "psl": { "version": "1.1.31", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", "dev": true }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" } }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, "puppeteer": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz", "integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==", "dev": true, "requires": { "debug": "^4.1.0", "extract-zip": "^1.6.6", "https-proxy-agent": "^2.2.1", "mime": "^2.0.3", "progress": "^2.0.1", "proxy-from-env": "^1.0.0", "rimraf": "^2.6.1", "ws": "^6.1.0" }, "dependencies": { "debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" } }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", "dev": true }, "querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", "dev": true, "requires": { "safe-buffer": "^5.1.0" } }, "randomfill": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "requires": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", "dev": true, "requires": { "readable-stream": "^2.0.2" } }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", "path-type": "^1.0.0" } }, "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" } }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" }, "dependencies": { "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } } } }, "rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { "resolve": "^1.9.0" } }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, "requires": { "indent-string": "^2.1.0", "strip-indent": "^1.0.1" } }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { "is-finite": "^1.0.0" } }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } }, "request-progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", "dev": true, "requires": { "throttleit": "^1.0.0" } }, "requizzle": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", "requires": { "lodash": "^4.17.14" } }, "resolve": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "requires": { "expand-tilde": "^2.0.0", "global-modules": "^1.0.0" } }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "requires": { "align-text": "^0.1.1" } }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { "glob": "^7.0.5" } }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true }, "sha.js": { "version": "2.4.11", "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "shasum": { "version": "1.0.2", "resolved": "http://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", "dev": true, "requires": { "json-stable-stringify": "~0.0.0", "sha.js": "~2.4.4" } }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "shell-quote": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", "dev": true, "requires": { "array-filter": "~0.0.0", "array-map": "~0.0.0", "array-reduce": "~0.0.0", "jsonify": "~0.0.0" } }, "shelljs": { "version": "0.3.0", "resolved": "http://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", "dev": true }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "simple-concat": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", "dev": true }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "dev": true, "requires": { "is-arrayish": "^0.3.1" }, "dependencies": { "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "dev": true } } }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", "dev": true }, "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", "dev": true, "requires": { "through": "2" } }, "sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", "dev": true }, "sshpk": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz", "integrity": "sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==", "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" } }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "dev": true }, "stream-browserify": { "version": "2.0.1", "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", "dev": true, "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" } }, "stream-combiner2": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", "dev": true, "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" } }, "stream-http": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", "readable-stream": "^2.3.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" } }, "stream-splicer": { "version": "2.0.0", "resolved": "http://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.2" } }, "string_decoder": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } }, "strip-ansi": { "version": "3.0.1", "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { "is-utf8": "^0.2.0" } }, "strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "dev": true, "requires": { "get-stdin": "^4.0.1" } }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, "subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", "dev": true, "requires": { "minimist": "^1.1.0" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" } }, "syntax-error": { "version": "1.4.0", "resolved": "http://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", "dev": true, "requires": { "acorn-node": "^1.2.0" } }, "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=" }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "dev": true }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", "dev": true }, "through": { "version": "2.3.8", "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "timers-browserify": { "version": "1.4.2", "resolved": "http://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", "dev": true, "requires": { "process": "~0.11.0" } }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" } }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" } }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", "dev": true }, "tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", "dev": true }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, "typescript": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==", "dev": true }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "uglify-js": { "version": "2.6.4", "resolved": "http://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=", "dev": true, "requires": { "async": "~0.2.6", "source-map": "~0.5.1", "uglify-to-browserify": "~1.0.0", "yargs": "~3.10.0" }, "dependencies": { "async": { "version": "0.2.10", "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", "dev": true } } }, "uglify-to-browserify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true }, "umd": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", "dev": true }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, "undeclared-identifiers": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz", "integrity": "sha512-13EaeocO4edF/3JKime9rD7oB6QI8llAGhgn5fKOPyfkJbRb6NFv9pYV6dFEmpa4uRjKeBqLZP8GpuzqHlKDMQ==", "dev": true, "requires": { "acorn-node": "^1.3.0", "get-assigned-identifiers": "^1.2.0", "simple-concat": "^1.0.0", "xtend": "^4.0.1" } }, "underscore": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" }, "underscore.string": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", "dev": true, "requires": { "sprintf-js": "^1.0.3", "util-deprecate": "^1.0.2" } }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { "punycode": "^2.1.0" }, "dependencies": { "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true } } }, "uri-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", "dev": true }, "url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "dev": true, "requires": { "punycode": "1.3.2", "querystring": "0.2.0" }, "dependencies": { "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", "dev": true } } }, "util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "dev": true, "requires": { "inherits": "2.0.3" } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true }, "v8flags": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" } }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "vm-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", "dev": true }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" } }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true }, "winston": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz", "integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==", "dev": true, "requires": { "async": "^2.6.0", "diagnostics": "^1.1.1", "is-stream": "^1.1.0", "logform": "^1.9.1", "one-time": "0.0.4", "readable-stream": "^2.3.6", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.2.0" }, "dependencies": { "async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { "lodash": "^4.17.10" } } } }, "winston-transport": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", "dev": true, "requires": { "readable-stream": "^2.3.6", "triple-beam": "^1.2.0" } }, "wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", "dev": true }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "ws": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "dev": true, "requires": { "async-limiter": "~1.0.0" } }, "xmlcreate": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==" }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true }, "yargs": { "version": "3.10.0", "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "requires": { "camelcase": "^1.0.2", "cliui": "^2.1.0", "decamelize": "^1.0.0", "window-size": "0.1.0" }, "dependencies": { "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "dev": true } } }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } } } } thrift-0.16.0/lib/ts/package.json000066400000000000000000000021631420101504100165460ustar00rootroot00000000000000{ "name": "thrift", "version": "0.16.0", "description": "Thrift is a software framework for scalable cross-language services development.", "author": { "name": "Apache Thrift Developers", "email": "dev@thrift.apache.org" }, "bugs": "https://issues.apache.org/jira/projects/THRIFT/summary", "homepage": "http://thrift.apache.org", "repository": "https://github.com/apache/thrift", "license": "Apache-2.0", "devDependencies": { "@types/node-int64": "^0.4.29", "@types/phantom": "^3.2.5", "@types/qunit": "^2.5.4", "browserify": "^16.2.3", "bufferutil": "^4.0.1", "grunt": "^1.4.1", "grunt-cli": "^1.4.3", "grunt-contrib-concat": "^1.0.1", "grunt-contrib-jshint": "^1.0.0", "grunt-contrib-qunit": "^3.1.0", "grunt-contrib-uglify": "^1.0.1", "grunt-jsdoc": "^2.4.1", "grunt-shell-spawn": "^0.3.12", "jslint": "^0.12.0", "node-int64": "^0.4.0", "phantom": "^6.0.3", "typescript": "^3.2.4" }, "dependencies": { "bufferutil": "^4.0.1", "jsdoc": "^3.6.7", "json-int64": "^1.0.0", "nopt": "^4.0.1" }, "types": "./thrift.d.ts" } thrift-0.16.0/lib/ts/test/000077500000000000000000000000001420101504100152355ustar00rootroot00000000000000thrift-0.16.0/lib/ts/test/build.xml000077500000000000000000000234101420101504100170610ustar00rootroot00000000000000 Java Script Test based on Thrift Java Library You need libthrift*.jar and libthrift*test.jar located at ${thrift.java.dir}/build/libs Did you compile Thrift Java library and its test suite by "ant compile-test"? Thrift compiler is missing ! check if Xvfb is available: check if phantomjs is available: Running Unit Tests with headless browser! check if gjslint is available: thrift-0.16.0/lib/ts/test/phantom-client.ts000066400000000000000000000331341420101504100205330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ import { ThriftTest } from "./gen-js/ThriftTest_types"; import "./gen-js/ThriftTest"; var Int64 = require("node-int64"); var phantom = require("phantom"); const int64_2_pow_60: typeof Int64 = new Int64('1000000000000000'); const int64_minus_2_pow_60: typeof Int64 = new Int64('f000000000000000'); (function() { 'use strict'; // Rudimentary test helper functions // TODO: Return error code based on kind of errors rather than throw var ok = function(t, msg) { if (!t) { console.log('*** FAILED ***'); throw new Error(msg); } }; var equal = function(a, b) { if (a !== b) { console.log('*** FAILED ***'); throw new Error(); } }; var test = function(name, f) { console.log('TEST : ' + name); f(); console.log('OK\n'); }; var parseArgs = function(args) { var skips = [ '--transport=http', '--protocol=json' ]; var opts = { port: '9090' // protocol: 'json', }; var keys = {}; for (var key in opts) { keys['--' + key + '='] = key; } for (var i in args) { var arg = args[i]; if (skips.indexOf(arg) != -1) { continue; } var hit = false; for (var k in keys) { if (arg.slice(0, k.length) === k) { opts[keys[k]] = arg.slice(k.length); hit = true; break; } } if (!hit) { throw new Error('Unknown argument: ' + arg); } } var portAsInt: number = parseInt(opts.port, 10); if (!opts.port || portAsInt < 1 || portAsInt > 65535) { throw new Error('Invalid port number'); } return opts; }; var execute = function() { console.log('### Apache Thrift Javascript standalone test client'); console.log('------------------------------------------------------------'); phantom.page.injectJs('thrift.js'); phantom.page.injectJs('gen-js/ThriftTest_types.js'); phantom.page.injectJs('gen-js/ThriftTest.js'); var system = require('system'); var opts = parseArgs(system.args.slice(1)); var port = opts.port; var transport = new Thrift.Transport('http://localhost:' + port + '/service'); var protocol = new Thrift.Protocol(transport); var client = new ThriftTest.ThriftTestClient(protocol); // TODO: Remove duplicate code with test.js. // all Languages in UTF-8 var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; function checkRecursively(map1, map2) { if (typeof map1 !== 'function' && typeof map2 !== 'function') { if (!map1 || typeof map1 !== 'object') { equal(map1, map2); } else { for (var key in map1) { checkRecursively(map1[key], map2[key]); } } } } test('Void', function() { equal(client.testVoid(), undefined); }); test('Binary (String)', function() { var binary: string = ''; for (var v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } equal(client.testBinary(binary), binary); }); test('Binary (Uint8Array)', function() { var binary: string = ''; for (var v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } var arr = new Uint8Array(binary.length); for (var i = 0; i < binary.length; ++i) { arr[i] = binary[i].charCodeAt(0); } const hexEncodedString = Array.from(arr, function(byte) { return String.fromCharCode(byte); }).join('') equal(client.testBinary(hexEncodedString), binary); }); test('String', function() { equal(client.testString(''), ''); equal(client.testString(stringTest), stringTest); var specialCharacters = 'quote: \" backslash:' + ' forwardslash-escaped: \/ ' + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + ' now-all-of-them-together: "\\\/\b\n\r\t' + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; equal(client.testString(specialCharacters), specialCharacters); }); test('Double', function() { equal(client.testDouble(0), 0); equal(client.testDouble(-1), -1); equal(client.testDouble(3.14), 3.14); equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60)); }); test('Bool', function() { equal(client.testBool(true), true); equal(client.testBool(false), false); }); test('I8', function() { equal(client.testByte(0), 0); equal(client.testByte(0x01), 0x01); }); test('I32', function() { equal(client.testI32(0), 0); equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30)); equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30)); }); test('I64', function() { equal(client.testI64(new Int64(0)), 0); equal(client.testI64(int64_2_pow_60), Math.pow(2, 52)); equal(client.testI64(int64_minus_2_pow_60), -Math.pow(2, 52)); }); test('Struct', function() { var structTestInput: ThriftTest.Xtruct = new ThriftTest.Xtruct(); structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); structTestInput.i64_thing = int64_2_pow_60; var structTestOutput: ThriftTest.Xtruct = client.testStruct(structTestInput); equal(structTestOutput.string_thing, structTestInput.string_thing); equal(structTestOutput.byte_thing, structTestInput.byte_thing); equal(structTestOutput.i32_thing, structTestInput.i32_thing); equal(structTestOutput.i64_thing, structTestInput.i64_thing); equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput)); }); test('Nest', function() { var xtrTestInput: ThriftTest.Xtruct = new ThriftTest.Xtruct(); xtrTestInput.string_thing = 'worked'; xtrTestInput.byte_thing = 0x01; xtrTestInput.i32_thing = Math.pow(2, 30); xtrTestInput.i64_thing = int64_2_pow_60; var nestTestInput: ThriftTest.Xtruct2 = new ThriftTest.Xtruct2(); nestTestInput.byte_thing = 0x02; nestTestInput.struct_thing = xtrTestInput; nestTestInput.i32_thing = Math.pow(2, 15); var nestTestOutput = client.testNest(nestTestInput); equal(nestTestOutput.byte_thing, nestTestInput.byte_thing); equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); equal(nestTestOutput.i32_thing, nestTestInput.i32_thing); equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput)); }); test('Map', function() { var mapTestInput: {[k: number]: number;} = {7: 77, 8: 88, 9: 99}; var mapTestOutput: {[k: number]: number;} = client.testMap(mapTestInput); for (var key in mapTestOutput) { equal(mapTestOutput[key], mapTestInput[key]); } }); test('StringMap', function() { var mapTestInput: {[k: string]: string;} = { 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', 'longValue': stringTest, stringTest: 'long key' }; var mapTestOutput: {[k: string]: string;} = client.testStringMap(mapTestInput); for (var key in mapTestOutput) { equal(mapTestOutput[key], mapTestInput[key]); } }); test('Set', function() { var setTestInput: number[] = [1, 2, 3]; ok(client.testSet(setTestInput), setTestInput); }); test('List', function() { var listTestInput: number[] = [1, 2, 3]; ok(client.testList(listTestInput), listTestInput); }); test('Enum', function() { equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE); }); test('TypeDef', function() { equal(client.testTypedef(new Int64(69)), 69); }); test('MapMap', function() { var mapMapTestExpectedResult: {[K: number]: {[k: number]: number}} = { '4': {'1': 1, '2': 2, '3': 3, '4': 4}, '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} }; var mapMapTestOutput = client.testMapMap(1); for (var key in mapMapTestOutput) { for (var key2 in mapMapTestOutput[key]) { equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]); } } checkRecursively(mapMapTestOutput, mapMapTestExpectedResult); }); test('Xception', function() { try { client.testException('Xception'); ok(false, "expected an exception but there was no exception"); } catch (e) { equal(e.errorCode, 1001); equal(e.message, 'Xception'); } }); test('no Exception', function() { try { client.testException('no Exception'); } catch (e) { ok(false, "expected no exception but here was an exception"); } }); test('TException', function() { try { client.testException('TException'); ok(false, "expected an exception but there was no exception"); } catch (e) { ok(ok, "succesfully got exception"); } }); const crazy: ThriftTest.Insanity = { 'userMap': { '5': new Int64(5), '8': new Int64(8) }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': new Int64(4) }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': new Int64(2) }] }; test('Insanity', function() { const insanity: {[k: number]: (ThriftTest.Insanity | {[k:number]: ThriftTest.Insanity})} = { '1': { '2': crazy, '3': crazy }, '2': { '6': new ThriftTest.Insanity() } }; var res = client.testInsanity(new ThriftTest.Insanity(crazy)); ok(res, JSON.stringify(res)); ok(insanity, JSON.stringify(insanity)); checkRecursively(res, insanity); }); console.log('------------------------------------------------------------'); console.log('### All tests succeeded.'); return 0; }; try { var ret = execute(); phantom.exit(ret); } catch (err) { // Catch all and exit to avoid hang. console.error(err); phantom.exit(1); } })(); thrift-0.16.0/lib/ts/test/server_http.js000066400000000000000000000041241420101504100201410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // This HTTP server is designed to serve the test.html browser // based JavaScript test page (which must be in the current directory). // This server also supplies the Thrift based test service, which depends // on the standard ThriftTest.thrift IDL service (which must be compiled // for Node and browser based JavaScript in ./gen-nodejs and ./gen-js // respectively). // // Using the command flag --es6, this server can be run using nodejs code built // for the es6 environment or for pre-es6 environment. // const thrift = require('../../nodejs/lib/thrift'); const es6Mode = process.argv.includes('--es6'); const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs'; const ThriftTestSvc = require(`./${genFolder}/ThriftTest.js`); const ThriftTestHandler = require('./test_handler').ThriftTestHandler; const ThriftTestSvcOpt = { transport: thrift.TBufferedTransport, protocol: thrift.TJSONProtocol, processor: ThriftTestSvc, handler: ThriftTestHandler }; const ThriftWebServerOptions = { files: __dirname, services: { '/service': ThriftTestSvcOpt } }; const server = thrift.createWebServer(ThriftWebServerOptions); const port = es6Mode ? 8088 : 8089; server.listen(port); console.log(`Serving files from: ${__dirname}`); console.log(`Http/Thrift Server (ES6 mode ${es6Mode}) running on port: ${port}`); thrift-0.16.0/lib/ts/test/test-int64.html000066400000000000000000000037221420101504100200500ustar00rootroot00000000000000+ Int64 Constants in JS: Unit Test

Int64 Constants in JS: Unit Test

thrift-0.16.0/lib/ts/test/test-int64.ts000066400000000000000000000076011420101504100175320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* jshint -W100 */ var Int64 = require("node-int64"); var JSONInt64 = require("json-int64"); import { Int64Test } from "./gen-js/Int64Test_types"; // Work around for old API used by QUnitAdapter of jsTestDriver if (typeof QUnit.log == 'function') { // When using real QUnit (fron PhantomJS) log failures to console QUnit.log(function(details) { if (!details.result) { console.log('======== FAIL ========'); console.log('TestName: ' + details.name); if (details.message) console.log(details.message); console.log('Expected: ' + details.expected); console.log('Actual : ' + details.actual); console.log('======================'); } }); } QUnit.module('Int64'); QUnit.test('Int64', function(assert) { console.log('Int64 test -- starts'); const EXPECTED_SMALL_INT64_AS_NUMBER: number = 42; const EXPECTED_SMALL_INT64: typeof Int64 = new Int64(42); const EXPECTED_MAX_JS_SAFE_INT64: typeof Int64 = new Int64(Number.MAX_SAFE_INTEGER); const EXPECTED_MIN_JS_SAFE_INT64: typeof Int64 = new Int64(Number.MIN_SAFE_INTEGER); const EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64: typeof Int64 = new Int64("0020000000000000"); // hex-encoded const EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64: typeof Int64 = new Int64("ffe0000000000000"); // hex-encoded 2's complement const EXPECTED_MAX_SIGNED_INT64: typeof Int64 = new Int64("7fffffffffffffff"); // hex-encoded const EXPECTED_MIN_SIGNED_INT64: typeof Int64 = new Int64("8000000000000000"); // hex-encoded 2's complement const EXPECTED_INT64_LIST = [ EXPECTED_SMALL_INT64, EXPECTED_MAX_JS_SAFE_INT64, EXPECTED_MIN_JS_SAFE_INT64, EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64, EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64, EXPECTED_MAX_SIGNED_INT64, EXPECTED_MIN_SIGNED_INT64 ]; assert.ok(EXPECTED_SMALL_INT64.equals(Int64Test.SMALL_INT64)); assert.ok(EXPECTED_MAX_JS_SAFE_INT64.equals(Int64Test.MAX_JS_SAFE_INT64)); assert.ok(EXPECTED_MIN_JS_SAFE_INT64.equals(Int64Test.MIN_JS_SAFE_INT64)); assert.ok( EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64.equals( Int64Test.MAX_JS_SAFE_PLUS_ONE_INT64 ) ); assert.ok( EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64.equals( Int64Test.MIN_JS_SAFE_MINUS_ONE_INT64 ) ); assert.ok(EXPECTED_MAX_SIGNED_INT64.equals(Int64Test.MAX_SIGNED_INT64)); assert.ok(EXPECTED_MIN_SIGNED_INT64.equals(Int64Test.MIN_SIGNED_INT64)); assert.equal( EXPECTED_SMALL_INT64_AS_NUMBER, Int64Test.SMALL_INT64.toNumber() ); assert.equal( Number.MAX_SAFE_INTEGER, Int64Test.MAX_JS_SAFE_INT64.toNumber() ); assert.equal( Number.MIN_SAFE_INTEGER, Int64Test.MIN_JS_SAFE_INT64.toNumber() ); for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i) { assert.ok(EXPECTED_INT64_LIST[i].equals(Int64Test.INT64_LIST[i])); } for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i){ let int64Object = EXPECTED_INT64_LIST[i]; assert.ok(Int64Test.INT64_2_INT64_MAP[JSONInt64.toDecimalString(int64Object)].equals(int64Object)); } console.log('Int64 test -- ends'); }); thrift-0.16.0/lib/ts/test/test.html000077500000000000000000000051371420101504100171130ustar00rootroot00000000000000 Thrift Javascript Bindings: Unit Test

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

thrift-0.16.0/lib/ts/test/test.ts000066400000000000000000000332211420101504100165650ustar00rootroot00000000000000import { ThriftTest } from "./gen-js/ThriftTest_types"; import "./gen-js/ThriftTest"; var Int64 = require("node-int64"); var JSONInt64 = require("json-int64"); var QUnit = require("./qunit"); const transport: Thrift.Transport = new Thrift.Transport("/service"); const protocol: Thrift.Protocol = new Thrift.Protocol(transport); const client: ThriftTest.ThriftTestClient = new ThriftTest.ThriftTestClient(protocol); const int64_2_pow_60: typeof Int64 = new Int64('1000000000000000'); const int64_minus_2_pow_60: typeof Int64 = new Int64('f000000000000000'); // Work around for old API used by QUnitAdapter of jsTestDriver if (typeof QUnit.log == 'function') { // When using real QUnit (fron PhantomJS) log failures to console QUnit.log(function(details) { if (!details.result) { console.log('======== FAIL ========'); console.log('TestName: ' + details.name); if (details.message) console.log(details.message); console.log('Expected: ' + JSONInt64.stringify(details.expected)); console.log('Actual : ' + JSONInt64.stringify(details.actual)); console.log('======================'); } }); } // all Languages in UTF-8 const stringTest: string = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; function checkRecursively(assert, map1: Object, map2: Object): void { if (typeof map1 !== 'function' && typeof map2 !== 'function') { if (!map1 || typeof map1 !== 'object') { assert.equal(map1, map2); } else { for (let key in map1) { checkRecursively(assert, map1[key], map2[key]); } } } } QUnit.module('Base Types'); QUnit.test('Void', function(assert) { assert.equal(client.testVoid(), undefined); }); QUnit.test('Binary (String)', function(assert) { let binary: string = ''; for (let v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } assert.equal(client.testBinary(binary), binary); }); QUnit.test('Binary (Uint8Array)', function(assert) { let binary: string = ''; for (let v = 255; v >= 0; --v) { binary += String.fromCharCode(v); } const arr: Uint8Array = new Uint8Array(binary.length); for (let i = 0; i < binary.length; ++i) { arr[i] = binary[i].charCodeAt(0); } const hexEncodedString = Array.from(arr, function(byte) { return String.fromCharCode(byte); }).join('') assert.equal(client.testBinary(hexEncodedString), binary); }); QUnit.test('String', function(assert) { assert.equal(client.testString(''), ''); assert.equal(client.testString(stringTest), stringTest); const specialCharacters: string = 'quote: \" backslash:' + ' forwardslash-escaped: \/ ' + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + ' now-all-of-them-together: "\\\/\b\n\r\t' + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; assert.equal(client.testString(specialCharacters), specialCharacters); }); QUnit.test('Double', function(assert) { assert.equal(client.testDouble(0), 0); assert.equal(client.testDouble(-1), -1); assert.equal(client.testDouble(3.14), 3.14); assert.equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60)); }); QUnit.test('Byte', function(assert) { assert.equal(client.testByte(0), 0); assert.equal(client.testByte(0x01), 0x01); }); QUnit.test('I32', function(assert) { assert.equal(client.testI32(0), 0); assert.equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30)); assert.equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30)); }); QUnit.test('I64', function(assert) { assert.equal(client.testI64(new Int64(0)), 0); let int64_2_pow_60_result: typeof Int64 = client.testI64(int64_2_pow_60); assert.ok(int64_2_pow_60.equals(int64_2_pow_60_result)); let int64_minus_2_pow_60_result: typeof Int64 = client.testI64(int64_minus_2_pow_60); assert.ok(int64_minus_2_pow_60.equals(int64_minus_2_pow_60_result)); }); QUnit.module('Structured Types'); QUnit.test('Struct', function(assert) { const structTestInput: ThriftTest.Xtruct = new ThriftTest.Xtruct(); structTestInput.string_thing = 'worked'; structTestInput.byte_thing = 0x01; structTestInput.i32_thing = Math.pow(2, 30); structTestInput.i64_thing = int64_2_pow_60; const structTestOutput: ThriftTest.Xtruct = client.testStruct(structTestInput); assert.equal(structTestOutput.string_thing, structTestInput.string_thing); assert.equal(structTestOutput.byte_thing, structTestInput.byte_thing); assert.equal(structTestOutput.i32_thing, structTestInput.i32_thing); assert.ok(structTestOutput.i64_thing.equals(structTestInput.i64_thing)); assert.ok(structTestInput.i64_thing.equals(structTestOutput.i64_thing)); assert.equal(JSONInt64.stringify(structTestOutput), JSONInt64.stringify(structTestInput)); }); QUnit.test('Nest', function(assert) { const xtrTestInput: ThriftTest.Xtruct = new ThriftTest.Xtruct(); xtrTestInput.string_thing = 'worked'; xtrTestInput.byte_thing = 0x01; xtrTestInput.i32_thing = Math.pow(2, 30); xtrTestInput.i64_thing = int64_2_pow_60; const nestTestInput: ThriftTest.Xtruct2 = new ThriftTest.Xtruct2(); nestTestInput.byte_thing = 0x02; nestTestInput.struct_thing = xtrTestInput; nestTestInput.i32_thing = Math.pow(2, 15); const nestTestOutput: ThriftTest.Xtruct2 = client.testNest(nestTestInput); assert.equal(nestTestOutput.byte_thing, nestTestInput.byte_thing); assert.equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); assert.equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); assert.equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); assert.ok(nestTestOutput.struct_thing.i64_thing.equals(nestTestInput.struct_thing.i64_thing)); assert.equal(nestTestOutput.i32_thing, nestTestInput.i32_thing); assert.equal(JSONInt64.stringify(nestTestOutput), JSONInt64.stringify(nestTestInput)); }); QUnit.test('Map', function(assert) { const mapTestInput: {[k: number]: number;} = {7: 77, 8: 88, 9: 99}; const mapTestOutput: {[k: number]: number;} = client.testMap(mapTestInput); for (let key in mapTestOutput) { assert.equal(mapTestOutput[key], mapTestInput[key]); } }); QUnit.test('StringMap', function(assert) { const mapTestInput: {[k: string]: string;} = { 'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key', 'longValue': stringTest, stringTest: 'long key' }; const mapTestOutput: {[k: string]: string;} = client.testStringMap(mapTestInput); for (let key in mapTestOutput) { assert.equal(mapTestOutput[key], mapTestInput[key]); } }); QUnit.test('Set', function(assert) { const setTestInput: number[] = [1, 2, 3]; assert.ok(client.testSet(setTestInput), setTestInput); }); QUnit.test('List', function(assert) { const listTestInput: number[] = [1, 2, 3]; assert.ok(client.testList(listTestInput), listTestInput); }); QUnit.test('Enum', function(assert) { assert.equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE); }); QUnit.test('TypeDef', function(assert) { assert.equal(client.testTypedef(new Int64(69)), 69); }); QUnit.module('deeper!'); QUnit.test('MapMap', function(assert) { const mapMapTestExpectedResult: {[K: number]: {[k: number]: number}} = { '4': {'1': 1, '2': 2, '3': 3, '4': 4}, '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1} }; const mapMapTestOutput = client.testMapMap(1); for (let key in mapMapTestOutput) { for (let key2 in mapMapTestOutput[key]) { assert.equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]); } } checkRecursively(assert, mapMapTestOutput, mapMapTestExpectedResult); }); QUnit.module('Exception'); QUnit.test('Xception', function(assert) { assert.expect(2); const done = assert.async(); try { client.testException('Xception'); assert.ok(false); }catch (e) { assert.equal(e.errorCode, 1001); assert.equal(e.message, 'Xception'); done(); } }); QUnit.test('no Exception', function(assert) { assert.expect(1); try { client.testException('no Exception'); assert.ok(true); }catch (e) { assert.ok(false); } }); QUnit.test('TException', function(assert) { //ThriftTest does not list TException as a legal exception so it will // generate an exception on the server that does not propagate back to // the client. This test has been modified to equate to "no exception" assert.expect(1); try { client.testException('TException'); } catch (e) { //assert.ok(false); } assert.ok(true); }); QUnit.module('Insanity'); const crazy: ThriftTest.Insanity = { 'userMap': { '5': new Int64(5), '8': new Int64(8) }, 'xtructs': [{ 'string_thing': 'Goodbye4', 'byte_thing': 4, 'i32_thing': 4, 'i64_thing': new Int64(4) }, { 'string_thing': 'Hello2', 'byte_thing': 2, 'i32_thing': 2, 'i64_thing': new Int64(2) }] }; QUnit.test('testInsanity', function(assert) { const insanity: {[k: number]: (ThriftTest.Insanity | {[k:number]: ThriftTest.Insanity})} = { '1': { '2': crazy, '3': crazy }, '2': { '6': new ThriftTest.Insanity() } }; const res = client.testInsanity(new ThriftTest.Insanity(crazy)); assert.ok(res, JSONInt64.stringify(res)); assert.ok(insanity, JSONInt64.stringify(insanity)); checkRecursively(assert, res, insanity); }); ////////////////////////////////// //Run same tests asynchronously QUnit.module('Async'); QUnit.test('Double', function(assert) { assert.expect(1); const done = assert.async(); client.testDouble(3.14159265, function(result) { assert.equal(result, 3.14159265); done(); }); }); QUnit.test('Byte', function(assert) { assert.expect(1); const done = assert.async(); client.testByte(0x01, function(result) { assert.equal(result, 0x01); done(); }); }); QUnit.test('I32', function(assert) { assert.expect(2); const done = assert.async(2); client.testI32(Math.pow(2, 30), function(result) { assert.equal(result, Math.pow(2, 30)); done(); }); client.testI32(Math.pow(-2, 31), function(result) { assert.equal(result, Math.pow(-2, 31)); done(); }); }); QUnit.test('I64', function(assert) { assert.expect(2); const done = assert.async(2); client.testI64(int64_2_pow_60, function(result) { assert.ok(int64_2_pow_60.equals(result)); done(); }); client.testI64(int64_minus_2_pow_60, function(result) { assert.ok(int64_minus_2_pow_60.equals(result)); done(); }); }); thrift-0.16.0/lib/ts/test/test_handler.js000066400000000000000000000133221420101504100202500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * 'License'); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //This is the server side Node test handler for the standard // Apache Thrift test service. const es6Mode = process.argv.includes('--es6'); const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs'; const ttypes = require(`./${genFolder}/ThriftTest_types`); const TException = require('../../nodejs/lib/thrift').TException; const Int64 = require('node-int64'); exports.ThriftTestHandler = { testVoid: function(result) { console.log('testVoid()'); result(null); }, testString: function(thing, result) { console.log('testString(\'' + thing + '\')'); result(null, thing); }, testByte: function(thing, result) { console.log('testByte(' + thing + ')'); result(null, thing); }, testI32: function(thing, result) { console.log('testI32(' + thing + ')'); result(null, thing); }, testI64: function(thing, result) { console.log('testI64(' + thing + ')'); result(null, thing); }, testDouble: function(thing, result) { console.log('testDouble(' + thing + ')'); result(null, thing); }, testBinary: function(thing, result) { console.log('testBinary(\'' + thing + '\')'); result(null, thing); }, testStruct: function(thing, result) { console.log('testStruct('); console.log(thing); console.log(')'); result(null, thing); }, testNest: function(nest, result) { console.log('testNest('); console.log(nest); console.log(')'); result(null, nest); }, testMap: function(thing, result) { console.log('testMap('); console.log(thing); console.log(')'); result(null, thing); }, testStringMap: function(thing, result) { console.log('testStringMap('); console.log(thing); console.log(')'); result(null, thing); }, testSet: function(thing, result) { console.log('testSet('); console.log(thing); console.log(')'); result(null, thing); }, testList: function(thing, result) { console.log('testList('); console.log(thing); console.log(')'); result(null, thing); }, testEnum: function(thing, result) { console.log('testEnum(' + thing + ')'); result(null, thing); }, testTypedef: function(thing, result) { console.log('testTypedef(' + thing + ')'); result(null, thing); }, testMapMap: function(hello, result) { console.log('testMapMap(' + hello + ')'); const mapmap = []; const pos = []; const neg = []; for (let i = 1; i < 5; i++) { pos[i] = i; neg[-i] = -i; } mapmap[4] = pos; mapmap[-4] = neg; result(null, mapmap); }, testInsanity: function(argument, result) { console.log('testInsanity('); console.log(argument); console.log(')'); const hello = new ttypes.Xtruct(); hello.string_thing = 'Hello2'; hello.byte_thing = 2; hello.i32_thing = 2; hello.i64_thing = new Int64(2); const goodbye = new ttypes.Xtruct(); goodbye.string_thing = 'Goodbye4'; goodbye.byte_thing = 4; goodbye.i32_thing = 4; goodbye.i64_thing = new Int64(4); const crazy = new ttypes.Insanity(); crazy.userMap = []; crazy.userMap[ttypes.Numberz.EIGHT] = 8; crazy.userMap[ttypes.Numberz.FIVE] = 5; crazy.xtructs = [goodbye, hello]; const first_map = []; const second_map = []; first_map[ttypes.Numberz.TWO] = crazy; first_map[ttypes.Numberz.THREE] = crazy; const looney = new ttypes.Insanity(); second_map[ttypes.Numberz.SIX] = looney; const insane = []; insane[1] = first_map; insane[2] = second_map; console.log('insane result:'); console.log(insane); result(null, insane); }, testMulti: function(arg0, arg1, arg2, arg3, arg4, arg5, result) { console.log('testMulti()'); const hello = new ttypes.Xtruct(); hello.string_thing = 'Hello2'; hello.byte_thing = arg0; hello.i32_thing = arg1; hello.i64_thing = arg2; result(null, hello); }, testException: function(arg, result) { console.log('testException(' + arg + ')'); if (arg === 'Xception') { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = arg; result(x); } else if (arg === 'TException') { result(new TException(arg)); } else { result(null); } }, testMultiException: function(arg0, arg1, result) { console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); if (arg0 === ('Xception')) { const x = new ttypes.Xception(); x.errorCode = 1001; x.message = 'This is an Xception'; result(x); } else if (arg0 === ('Xception2')) { const x2 = new ttypes.Xception2(); x2.errorCode = 2002; x2.struct_thing = new ttypes.Xtruct(); x2.struct_thing.string_thing = 'This is an Xception2'; result(x2); } const res = new ttypes.Xtruct(); res.string_thing = arg1; result(null, res); }, testOneway: function(sleepFor, result) { console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!'); } }; //ThriftTestSvcHandler thrift-0.16.0/lib/ts/thrift.d.ts000066400000000000000000000554221420101504100163600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ declare module Thrift { /** * Thrift JavaScript library version. */ var Version: string; /** * Thrift IDL type string to Id mapping. * @property {number} STOP - End of a set of fields. * @property {number} VOID - No value (only legal for return types). * @property {number} BOOL - True/False integer. * @property {number} BYTE - Signed 8 bit integer. * @property {number} I08 - Signed 8 bit integer. * @property {number} DOUBLE - 64 bit IEEE 854 floating point. * @property {number} I16 - Signed 16 bit integer. * @property {number} I32 - Signed 32 bit integer. * @property {number} I64 - Signed 64 bit integer. * @property {number} STRING - Array of bytes representing a string of characters. * @property {number} UTF7 - Array of bytes representing a string of UTF7 encoded characters. * @property {number} STRUCT - A multifield type. * @property {number} MAP - A collection type (map/associative-array/dictionary). * @property {number} SET - A collection type (unordered and without repeated values). * @property {number} LIST - A collection type (unordered). * @property {number} UTF8 - Array of bytes representing a string of UTF8 encoded characters. * @property {number} UTF16 - Array of bytes representing a string of UTF16 encoded characters. */ interface Type { 'STOP': number; 'VOID': number; 'BOOL': number; 'BYTE': number; 'I08': number; 'DOUBLE': number; 'I16': number; 'I32': number; 'I64': number; 'STRING': number; 'UTF7': number; 'STRUCT': number; 'MAP': number; 'SET': number; 'LIST': number; 'UTF8': number; 'UTF16': number; } var Type: Type; /** * Thrift RPC message type string to Id mapping. * @property {number} CALL - RPC call sent from client to server. * @property {number} REPLY - RPC call normal response from server to client. * @property {number} EXCEPTION - RPC call exception response from server to client. * @property {number} ONEWAY - Oneway RPC call from client to server with no response. */ interface MessageType { 'CALL': number; 'REPLY': number; 'EXCEPTION': number; 'ONEWAY': number; } var MessageType: MessageType; /** * Utility function returning the count of an object's own properties. * @param {object} obj - Object to test. * @returns {number} number of object's own properties */ function objectLength(obj: Object): number; /** * Utility function to establish prototype inheritance. * @param {function} constructor - Contstructor function to set as derived. * @param {function} superConstructor - Contstructor function to set as base. * @param {string} [name] - Type name to set as name property in derived prototype. */ function inherits(constructor: Function, superConstructor: Function, name?: string): void; /** * TException is the base class for all Thrift exceptions types. */ class TException implements Error { name: string; message: string; /** * Initializes a Thrift TException instance. * @param {string} message - The TException message (distinct from the Error message). */ constructor(message: string); /** * Returns the message set on the exception. * @returns {string} exception message */ getMessage(): string; } /** * Thrift Application Exception type string to Id mapping. * @property {number} UNKNOWN - Unknown/undefined. * @property {number} UNKNOWN_METHOD - Client attempted to call a method unknown to the server. * @property {number} INVALID_MESSAGE_TYPE - Client passed an unknown/unsupported MessageType. * @property {number} WRONG_METHOD_NAME - Unused. * @property {number} BAD_SEQUENCE_ID - Unused in Thrift RPC, used to flag proprietary sequence number errors. * @property {number} MISSING_RESULT - Raised by a server processor if a handler fails to supply the required return result. * @property {number} INTERNAL_ERROR - Something bad happened. * @property {number} PROTOCOL_ERROR - The protocol layer failed to serialize or deserialize data. * @property {number} INVALID_TRANSFORM - Unused. * @property {number} INVALID_PROTOCOL - The protocol (or version) is not supported. * @property {number} UNSUPPORTED_CLIENT_TYPE - Unused. */ interface TApplicationExceptionType { 'UNKNOWN': number; 'UNKNOWN_METHOD': number; 'INVALID_MESSAGE_TYPE': number; 'WRONG_METHOD_NAME': number; 'BAD_SEQUENCE_ID': number; 'MISSING_RESULT': number; 'INTERNAL_ERROR': number; 'PROTOCOL_ERROR': number; 'INVALID_TRANSFORM': number; 'INVALID_PROTOCOL': number; 'UNSUPPORTED_CLIENT_TYPE': number; } var TApplicationExceptionType: TApplicationExceptionType; /** * TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client. */ class TApplicationException extends TException { message: string; code: number; /** * Initializes a Thrift TApplicationException instance. * @param {string} message - The TApplicationException message (distinct from the Error message). * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code. */ constructor(message: string, code?: number); /** * Read a TApplicationException from the supplied protocol. * @param {object} input - The input protocol to read from. */ read(input: Object): void; /** * Write a TApplicationException to the supplied protocol. * @param {object} output - The output protocol to write to. */ write(output: Object): void; /** * Returns the application exception code set on the exception. * @returns {Thrift.TApplicationExceptionType} exception code */ getCode(): number; } /** * The Apache Thrift Transport layer performs byte level I/O between RPC * clients and servers. The JavaScript Transport object type uses Http[s]/XHR and is * the sole browser based Thrift transport. Target servers must implement the http[s] * transport (see: node.js example server). */ class TXHRTransport { url: string; wpos: number; rpos: number; useCORS: any; send_buf: string; recv_buf: string; /** * If you do not specify a url then you must handle XHR operations on * your own. This type can also be constructed using the Transport alias * for backward compatibility. * @param {string} [url] - The URL to connect to. * @param {object} [options] - Options. */ constructor(url?: string, options?: Object); /** * Gets the browser specific XmlHttpRequest Object. * @returns {object} the browser XHR interface object */ getXmlHttpRequestObject(): Object; /** * Sends the current XRH request if the transport was created with a URL and * the async parameter if false. If the transport was not created with a URL * or the async parameter is True or the URL is an empty string, the current * send buffer is returned. * @param {object} async - If true the current send buffer is returned. * @param {function} callback - Optional async completion callback. * @returns {undefined|string} Nothing or the current send buffer. */ flush(async: any, callback?: Function): string; /** * Creates a jQuery XHR object to be used for a Thrift server call. * @param {object} client - The Thrift Service client object generated by the IDL compiler. * @param {object} postData - The message to send to the server. * @param {function} args - The function to call if the request succeeds. * @param {function} recv_method - The Thrift Service Client receive method for the call. * @returns {object} A new jQuery XHR object. */ jqRequest(client: Object, postData: any, args: Function, recv_method: Function): Object; /** * Sets the buffer to use when receiving server responses. * @param {string} buf - The buffer to receive server responses. */ setRecvBuffer(buf: string): void; /** * Returns true if the transport is open, in browser based JavaScript * this function always returns true. * @returns {boolean} Always True. */ isOpen(): boolean; /** * Opens the transport connection, in browser based JavaScript * this function is a nop. */ open(): void; /** * Closes the transport connection, in browser based JavaScript * this function is a nop. */ close(): void; /** * Returns the specified number of characters from the response * buffer. * @param {number} len - The number of characters to return. * @returns {string} Characters sent by the server. */ read(len: number): string; /** * Returns the entire response buffer. * @returns {string} Characters sent by the server. */ readAll(): string; /** * Sets the send buffer to buf. * @param {string} buf - The buffer to send. */ write(buf: string): void; /** * Returns the send buffer. * @returns {string} The send buffer. */ getSendBuffer(): string; } /** * Old alias of the TXHRTransport for backwards compatibility. */ class Transport extends TXHRTransport { } /** * The Apache Thrift Transport layer performs byte level I/O * between RPC clients and servers. The JavaScript TWebSocketTransport object * uses the WebSocket protocol. Target servers must implement WebSocket. */ class TWebSocketTransport { url: string; //Where to connect socket: any; //The web socket callbacks: Function[]; //Pending callbacks send_pending: any[]; //Buffers/Callback pairs waiting to be sent send_buf: string; //Outbound data, immutable until sent recv_buf: string; //Inbound data rb_wpos: number; //Network write position in receive buffer rb_rpos: number; //Client read position in receive buffer /** * Constructor Function for the WebSocket transport. * @param {string } [url] - The URL to connect to. */ constructor(url: string); __reset(url: string): void; /** * Sends the current WS request and registers callback. The async * parameter is ignored (WS flush is always async) and the callback * function parameter is required. * @param {object} async - Ignored. * @param {function} callback - The client completion callback. * @returns {undefined|string} Nothing (undefined) */ flush(async: any, callback: Function): string; __onOpen(): void; __onClose(): void; __onMessage(): void; __onError(): void; /** * Sets the buffer to use when receiving server responses. * @param {string} buf - The buffer to receive server responses. */ setRecvBuffer(buf: string): void; /** * Returns true if the transport is open * @returns {boolean} */ isOpen(): boolean; /** * Opens the transport connection */ open(): void; /** * Closes the transport connection */ close(): void; /** * Returns the specified number of characters from the response * buffer. * @param {number} len - The number of characters to return. * @returns {string} Characters sent by the server. */ read(len: number): string; /** * Returns the entire response buffer. * @returns {string} Characters sent by the server. */ readAll(): string; /** * Sets the send buffer to buf. * @param {string} buf - The buffer to send. */ write(buf: string): void; /** * Returns the send buffer. * @returns {string} The send buffer. */ getSendBuffer(): string; } /** * Apache Thrift Protocols perform serialization which enables cross * language RPC. The Protocol type is the JavaScript browser implementation * of the Apache Thrift TJSONProtocol. */ class TJSONProtocol { transport: Object; /** * Thrift IDL type Id to string mapping. * The mapping table looks as follows: * Thrift.Type.BOOL -> "tf": True/False integer. * Thrift.Type.BYTE -> "i8": Signed 8 bit integer. * Thrift.Type.I16 -> "i16": Signed 16 bit integer. * Thrift.Type.I32 -> "i32": Signed 32 bit integer. * Thrift.Type.I64 -> "i64": Signed 64 bit integer. * Thrift.Type.DOUBLE -> "dbl": 64 bit IEEE 854 floating point. * Thrift.Type.STRUCT -> "rec": A multifield type. * Thrift.Type.STRING -> "str": Array of bytes representing a string of characters. * Thrift.Type.MAP -> "map": A collection type (map/associative-array/dictionary). * Thrift.Type.LIST -> "lst": A collection type (unordered). * Thrift.Type.SET -> "set": A collection type (unordered and without repeated values). */ Type: { [k: number]: string }; /** * Thrift IDL type string to Id mapping. * The mapping table looks as follows: * "tf" -> Thrift.Type.BOOL * "i8" -> Thrift.Type.BYTE * "i16" -> Thrift.Type.I16 * "i32" -> Thrift.Type.I32 * "i64" -> Thrift.Type.I64 * "dbl" -> Thrift.Type.DOUBLE * "rec" -> Thrift.Type.STRUCT * "str" -> Thrift.Type.STRING * "map" -> Thrift.Type.MAP * "lst" -> Thrift.Type.LIST * "set" -> Thrift.Type.SET */ RType: { [k: string]: number }; /** * The TJSONProtocol version number. */ Version: number; /** * Initializes a Thrift JSON protocol instance. * @param {Thrift.Transport} transport - The transport to serialize to/from. */ constructor(transport: Object); /** * Returns the underlying transport. * @returns {Thrift.Transport} The underlying transport. */ getTransport(): Object; /** * Serializes the beginning of a Thrift RPC message. * @param {string} name - The service method to call. * @param {Thrift.MessageType} messageType - The type of method call. * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). */ writeMessageBegin(name: string, messageType: number, seqid: number): void; /** * Serializes the end of a Thrift RPC message. */ writeMessageEnd(): void; /** * Serializes the beginning of a struct. * @param {string} name - The name of the struct. */ writeStructBegin(name?: string): void; /** * Serializes the end of a struct. */ writeStructEnd(): void; /** * Serializes the beginning of a struct field. * @param {string} name - The name of the field. * @param {Thrift.Protocol.Type} fieldType - The data type of the field. * @param {number} fieldId - The field's unique identifier. */ writeFieldBegin(name: string, fieldType: number, fieldId: number): void; /** * Serializes the end of a field. */ writeFieldEnd(): void; /** * Serializes the end of the set of fields for a struct. */ writeFieldStop(): void; /** * Serializes the beginning of a map collection. * @param {Thrift.Type} keyType - The data type of the key. * @param {Thrift.Type} valType - The data type of the value. * @param {number} [size] - The number of elements in the map (ignored). */ writeMapBegin(keyType: number, valType: number, size?: number): void; /** * Serializes the end of a map. */ writeMapEnd(): void; /** * Serializes the beginning of a list collection. * @param {Thrift.Type} elemType - The data type of the elements. * @param {number} size - The number of elements in the list. */ writeListBegin(elemType: number, size: number): void; /** * Serializes the end of a list. */ writeListEnd(): void; /** * Serializes the beginning of a set collection. * @param {Thrift.Type} elemType - The data type of the elements. * @param {number} size - The number of elements in the list. */ writeSetBegin(elemType: number, size: number): void; /** * Serializes the end of a set. */ writeSetEnd(): void; /** Serializes a boolean */ writeBool(value: boolean): void; /** Serializes a number */ writeByte(i8: number): void; /** Serializes a number */ writeI16(i16: number): void; /** Serializes a number */ writeI32(i32: number): void; /** Serializes a number */ writeI64(i64: number): void; /** Serializes a number */ writeDouble(dbl: number): void; /** Serializes a string */ writeString(str: string): void; /** Serializes a string */ writeBinary(str: string): void; /** @class @name AnonReadMessageBeginReturn @property {string} fname - The name of the service method. @property {Thrift.MessageType} mtype - The type of message call. @property {number} rseqid - The sequence number of the message (0 in Thrift RPC). */ /** * Deserializes the beginning of a message. * @returns {AnonReadMessageBeginReturn} */ readMessageBegin(): { fname: string; mtype: number; rseqid: number }; /** Deserializes the end of a message. */ readMessageEnd(): void; /** * Deserializes the beginning of a struct. * @param {string} [name] - The name of the struct (ignored). * @returns {object} - An object with an empty string fname property. */ readStructBegin(name?: string): { fname: string }; /** Deserializes the end of a struct. */ readStructEnd(): void; /** @class @name AnonReadFieldBeginReturn @property {string} fname - The name of the field (always ''). @property {Thrift.Type} ftype - The data type of the field. @property {number} fid - The unique identifier of the field. */ /** * Deserializes the beginning of a field. * @returns {AnonReadFieldBeginReturn} */ readFieldBegin(): { fname: string; ftype: number; fid: number }; /** Deserializes the end of a field. */ readFieldEnd(): void; /** @class @name AnonReadMapBeginReturn @property {Thrift.Type} ktype - The data type of the key. @property {Thrift.Type} vtype - The data type of the value. @property {number} size - The number of elements in the map. */ /** * Deserializes the beginning of a map. * @returns {AnonReadMapBeginReturn} */ readMapBegin(): { ktype: number; vtype: number; size: number }; /** Deserializes the end of a map. */ readMapEnd(): void; /** @class @name AnonReadColBeginReturn @property {Thrift.Type} etype - The data type of the element. @property {number} size - The number of elements in the collection. */ /** * Deserializes the beginning of a list. * @returns {AnonReadColBeginReturn} */ readListBegin(): { etype: number; size: number }; /** Deserializes the end of a list. */ readListEnd(): void; /** * Deserializes the beginning of a set. * @param {Thrift.Type} elemType - The data type of the elements (ignored). * @param {number} size - The number of elements in the list (ignored). * @returns {AnonReadColBeginReturn} */ readSetBegin(elemType?: number, size?: number): { etype: number; size: number }; /** Deserializes the end of a set. */ readSetEnd(): void; /** Returns an object with a value property set to * False unless the next number in the protocol buffer * is 1, in which case the value property is True. */ readBool(): Object; /** Returns an object with a value property set to the next value found in the protocol buffer. */ readByte(): Object; /** Returns an object with a value property set to the next value found in the protocol buffer. */ readI16(): Object; /** Returns an object with a value property set to the next value found in the protocol buffer. */ readI32(f?: any): Object; /** Returns an object with a value property set to the next value found in the protocol buffer. */ readI64(): Object; /** Returns an object with a value property set to the next value found in the protocol buffer. */ readDouble(): Object; /** Returns an object with a value property set to the next value found in the protocol buffer. */ readString(): Object; /** Returns an object with a value property set to the next value found in the protocol buffer. */ readBinary(): Object; /** * Method to arbitrarily skip over data (not implemented). */ skip(type: number): void; } /** * Old alias of the TXHRTransport for backwards compatibility. */ class Protocol extends TJSONProtocol { } class MultiplexProtocol extends TJSONProtocol { serviceName: string; /** * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol. * @param {string} srvName * @param {Thrift.Transport} trans * @param {any} [strictRead] * @param {any} [strictWrite] */ constructor(srvName: string, trans: Object, strictRead?: any, strictWrite?: any); /** * Override writeMessageBegin method of prototype * Serializes the beginning of a Thrift RPC message. * @param {string} name - The service method to call. * @param {Thrift.MessageType} messageType - The type of method call. * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). */ writeMessageBegin(name: string, type: number, seqid: number): void; } class Multiplexer { seqid: number; /** * Instantiates a multiplexed client for a specific service. * @param {String} serviceName - The transport to serialize to/from. * @param {Thrift.ServiceClient} SCl - The Service Client Class. * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port. */ createClient(serviceName: string, SCl: any, transport: Object): any; } } thrift-0.16.0/lib/ts/tsconfig.json000066400000000000000000000013421420101504100167650ustar00rootroot00000000000000{ "compilerOptions": { "allowJs": false, "alwaysStrict": true, "baseUrl": ".", "declaration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "module": "commonjs", "moduleResolution": "node", "noImplicitThis": true, "noUnusedLocals": true, "preserveConstEnums": true, "removeComments": true, "strictFunctionTypes": true, "strictNullChecks": true, "target": "es6", "paths": { "*": [ "*", "test/", "test/gen-js/*" ] }, }, "exclude": [ "./test/gen-nodejs/", "./test/build/", ] } thrift-0.16.0/lib/xml/000077500000000000000000000000001420101504100144305ustar00rootroot00000000000000thrift-0.16.0/lib/xml/Makefile.am000066400000000000000000000016231420101504100164660ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = if WITH_JAVA # Schema validation test depends on java SUBDIRS += test endif EXTRA_DIST = \ thrift-idl.xsd \ test thrift-0.16.0/lib/xml/test/000077500000000000000000000000001420101504100154075ustar00rootroot00000000000000thrift-0.16.0/lib/xml/test/Makefile.am000066400000000000000000000017121420101504100174440ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # check: $(ANT) $(ANT_FLAGS) test # Make sure this doesn't fail if ant is not configured. clean-local: ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ $$ANT $(ANT_FLAGS) clean thrift-0.16.0/lib/xml/test/build.xml000066400000000000000000000100721420101504100172300ustar00rootroot00000000000000 XML Schema Validation Test Thrift compiler is missing ! thrift-0.16.0/lib/xml/thrift-idl.xsd000066400000000000000000000230111420101504100172130ustar00rootroot00000000000000 thrift-0.16.0/package-lock.json000066400000000000000000003552471420101504100163160ustar00rootroot00000000000000{ "name": "thrift", "version": "0.16.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { "@babel/highlight": "^7.0.0" } }, "@babel/core": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz", "integrity": "sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", "@babel/generator": "^7.8.4", "@babel/helpers": "^7.8.4", "@babel/parser": "^7.8.4", "@babel/template": "^7.8.3", "@babel/traverse": "^7.8.4", "@babel/types": "^7.8.3", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", "json5": "^2.1.0", "lodash": "^4.17.13", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" }, "dependencies": { "@babel/code-frame": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", "dev": true, "requires": { "@babel/highlight": "^7.8.3" } }, "@babel/highlight": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", "dev": true }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "resolve": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" }, "dependencies": { "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true } } }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } } }, "@babel/generator": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", "dev": true, "requires": { "@babel/types": "^7.8.3", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" }, "dependencies": { "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } } }, "@babel/helper-function-name": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.8.3", "@babel/template": "^7.8.3", "@babel/types": "^7.8.3" } }, "@babel/helper-get-function-arity": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", "dev": true, "requires": { "@babel/types": "^7.8.3" } }, "@babel/helper-split-export-declaration": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", "dev": true, "requires": { "@babel/types": "^7.8.3" } }, "@babel/helpers": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", "dev": true, "requires": { "@babel/template": "^7.8.3", "@babel/traverse": "^7.8.4", "@babel/types": "^7.8.3" } }, "@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { "version": "7.15.8", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", "dev": true }, "@babel/template": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", "@babel/parser": "^7.8.3", "@babel/types": "^7.8.3" }, "dependencies": { "@babel/code-frame": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", "dev": true, "requires": { "@babel/highlight": "^7.8.3" } }, "@babel/highlight": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", "dev": true } } }, "@babel/traverse": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", "@babel/generator": "^7.8.4", "@babel/helper-function-name": "^7.8.3", "@babel/helper-split-export-declaration": "^7.8.3", "@babel/parser": "^7.8.4", "@babel/types": "^7.8.3", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" }, "dependencies": { "@babel/code-frame": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", "dev": true, "requires": { "@babel/highlight": "^7.8.3" } }, "@babel/highlight": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", "dev": true }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "@babel/types": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", "dev": true, "requires": { "esutils": "^2.0.2", "lodash": "^4.17.13", "to-fast-properties": "^2.0.0" } }, "@istanbuljs/load-nyc-config": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", "dev": true, "requires": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" }, "dependencies": { "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true } } }, "@istanbuljs/schema": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", "dev": true }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, "@types/node": { "version": "10.12.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.6.tgz", "integrity": "sha512-+ZWB5Ec1iki99xQFzBlivlKxSZQ+fuUKBott8StBOnLN4dWbRHlgdg1XknpW6g0tweniN5DcOqA64CJyOUPSAw==", "dev": true }, "@types/node-int64": { "version": "0.4.29", "resolved": "https://registry.npmjs.org/@types/node-int64/-/node-int64-0.4.29.tgz", "integrity": "sha512-rHXvenLTj/CcsmNAebaBOhxQ2MqEGl3yXZZcZ21XYR+gzGTTcpOy2N4IxpvTCz48loyQNatHvfn6GhIbbZ1R3Q==", "dev": true, "requires": { "@types/node": "*" } }, "@types/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.1.tgz", "integrity": "sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA==", "dev": true }, "acorn": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, "acorn-jsx": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.0.tgz", "integrity": "sha512-XkB50fn0MURDyww9+UYL3c1yLbOBz0ZFvrdYlGB8l+Ije1oSC75qAqrzSPjYQbdnQUzhlUGNKuesryAv0gxZOg==", "dev": true }, "aggregate-error": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", "dev": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "ajv": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" } }, "append-transform": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", "dev": true, "requires": { "default-require-extensions": "^3.0.0" } }, "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" } }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { "array-uniq": "^1.0.1" } }, "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { "safer-buffer": "~2.1.0" } }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, "aws4": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "dev": true, "requires": { "tweetnacl": "^0.14.3" } }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "browser-or-node": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", "integrity": "sha512-sVIA0cysIED0nbmNOm7sZzKfgN1rpFmrqvLZaFWspaBAftfQcezlC81G6j6U2RJf4Lh66zFxrCeOsvkUXIcPWg==" }, "buffer-equals": { "version": "1.0.4", "resolved": "http://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz", "integrity": "sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=", "dev": true }, "caching-transform": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", "dev": true, "requires": { "hasha": "^5.0.0", "make-dir": "^3.0.0", "package-hash": "^4.0.0", "write-file-atomic": "^3.0.0" } }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { "callsites": "^0.2.0" } }, "callsites": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", "dev": true }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, "catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", "dev": true, "requires": { "lodash": "^4.17.15" } }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { "restore-cursor": "^2.0.0" } }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, "cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" }, "dependencies": { "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" } }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { "ansi-regex": "^5.0.0" } } } }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { "color-name": "1.1.3" } }, "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, "commander": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "connect": { "version": "3.6.6", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", "dev": true, "requires": { "debug": "2.6.9", "finalhandler": "1.1.0", "parseurl": "~1.3.2", "utils-merge": "1.0.1" } }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" } }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", "dev": true }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, "default-require-extensions": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", "dev": true, "requires": { "strip-bom": "^4.0.0" } }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { "object-keys": "^1.0.12" } }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", "dev": true }, "del": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { "globby": "^5.0.0", "is-path-cwd": "^1.0.0", "is-path-in-cwd": "^1.0.0", "object-assign": "^4.0.1", "pify": "^2.0.0", "pinkie-promise": "^2.0.0", "rimraf": "^2.2.8" } }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" } }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, "entities": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", "dev": true }, "es-abstract": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", "dev": true, "requires": { "es-to-primitive": "^1.1.1", "function-bind": "^1.1.1", "has": "^1.0.1", "is-callable": "^1.1.3", "is-regex": "^1.0.4" } }, "es-to-primitive": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", "is-symbol": "^1.0.2" } }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "eslint": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz", "integrity": "sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "ajv": "^6.5.3", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^2.1.0", "eslint-scope": "^4.0.0", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", "espree": "^4.0.0", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^2.0.0", "functional-red-black-tree": "^1.0.1", "glob": "^7.1.2", "globals": "^11.7.0", "ignore": "^4.0.6", "imurmurhash": "^0.1.4", "inquirer": "^6.1.0", "is-resolvable": "^1.1.0", "js-yaml": "^3.12.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", "lodash": "^4.17.5", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "path-is-inside": "^1.0.2", "pluralize": "^7.0.0", "progress": "^2.0.0", "regexpp": "^2.0.1", "require-uncached": "^1.0.3", "semver": "^5.5.1", "strip-ansi": "^4.0.0", "strip-json-comments": "^2.0.1", "table": "^5.0.2", "text-table": "^0.2.0" }, "dependencies": { "debug": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "dev": true, "requires": { "ms": "^2.1.1" } }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true } } }, "eslint-config-prettier": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.1.0.tgz", "integrity": "sha512-QYGfmzuc4q4J6XIhlp8vRKdI/fI0tQfQPy1dME3UOLprE+v4ssH/3W9LM2Q7h5qBcy5m0ehCrBDU2YF8q6OY8w==", "dev": true, "requires": { "get-stdin": "^6.0.0" } }, "eslint-plugin-prettier": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.0.tgz", "integrity": "sha512-4g11opzhqq/8+AMmo5Vc2Gn7z9alZ4JqrbZ+D4i8KlSyxeQhZHlmIrY8U9Akf514MoEhogPa87Jgkq87aZ2Ohw==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" } }, "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" } }, "eslint-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" }, "dependencies": { "eslint-visitor-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true } } }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, "espree": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", "dev": true, "requires": { "acorn": "^6.0.2", "acorn-jsx": "^5.0.0", "eslint-visitor-keys": "^1.0.0" } }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { "estraverse": "^4.0.0" } }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" } }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, "external-editor": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", "dev": true, "requires": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, "fast-diff": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { "flat-cache": "^1.2.1", "object-assign": "^4.0.1" } }, "finalhandler": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.1", "escape-html": "~1.0.3", "on-finished": "~2.3.0", "parseurl": "~1.3.2", "statuses": "~1.3.1", "unpipe": "~1.0.0" } }, "find-cache-dir": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.2.0.tgz", "integrity": "sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg==", "dev": true, "requires": { "commondir": "^1.0.1", "make-dir": "^3.0.0", "pkg-dir": "^4.1.0" } }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "flat-cache": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { "circular-json": "^0.3.1", "del": "^2.0.2", "graceful-fs": "^4.1.2", "write": "^0.2.1" } }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, "requires": { "is-callable": "^1.1.3" } }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, "requires": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" }, "dependencies": { "cross-spawn": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } } } }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, "fromentries": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", "dev": true }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, "gensync": { "version": "1.0.0-beta.1", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", "dev": true }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, "get-stdin": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "globals": { "version": "11.8.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", "dev": true }, "globby": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { "array-union": "^1.0.1", "arrify": "^1.0.0", "glob": "^7.0.3", "object-assign": "^4.0.1", "pify": "^2.0.0", "pinkie-promise": "^2.0.0" } }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", "dev": true }, "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" }, "dependencies": { "ajv": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } } } }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, "hasha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", "dev": true, "requires": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" } }, "html-escaper": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==", "dev": true }, "html-validator": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/html-validator/-/html-validator-3.1.3.tgz", "integrity": "sha512-RhjcQIHS/SfYzQ+/JrFWKU6AVve6AuwftAG/cWX3+bpvBK/tGMqbOleKlsAxLrKD84+GSJ1oJGnkyhdVLBGCqg==", "dev": true, "requires": { "request": "2.88.0", "valid-url": "1.0.9" } }, "html-validator-cli": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/html-validator-cli/-/html-validator-cli-4.1.4.tgz", "integrity": "sha512-4vGP107UDhhNHeWA5N8j/nUPlQbtB/W/K2x/P7aElbWMWrOkJA0MRSVFsMFrTPSAAjZWCG9uki2+1cQDzFtVcQ==", "dev": true, "requires": { "html-validator": "3.1.3", "minimist": "1.2.0" }, "dependencies": { "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } } }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "inquirer": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", "dev": true, "requires": { "ansi-escapes": "^3.0.0", "chalk": "^2.0.0", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.0", "figures": "^2.0.0", "lodash": "^4.17.10", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rxjs": "^6.1.0", "string-width": "^2.1.0", "strip-ansi": "^4.0.0", "through": "^2.3.6" } }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", "dev": true }, "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", "dev": true }, "is-path-in-cwd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { "is-path-inside": "^1.0.0" } }, "is-path-inside": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { "path-is-inside": "^1.0.1" } }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { "has": "^1.0.1" } }, "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "dev": true, "requires": { "has-symbols": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, "istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", "dev": true }, "istanbul-lib-hook": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, "requires": { "append-transform": "^2.0.0" } }, "istanbul-lib-instrument": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", "dev": true, "requires": { "@babel/core": "^7.7.5", "@babel/parser": "^7.7.5", "@babel/template": "^7.7.4", "@babel/traverse": "^7.7.4", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.0.0", "semver": "^6.3.0" }, "dependencies": { "@babel/parser": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", "dev": true }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "istanbul-lib-processinfo": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", "dev": true, "requires": { "archy": "^1.0.0", "cross-spawn": "^7.0.0", "istanbul-lib-coverage": "^3.0.0-alpha.1", "make-dir": "^3.0.0", "p-map": "^3.0.0", "rimraf": "^3.0.0", "uuid": "^3.3.3" }, "dependencies": { "cross-spawn": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } } } }, "istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "requires": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", "supports-color": "^7.1.0" }, "dependencies": { "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { "has-flag": "^4.0.0" } } } }, "istanbul-lib-source-maps": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", "dev": true, "requires": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, "dependencies": { "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "istanbul-reports": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.0.tgz", "integrity": "sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==", "dev": true, "requires": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" } }, "js2xmlparser": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", "dev": true, "requires": { "xmlcreate": "^2.0.3" } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, "jsdoc": { "version": "3.6.7", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", "dev": true, "requires": { "@babel/parser": "^7.9.4", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.1", "klaw": "^3.0.0", "markdown-it": "^10.0.0", "markdown-it-anchor": "^5.2.7", "marked": "^2.0.3", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", "underscore": "~1.13.1" }, "dependencies": { "escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true } } }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "json-int64": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-int64/-/json-int64-1.0.2.tgz", "integrity": "sha512-uGrIXtRehbksM17S2lJRLPljufK52KL2ewbJi0xgcRPONoRLXa4yAUIKAUxF69dbnqIoBu33fB28MAWSxupB8Q==", "dev": true, "requires": { "node-int64": "0.4.0" } }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, "json5": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" } }, "klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", "dev": true, "requires": { "graceful-fs": "^4.1.9" } }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" } }, "linkify-it": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "dev": true, "requires": { "uc.micro": "^1.0.1" } }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { "p-locate": "^4.1.0" } }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, "make-dir": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", "dev": true, "requires": { "semver": "^6.0.0" }, "dependencies": { "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "dev": true, "requires": { "argparse": "^1.0.7", "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" } }, "markdown-it-anchor": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", "dev": true }, "marked": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", "dev": true }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", "dev": true }, "mime-db": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", "dev": true }, "mime-types": { "version": "2.1.21", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "dev": true, "requires": { "mime-db": "~1.37.0" } }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { "minimist": "^1.2.5" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-gyp-build": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz", "integrity": "sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==", "dev": true }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", "dev": true, "requires": { "process-on-spawn": "^1.0.0" } }, "nyc": { "version": "15.0.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.0.tgz", "integrity": "sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg==", "dev": true, "requires": { "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", "caching-transform": "^4.0.0", "convert-source-map": "^1.7.0", "decamelize": "^1.2.0", "find-cache-dir": "^3.2.0", "find-up": "^4.1.0", "foreground-child": "^2.0.0", "glob": "^7.1.6", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-hook": "^3.0.0", "istanbul-lib-instrument": "^4.0.0", "istanbul-lib-processinfo": "^2.0.2", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.0", "js-yaml": "^3.13.1", "make-dir": "^3.0.0", "node-preload": "^0.2.0", "p-map": "^3.0.0", "process-on-spawn": "^1.0.0", "resolve-from": "^5.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "spawn-wrap": "^2.0.0", "test-exclude": "^6.0.0", "uuid": "^3.3.3", "yargs": "^15.0.2" }, "dependencies": { "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true } } }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object-inspect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", "dev": true }, "object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", "dev": true }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "dev": true, "requires": { "ee-first": "1.1.1" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" } }, "onetime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { "mimic-fn": "^1.0.0" } }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", "wordwrap": "~1.0.0" } }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, "p-limit": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { "p-limit": "^2.2.0" } }, "p-map": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", "dev": true, "requires": { "aggregate-error": "^3.0.0" } }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "package-hash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", "dev": true, "requires": { "graceful-fs": "^4.1.15", "hasha": "^5.0.0", "lodash.flattendeep": "^4.4.0", "release-zalgo": "^1.0.0" }, "dependencies": { "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true } } }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", "dev": true }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, "pify": { "version": "2.3.0", "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { "pinkie": "^2.0.0" } }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { "find-up": "^4.0.0" } }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, "prettier": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz", "integrity": "sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==", "dev": true }, "prettier-linter-helpers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { "fast-diff": "^1.1.2" } }, "process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", "dev": true, "requires": { "fromentries": "^1.2.0" } }, "progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", "dev": true }, "psl": { "version": "1.1.31", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", "dev": true }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, "release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", "dev": true, "requires": { "es6-error": "^4.0.1" } }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, "require-uncached": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { "caller-path": "^0.1.0", "resolve-from": "^1.0.0" } }, "requizzle": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", "dev": true, "requires": { "lodash": "^4.17.14" } }, "resolve-from": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", "dev": true }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" } }, "resumer": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", "dev": true, "requires": { "through": "~2.3.4" } }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { "glob": "^7.0.5" } }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { "is-promise": "^2.1.0" } }, "rxjs": { "version": "6.3.3", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", "dev": true, "requires": { "tslib": "^1.9.0" } }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0" } }, "spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", "dev": true, "requires": { "foreground-child": "^2.0.0", "is-windows": "^1.0.2", "make-dir": "^3.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "which": "^2.0.1" }, "dependencies": { "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } } } }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" } }, "statuses": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", "dev": true }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" } }, "string.prototype.trim": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.0", "function-bind": "^1.0.2" } }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "^3.0.0" } }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } }, "table": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz", "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==", "dev": true, "requires": { "ajv": "^6.5.3", "lodash": "^4.17.10", "slice-ansi": "1.0.0", "string-width": "^2.1.1" } }, "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", "dev": true }, "tape": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz", "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==", "dev": true, "requires": { "deep-equal": "~1.0.1", "defined": "~1.0.0", "for-each": "~0.3.3", "function-bind": "~1.1.1", "glob": "~7.1.2", "has": "~1.0.3", "inherits": "~2.0.3", "minimist": "~1.2.0", "object-inspect": "~1.6.0", "resolve": "~1.7.1", "resumer": "~0.0.0", "string.prototype.trim": "~1.1.2", "through": "~2.3.8" }, "dependencies": { "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "resolve": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", "dev": true, "requires": { "path-parse": "^1.0.5" }, "dependencies": { "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true } } } } }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "requires": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" }, "dependencies": { "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } } } }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "through": { "version": "2.3.8", "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" } }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" }, "dependencies": { "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true } } }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", "dev": true }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { "prelude-ls": "~1.1.2" } }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, "requires": { "is-typedarray": "^1.0.0" } }, "typescript": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz", "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==", "dev": true }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, "underscore": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { "punycode": "^2.1.0" } }, "utf-8-validate": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.2.tgz", "integrity": "sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw==", "dev": true, "requires": { "node-gyp-build": "~3.7.0" } }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true }, "valid-url": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=", "dev": true }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "dependencies": { "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" } }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { "ansi-regex": "^5.0.0" } } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { "mkdirp": "^0.5.1" } }, "write-file-atomic": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.1.tgz", "integrity": "sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw==", "dev": true, "requires": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "ws": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", "requires": { "async-limiter": "~1.0.0" } }, "xmlcreate": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", "dev": true }, "y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "requires": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" }, "dependencies": { "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" } }, "yargs-parser": { "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } } } } } } thrift-0.16.0/package.json000066400000000000000000000035471420101504100153610ustar00rootroot00000000000000{ "name": "thrift", "description": "node.js bindings for the Apache Thrift RPC system", "homepage": "http://thrift.apache.org/", "repository": { "type": "git", "url": "https://github.com/apache/thrift.git" }, "version": "0.16.0", "author": { "name": "Apache Thrift Developers", "email": "dev@thrift.apache.org", "url": "http://thrift.apache.org" }, "license": "Apache-2.0", "licenses": [ { "type": "Apache-2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0" } ], "bugs": { "mail": "dev@thrift.apache.org", "url": "https://issues.apache.org/jira/browse/THRIFT" }, "files": [ "lib/nodejs/lib/thrift", "lib/nodejs/README.md" ], "directories": { "lib": "./lib/nodejs/lib/thrift" }, "browser": "./lib/nodejs/lib/thrift/browser.js", "main": "./lib/nodejs/lib/thrift", "engines": { "node": ">= 10.18.0" }, "dependencies": { "browser-or-node": "^1.2.1", "isomorphic-ws": "^4.0.1", "node-int64": "^0.4.0", "q": "^1.5.0", "ws": "^5.2.3" }, "devDependencies": { "@types/node": "^10.12.6", "@types/node-int64": "^0.4.29", "@types/q": "^1.5.1", "buffer-equals": "^1.0.4", "commander": "^2.14.1", "connect": "^3.6.6", "eslint": "^5.7.0", "eslint-config-prettier": "^3.1.0", "eslint-plugin-prettier": "^3.0.0", "html-validator-cli": "^4.1.4", "jsdoc": "^3.6.7", "json-int64": "^1.0.2", "nyc": "^15.0.0", "prettier": "^1.14.3", "tape": "^4.9.0", "typescript": "^3.1.6", "utf-8-validate": "^5.0.0" }, "scripts": { "cover": "lib/nodejs/test/testAll.sh COVER", "test": "lib/nodejs/test/testAll.sh", "test-ts": "lib/nodets/test/testAll.sh", "prettier": "prettier --write '**/*.js'", "lint": "eslint lib/nodejs/. --ext .js", "lint-tests": "eslint lib/nodejs/test/. --ext .js" } } thrift-0.16.0/phpcs.xml.dist000066400000000000000000000013551420101504100156670ustar00rootroot00000000000000 The coding standard for thrift. lib/php/lib lib/php/test lib/php/test/packages/* lib/php/test/* lib/php/test/* thrift-0.16.0/rust-toolchain000066400000000000000000000000071420101504100157550ustar00rootroot000000000000001.40.0 thrift-0.16.0/sonar-project.properties000077500000000000000000000103701420101504100177720ustar00rootroot00000000000000# Apache Thrift © The Apache Software Foundation # http://www.apache.org/licenses/LICENSE-2.0 # SPDX-License-Identifier: Apache-2.0 # File: sonar-project.properties # Apache Thrift configuration file for Sonar https://analysis.apache.org/ # Sonar is an open platform to manage code quality http://www.sonarsource.org/ # required metadata sonar.projectKey=org.apache.thrift sonar.projectName=Apache Thrift sonar.projectDescription= The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that work efficiently and seamlessly between all major languages. # Apache Thrift Version sonar.projectVersion=0.16.0 # use this to set another version string # $ sonar-runner -D sonar.projectVersion=`git rev-parse HEAD` # set projectDate in combination with projectVersion for imports of old releases #sonar.projectDate=yyyy-MM-dd # TODO add website (sonar.projectUrl does not work) #sonar.XXXX=http//thrift.apache.org # Some properties that will be inherited by the modules sonar.sources=src sonar.language=java,js,c++,py,c sonar.sourceEncoding=UTF-8 # scm sonar.scm.url=scm:git:https://github.com/apache/thrift.git # cppcheck -q --error-exitcode=0 --xml . 2> cppcheck-result.xml sonar.cxx.cppcheck.reportPath=cppcheck-result.xml # List of the module identifiers sonar.modules=module1,module3,module4,module5,module6,module7,module8,module9,module10,module11,module12 # we need sonar-runner 2.1 for this, see http://jira.codehaus.org/browse/SONARPLUGINS-2421 #sonar.modules=module2 # delph plugin is broken #sonar.modules=module13 # phpunit plugin is broken #sonar.modules=module14 module1.sonar.projectName=Apache Thrift - Java Library module1.sonar.projectBaseDir=lib/java module1.sonar.sources=src module1.sonar.tests=test module1.sonar.binaries=build/libs/libthrift-0.16.0.jar module1.sonar.libraries=build/deps/*.jar module1.sonar.language=java module2.sonar.projectName=Apache Thrift - Java Tutorial module2.sonar.projectBaseDir=. module2.sonar.sources=tutorial/java/src, tutorial/java/gen-java module2.sonar.binaries=tutorial/java/tutorial.jar module2.sonar.libraries=lib/java/build/deps/*.jar,lib/java/build/libs/libthrift-0.16.0.jar module2.sonar.language=java module3.sonar.projectName=Apache Thrift - JavaScript Library module3.sonar.projectBaseDir=lib/js module3.sonar.sources=. module3.sonar.exclusions=test/**/* module3.sonar.language=js module4.sonar.projectName=Apache Thrift - JavaScript Tutorial module4.sonar.projectBaseDir=tutorial/js module4.sonar.sources=. module4.sonar.language=web module5.sonar.projectName=Apache Thrift - C++ Library module5.sonar.projectBaseDir=lib/cpp module5.sonar.sources=src module5.sonar.tests=test module5.sonar.language=c++ module6.sonar.projectName=Apache Thrift - C++ Tutorial module6.sonar.projectBaseDir=tutorial/cpp module6.sonar.sources=. module6.sonar.exclusions=gen-cpp/**/* module6.sonar.language=c++ module7.sonar.projectName=Apache Thrift - C++ Cross Language Test module7.sonar.projectBaseDir=test/cpp module7.sonar.sources=src module7.sonar.language=c++ module8.sonar.projectName=Apache Thrift - Compiler module8.sonar.projectBaseDir=compiler/cpp module8.sonar.sources=src module8.sonar.language=c++ module9.sonar.projectName=Apache Thrift - Python Library module9.sonar.projectBaseDir=lib/py module9.sonar.sources=src module9.sonar.language=py module10.sonar.projectName=Apache Thrift - Python Tutorial module10.sonar.projectBaseDir=tutorial/py module10.sonar.sources=. module10.sonar.exclusions=gen-py/**/* module10.sonar.language=py module11.sonar.projectName=Apache Thrift - Python Cross Language Test module11.sonar.projectBaseDir=test/py module11.sonar.sources=. module11.sonar.exclusions=gen-*/**/* module11.sonar.language=py module12.sonar.projectName=Apache Thrift - c_glib Library module12.sonar.projectBaseDir=lib/c_glib module12.sonar.sources=src module12.sonar.language=c module13.sonar.projectName=Apache Thrift - Delphi Library module13.sonar.projectBaseDir=lib/delphi module13.sonar.sources=src module13.sonar.tests=test module13.sonar.language=delph module14.sonar.projectName=Apache Thrift - PHP Library module14.sonar.projectBaseDir=lib/php module14.sonar.sources=src module14.sonar.language=php # TODO add some more languages here thrift-0.16.0/test/000077500000000000000000000000001420101504100140415ustar00rootroot00000000000000thrift-0.16.0/test/AnnotationTest.thrift000066400000000000000000000041341420101504100202370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ typedef list ( cpp.template = "std::list" ) int_linked_list struct foo { 1: i32 bar ( presence = "required" ); 2: i32 baz ( presence = "manual", cpp.use_pointer = "", ); 3: i32 qux; 4: i32 bop; } ( cpp.type = "DenseFoo", python.type = "DenseFoo", java.final = "", annotation.without.value, ) exception foo_error { 1: i32 error_code ( foo="bar" ) 2: string error_msg } (foo = "bar") typedef string ( unicode.encoding = "UTF-16" ) non_latin_string (foo="bar") typedef list< double ( cpp.fixed_point = "16" ) > tiny_float_list enum weekdays { SUNDAY ( weekend = "yes" ), MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY ( weekend = "yes" ) } (foo.bar="baz") /* Note that annotations on senum values are not supported. */ senum seasons { "Spring", "Summer", "Fall", "Winter" } ( foo = "bar" ) struct ostr_default { 1: i32 bar; } struct ostr_custom { 1: i32 bar; } (cpp.customostream) service foo_service { void foo() ( foo = "bar" ) } (a.b="c") service deprecate_everything { void Foo( ) ( deprecated = "This method has neither 'x' nor \"y\"" ) void Bar( ) ( deprecated = "Fails to deliver 中文 колбаса" ) void Baz( ) ( deprecated = "Need this to work with tabs (\t) or Umlauts (äöüÄÖÜß) too" ) void Deprecated() ( deprecated ) // no comment } thrift-0.16.0/test/BrokenConstants.thrift000066400000000000000000000016431420101504100204040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const i64 myint = 68719476736 const i64 broken = 9876543210987654321 // A little over 2^63 enum foo { bar = 68719476736 } thrift-0.16.0/test/ConstantsDemo.thrift000066400000000000000000000040071420101504100200450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace cpp yozone namespace erl consts_ struct thing { 1: i32 hello, 2: i32 goodbye } enum enumconstants { ONE = 1, TWO = 2 } // struct thing2 { // /** standard docstring */ // 1: enumconstants val = TWO // } typedef i32 myIntType const myIntType myInt = 3 //const map GEN_ENUM_NAMES = {ONE : "HOWDY", TWO: "PARTNER"} const i32 hex_const = 0x0001F const i32 negative_hex_constant = -0x0001F const i32 GEN_ME = -3523553 const double GEn_DUB = 325.532 const double GEn_DU = 085.2355 const string GEN_STRING = "asldkjasfd" const double e10 = 1e10 // fails with 0.9.3 and earlier const double e11 = -1e10 const map GEN_MAP = { 35532 : 233, 43523 : 853 } const list GEN_LIST = [ 235235, 23598352, 3253523 ] const map> GEN_MAPMAP = { 235 : { 532 : 53255, 235:235}} const map GEN_MAP2 = { "hello" : 233, "lkj98d" : 853, 'lkjsdf' : 098325 } const thing GEN_THING = { 'hello' : 325, 'goodbye' : 325352 } const map GEN_WHAT = { 35 : { 'hello' : 325, 'goodbye' : 325352 } } const set GEN_SET = [ 235, 235, 53235 ] exception Blah { 1: i32 bing } exception Gak {} service yowza { void blingity(), i32 blangity() throws (1: Blah hoot ) } thrift-0.16.0/test/DebugProtoTest.thrift000066400000000000000000000241311420101504100201760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace c_glib TTest namespace cpp thrift.test.debug namespace java thrift.test namespace rb thrift.test struct Doubles { 1: double nan, 2: double inf, 3: double neginf, 4: double repeating, 5: double big, 6: double tiny, 7: double zero, 8: double negzero, } struct OneOfEach { 1: bool im_true, 2: bool im_false, 3: i8 a_bite = 0x7f, 4: i16 integer16 = 0x7fff, 5: i32 integer32, 6: i64 integer64 = 10000000000, 7: double double_precision, 8: string some_characters, 9: string zomg_unicode, 10: bool what_who, 11: binary base64, 12: list byte_list = [1, 2, 3], 13: list i16_list = [1,2,3], 14: list i64_list = [1,2,3] } struct Bonk { 1: i32 type, 2: string message, } struct Nesting { 1: Bonk my_bonk, 2: OneOfEach my_ooe, } struct HolyMoley { 1: list big, 2: set (python.immutable = "")> contain, 3: map> bonks, } struct Backwards { 2: i32 first_tag2, 1: i32 second_tag1, } struct Empty { } ( python.immutable = "", ) struct Wrapper { 1: Empty foo } ( python.immutable = "", ) struct RandomStuff { 1: i32 a, 2: i32 b, 3: i32 c, 4: i32 d, 5: list myintlist, 6: map maps, 7: i64 bigint, 8: double triple, } struct Base64 { 1: i32 a, 2: binary b1, 3: binary b2, 4: binary b3, 5: binary b4, 6: binary b5, 7: binary b6, } struct CompactProtoTestStruct { // primitive fields 1: i8 a_byte; 2: i16 a_i16; 3: i32 a_i32; 4: i64 a_i64; 5: double a_double; 6: string a_string; 7: binary a_binary; 8: bool true_field; 9: bool false_field; 10: Empty empty_struct_field; // primitives in lists 11: list byte_list; 12: list i16_list; 13: list i32_list; 14: list i64_list; 15: list double_list; 16: list string_list; 17: list binary_list; 18: list boolean_list; 19: list struct_list; // primitives in sets 20: set byte_set; 21: set i16_set; 22: set i32_set; 23: set i64_set; 24: set double_set; 25: set string_set; 26: set binary_set; 27: set boolean_set; 28: set struct_set; // maps // primitives as keys 29: map byte_byte_map; 30: map i16_byte_map; 31: map i32_byte_map; 32: map i64_byte_map; 33: map double_byte_map; 34: map string_byte_map; 35: map binary_byte_map; 36: map boolean_byte_map; // primitives as values 37: map byte_i16_map; 38: map byte_i32_map; 39: map byte_i64_map; 40: map byte_double_map; 41: map byte_string_map; 42: map byte_binary_map; 43: map byte_boolean_map; // collections as keys 44: map (python.immutable = ""), i8> list_byte_map; 45: map (python.immutable = ""), i8> set_byte_map; 46: map (python.immutable = ""), i8> map_byte_map; // collections as values 47: map> byte_map_map; 48: map> byte_set_map; 49: map> byte_list_map; // large field IDs 500 : i64 field500; 5000 : i64 field5000; 20000 : i64 field20000; } // To be used to test the serialization of an empty map struct SingleMapTestStruct { 1: required map i32_map; } const CompactProtoTestStruct COMPACT_TEST = { 'a_byte' : 127, 'a_i16' : 32000, 'a_i32' : 1000000000, 'a_i64' : 0xffffffffff, 'a_double' : 5.6789, 'a_string' : "my string", //'a_binary,' 'true_field' : 1, 'false_field' : 0, 'empty_struct_field' : {}, 'byte_list' : [-127, -1, 0, 1, 127], 'i16_list' : [-1, 0, 1, 0x7fff], 'i32_list' : [-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff], 'i64_list' : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff], 'double_list' : [0.1, 0.2, 0.3], 'string_list' : ["first", "second", "third"], //'binary_list,' 'boolean_list' : [1, 1, 1, 0, 0, 0], 'struct_list' : [{}, {}], 'byte_set' : [-127, -1, 0, 1, 127], 'i16_set' : [-1, 0, 1, 0x7fff], 'i32_set' : [1, 2, 3], 'i64_set' : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff], 'double_set' : [0.1, 0.2, 0.3], 'string_set' : ["first", "second", "third"], //'binary_set,' 'boolean_set' : [1, 0], 'struct_set' : [{}], 'byte_byte_map' : {1 : 2}, 'i16_byte_map' : {1 : 1, -1 : 1, 0x7fff : 1}, 'i32_byte_map' : {1 : 1, -1 : 1, 0x7fffffff : 1}, 'i64_byte_map' : {0 : 1, 1 : 1, -1 : 1, 0x7fffffffffffffff : 1}, 'double_byte_map' : {-1.1 : 1, 1.1 : 1}, 'string_byte_map' : {"first" : 1, "second" : 2, "third" : 3, "" : 0}, //'binary_byte_map,' 'boolean_byte_map' : {1 : 1, 0 : 0}, 'byte_i16_map' : {1 : 1, 2 : -1, 3 : 0x7fff}, 'byte_i32_map' : {1 : 1, 2 : -1, 3 : 0x7fffffff}, 'byte_i64_map' : {1 : 1, 2 : -1, 3 : 0x7fffffffffffffff}, 'byte_double_map' : {1 : 0.1, 2 : -0.1, 3 : 1000000.1}, 'byte_string_map' : {1 : "", 2 : "blah", 3 : "loooooooooooooong string"}, //'byte_binary_map,' 'byte_boolean_map' : {1 : 1, 2 : 0}, 'list_byte_map' : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0}, 'set_byte_map' : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0}, 'map_byte_map' : {{1 : 1} : 1, {2 : 2} : 2, {} : 0}, 'byte_map_map' : {0 : {}, 1 : {1 : 1}, 2 : {1 : 1, 2 : 2}}, 'byte_set_map' : {0 : [], 1 : [1], 2 : [1, 2]}, 'byte_list_map' : {0 : [], 1 : [1], 2 : [1, 2]}, 'field500' : 500, 'field5000' : 5000, 'field20000' : 20000, } const i32 MYCONST = 2 exception ExceptionWithAMap { 1: string blah; 2: map map_field; } exception MutableException { 1: string msg; } (python.immutable = "false") exception ExceptionWithoutFields {} service ServiceForExceptionWithAMap { void methodThatThrowsAnException() throws (1: ExceptionWithAMap xwamap); } service Srv { i32 Janky(1: i32 arg); // return type only methods void voidMethod(); i32 primitiveMethod(); CompactProtoTestStruct structMethod(); void methodWithDefaultArgs(1: i32 something = MYCONST); oneway void onewayMethod(); bool declaredExceptionMethod(1: bool shouldThrow) throws (1: ExceptionWithAMap xwamap); } service Inherited extends Srv { i32 identity(1: i32 arg) } service EmptyService {} // The only purpose of this thing is to increase the size of the generated code // so that ZlibTest has more highly compressible data to play with. struct BlowUp { 1: map(python.immutable = ""),set (python.immutable = "")>> b1; 2: map(python.immutable = ""),set (python.immutable = "")>> b2; 3: map(python.immutable = ""),set (python.immutable = "")>> b3; 4: map(python.immutable = ""),set (python.immutable = "")>> b4; } struct ReverseOrderStruct { 4: string first; 3: i16 second; 2: i32 third; 1: i64 fourth; } service ReverseOrderService { void myMethod(4: string first, 3: i16 second, 2: i32 third, 1: i64 fourth); } enum SomeEnum { ONE = 1 TWO = 2 } /** This is a docstring on a constant! */ const SomeEnum MY_SOME_ENUM = SomeEnum.ONE const SomeEnum MY_SOME_ENUM_1 = 1 /*const SomeEnum MY_SOME_ENUM_2 = 7*/ const map MY_ENUM_MAP = { SomeEnum.ONE : SomeEnum.TWO } struct StructWithSomeEnum { 1: SomeEnum blah; } const map EXTRA_CRAZY_MAP = { SomeEnum.ONE : {"blah" : SomeEnum.TWO} } union TestUnion { /** * A doc string */ 1: string string_field; 2: i32 i32_field; 3: OneOfEach struct_field; 4: list struct_list; 5: i32 other_i32_field; 6: SomeEnum enum_field; 7: set i32_set; 8: map i32_map; } union TestUnionMinusStringField { 2: i32 i32_field; 3: OneOfEach struct_field; 4: list struct_list; 5: i32 other_i32_field; 6: SomeEnum enum_field; 7: set i32_set; 8: map i32_map; } union ComparableUnion { 1: string string_field; 2: binary binary_field; } struct StructWithAUnion { 1: TestUnion test_union; } struct PrimitiveThenStruct { 1: i32 blah; 2: i32 blah2; 3: Backwards bw; } typedef map SomeMap struct StructWithASomemap { 1: required SomeMap somemap_field; } struct BigFieldIdStruct { 1: string field1; 45: string field2; } struct BreaksRubyCompactProtocol { 1: string field1; 2: BigFieldIdStruct field2; 3: i32 field3; } struct TupleProtocolTestStruct { optional i32 field1; optional i32 field2; optional i32 field3; optional i32 field4; optional i32 field5; optional i32 field6; optional i32 field7; optional i32 field8; optional i32 field9; optional i32 field10; optional i32 field11; optional i32 field12; } struct ListDoublePerf { 1: list field; } thrift-0.16.0/test/DenseLinkingTest.thrift000066400000000000000000000044361420101504100205040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* ../compiler/cpp/thrift -gen cpp:dense DebugProtoTest.thrift ../compiler/cpp/thrift -gen cpp:dense DenseLinkingTest.thrift g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \ DebugProtoTest.cpp gen-cpp/DebugProtoTest_types.cpp \ gen-cpp/DenseLinkingTest_types.cpp \ ../lib/cpp/.libs/libthrift.a -o DebugProtoTest ./DebugProtoTest */ /* The idea of this test is that everything is structurally identical to DebugProtoTest. If I messed up the naming of the reflection local typespecs, then compiling this should give errors because of doubly defined symbols. */ namespace cpp thrift.test namespace java thrift.test struct OneOfEachZZ { 1: bool im_true, 2: bool im_false, 3: byte a_bite, 4: i16 integer16, 5: i32 integer32, 6: i64 integer64, 7: double double_precision, 8: string some_characters, 9: string zomg_unicode, 10: bool what_who, } struct BonkZZ { 1: i32 type, 2: string message, } struct NestingZZ { 1: BonkZZ my_bonk, 2: OneOfEachZZ my_ooe, } struct HolyMoleyZZ { 1: list big, 2: set> contain, 3: map> bonks, } struct BackwardsZZ { 2: i32 first_tag2, 1: i32 second_tag1, } struct EmptyZZ { } struct WrapperZZ { 1: EmptyZZ foo } struct RandomStuffZZ { 1: i32 a, 2: i32 b, 3: i32 c, 4: i32 d, 5: list myintlist, 6: map maps, 7: i64 bigint, 8: double triple, } service Srv { i32 Janky(1: i32 arg) } service UnderscoreSrv { i64 some_rpc_call(1: string message) } thrift-0.16.0/test/DocTest.thrift000066400000000000000000000141671420101504100166410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * Program doctext. * * Seriously, this is the documentation for this whole program. */ namespace java thrift.test namespace cpp thrift.test // C++ comment /* c style comment */ # the new unix comment /** Some doc text goes here. Wow I am [nesting these] (no more nesting.) */ enum Numberz { /** This is how to document a parameter */ ONE = 1, /** And this is a doc for a parameter that has no specific value assigned */ TWO, THREE, FIVE = 5, SIX, EIGHT = 8 } /** This is how you would do a typedef doc */ typedef i64 UserId /** And this is where you would document a struct */ struct Xtruct { /** And the members of a struct */ 1: string string_thing /** doct text goes before a comma */ 4: i8 byte_thing, 9: i32 i32_thing, 11: i64 i64_thing } /** * You can document constants now too. Yeehaw! */ const i32 INT32CONSTANT = 9853 const i16 INT16CONSTANT = 1616 /** Everyone get in on the docu-action! */ const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} struct Xtruct2 { 1: i8 byte_thing, 2: Xtruct struct_thing, 3: i32 i32_thing } /** Struct insanity */ struct Insanity { /** This is doc for field 1 */ 1: map userMap, /** And this is doc for field 2 */ 2: list xtructs } exception Xception { 1: i32 errorCode, 2: string message } exception Xception2 { 1: i32 errorCode, 2: Xtruct struct_thing } /* C1 */ /** Doc */ /* C2 */ /* C3 */ struct EmptyStruct {} struct OneField { 1: EmptyStruct field } /** This is where you would document a Service */ service ThriftTest { /** And this is how you would document functions in a service */ void testVoid(), string testString(1: string thing), i8 testByte(1: byte thing), i32 testI32(1: i32 thing), /** Like this one */ i64 testI64(1: i64 thing), double testDouble(1: double thing), Xtruct testStruct(1: Xtruct thing), Xtruct2 testNest(1: Xtruct2 thing), map testMap(1: map thing), set testSet(1: set thing), list testList(1: list thing), /** This is an example of a function with params documented */ Numberz testEnum( /** This param is a thing */ 1: Numberz thing ), UserId testTypedef(1: UserId thing), map> testMapMap(1: i32 hello), /* So you think you've got this all worked, out eh? */ map> testInsanity(1: Insanity argument), } /// This style of Doxy-comment doesn't work. typedef i32 SorryNoGo /** * This is a trivial example of a multiline docstring. */ typedef i32 TrivialMultiLine /** * This is the canonical example * of a multiline docstring. */ typedef i32 StandardMultiLine /** * The last line is non-blank. * I said non-blank! */ typedef i32 LastLine /** Both the first line * are non blank. ;-) * and the last line */ typedef i32 FirstAndLastLine /** * INDENTED TITLE * The text is less indented. */ typedef i32 IndentedTitle /** First line indented. * Unfortunately, this does not get indented. */ typedef i32 FirstLineIndent /** * void code_in_comment() { * printf("hooray code!"); * } */ typedef i32 CodeInComment /** * Indented Docstring. * This whole docstring is indented. * This line is indented further. */ typedef i32 IndentedDocstring /** Irregular docstring. * We will have to punt * on this thing */ typedef i32 Irregular1 /** * note the space * before these lines * but not this * one */ typedef i32 Irregular2 /** * Flush against * the left. */ typedef i32 Flush /** No stars in this one. It should still work fine, though. Including indenting. */ typedef i32 NoStars /** Trailing whitespace Sloppy trailing whitespace is truncated. */ typedef i32 TrailingWhitespace /** * This is a big one. * * We'll have some blank lines in it. * * void as_well_as(some code) { * puts("YEEHAW!"); * } */ typedef i32 BigDog /** * * */ typedef i32 TotallyDegenerate /**no room for newline here*/ /* * / */ typedef i32 TestFor3501a /** * / */ typedef i32 TestFor3501b /* Comment-end tokens can of course have more than one asterisk */ struct TestFor3709_00 { /* ? */ 1: i32 foo } /* Comment-end tokens can of course have more than one asterisk **/ struct TestFor3709_01 { /* ? */ 1: i32 foo } /* Comment-end tokens can of course have more than one asterisk ***/ struct TestFor3709_02 { /* ? */ 1: i32 foo } /** Comment-end tokens can of course have more than one asterisk */ struct TestFor3709_03 { /* ? */ 1: i32 foo } /** Comment-end tokens can of course have more than one asterisk **/ struct TestFor3709_04 { /* ? */ 1: i32 foo } /** Comment-end tokens can of course have more than one asterisk ***/ struct TestFor3709_05 { /* ? */ 1: i32 foo } /*** Comment-end tokens can of course have more than one asterisk */ struct TestFor3709_06 { /* ? */ 1: i32 foo } /*** Comment-end tokens can of course have more than one asterisk **/ struct TestFor3709_07 { /* ? */ 1: i32 foo } /*** Comment-end tokens can of course have more than one asterisk ***/ struct TestFor3709_08 { /* ? */ 1: i32 foo } struct TestFor3709 { /** This is a comment */ 1: required string id, /** This is also a comment **/ 2: required string typeId, /** Yet another comment! */ 3: required i32 endTimestamp } /* THE END */ thrift-0.16.0/test/DoubleConstantsTest.thrift000066400000000000000000000021441420101504100212330ustar00rootroot00000000000000namespace java thrift.test namespace cpp thrift.test // more tests on double constants (precision and type checks) const double DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST = 1 const double DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST = -100 const double DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST = 9223372036854775807 const double DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST = -9223372036854775807 const double DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST = 3.14159265359 const double DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST = 1000000.1 const double DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST = -1000000.1 const double DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST = 1.7e+308 const double DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST = 9223372036854775816.43 const double DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST = -1.7e+308 const double DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST = -9223372036854775816.43 const list DOUBLE_LIST_TEST = [1,-100,100,9223372036854775807,-9223372036854775807,3.14159265359,1000000.1,-1000000.1,1.7e+308,-1.7e+308,9223372036854775816.43,-9223372036854775816.43] thrift-0.16.0/test/EnumContainersTest.thrift000066400000000000000000000026451420101504100210640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace java thrift.test.enumcontainers enum GreekGodGoddess { ARES, APHRODITE, ZEUS, POSEIDON, HERA, } typedef GreekGodGoddess GreekGodGoddessType typedef i32 Power struct GodBean { 1: optional map power, 2: optional set goddess, 3: optional map byAlias, 4: optional set images, } const map ATTRIBUTES = { GreekGodGoddess.ZEUS: "lightning bolt", GreekGodGoddess.POSEIDON: "trident", } const set BEAUTY = [ GreekGodGoddess.APHRODITE, GreekGodGoddess.HERA ] thrift-0.16.0/test/EnumTest.thrift000066400000000000000000000070101420101504100170250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace c_glib TTest enum MyEnum1 { ME1_0 = 0, ME1_1 = 1, ME1_2, ME1_3, ME1_5 = 5, ME1_6, } enum MyEnum2 { ME2_0, ME2_1, ME2_2, } enum MyEnum2_again { // enum value identifiers may appear again in another enum type ME0_1, ME1_1, ME2_1, ME3_1, } enum MyEnum3 { ME3_0, ME3_1, ME3_N2 = -2, ME3_N1, ME3_D0, ME3_D1, ME3_9 = 9, ME3_10, } enum MyEnum4 { ME4_A = 0x7ffffffd ME4_B ME4_C // attempting to define another enum value here fails // with an overflow error, as we overflow values that can be // represented with an i32. } enum MyEnum5 { e1 // fails with 0.9.3 and earlier e2 = 42 // fails with 0.9.3 and earlier } enum MyEnumWithCustomOstream { custom1 = 1, CustoM2 } (cpp.customostream) struct MyStruct { 1: MyEnum2 me2_2 = MyEnum1.ME2_2 2: MyEnum3 me3_n2 = MyEnum3.ME3_N2 3: MyEnum3 me3_d1 = MyEnum3.ME3_D1 } struct EnumTestStruct { 1: MyEnum3 a_enum; 2: list enum_list; 3: set enum_set; 4: map enum_enum_map; // collections as keys 44: map (python.immutable = ""), MyEnum3> list_enum_map; 45: map (python.immutable = ""), MyEnum3> set_enum_map; 46: map (python.immutable = ""), MyEnum3> map_enum_map; // collections as values 47: map> enum_map_map; 48: map> enum_set_map; 49: map> enum_list_map; } const EnumTestStruct ENUM_TEST = { 'a_enum': MyEnum3.ME3_D1, 'enum_list': [MyEnum3.ME3_D1, MyEnum3.ME3_0, MyEnum3.ME3_N2], 'enum_set': [MyEnum3.ME3_D1, MyEnum3.ME3_N1], 'enum_enum_map': {MyEnum3.ME3_D1: MyEnum3.ME3_0, MyEnum3.ME3_0: MyEnum3.ME3_D1}, 'list_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0, [MyEnum3.ME3_0]: MyEnum3.ME3_D1}, 'set_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0}, 'map_enum_map': {{MyEnum3.ME3_N1: MyEnum3.ME3_10}: MyEnum3.ME3_1}, 'enum_map_map': {MyEnum3.ME3_N1: {MyEnum3.ME3_D1: MyEnum3.ME3_D1}}, 'enum_set_map': {MyEnum3.ME3_N2: [MyEnum3.ME3_D1, MyEnum3.ME3_N1], MyEnum3.ME3_10: [MyEnum3.ME3_D1, MyEnum3.ME3_N1]}, 'enum_list_map': {MyEnum3.ME3_D1: [MyEnum3.ME3_10], MyEnum3.ME3_0: [MyEnum3.ME3_9, MyEnum3.ME3_10]}, } service EnumTestService { MyEnum3 testEnum(1: MyEnum3 enum1), list testEnumList(1: list enum1), set testEnumSet(1: set enum1), map testEnumMap(1: map enum1), EnumTestStruct testEnumStruct(1: EnumTestStruct enum1), } thrift-0.16.0/test/FullCamelTest.thrift000066400000000000000000000022041420101504100177650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace java thrift.test.fullcamel struct OneOfEachZZ { 1: bool im_true, 2: bool im_false, 3: byte a_bite, 4: i16 integer16, 5: i32 integer32, 6: i64 integer64, 7: double double_precision, 8: string some_characters, 9: string zomg_unicode, 10: bool what_who, } service UnderscoreSrv { i64 some_rpc_call(1: string message) } thrift-0.16.0/test/Identifiers.thrift000066400000000000000000000002021420101504100175220ustar00rootroot00000000000000// THRIFT-4953 struct NoFieldIdentifiersTest { string field_without_id1, string field_without_id2, 1: string field_with_id }thrift-0.16.0/test/Include.thrift000066400000000000000000000015751420101504100166560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ include "ThriftTest.thrift" struct IncludeTest { 1: required ThriftTest.Bools bools }thrift-0.16.0/test/Int64Test.thrift000066400000000000000000000035001420101504100170250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace js Int64Test const i64 SMALL_INT64 = 42 const i64 MAX_JS_SAFE_INT64 = 9007199254740991 const i64 MIN_JS_SAFE_INT64 = -9007199254740991 const i64 MAX_JS_SAFE_PLUS_ONE_INT64 = 9007199254740992 const i64 MIN_JS_SAFE_MINUS_ONE_INT64 = -9007199254740992 const i64 MAX_SIGNED_INT64 = 9223372036854775807 const i64 MIN_SIGNED_INT64 = -9223372036854775808 const list INT64_LIST = [SMALL_INT64, MAX_JS_SAFE_INT64, MIN_JS_SAFE_INT64, MAX_JS_SAFE_PLUS_ONE_INT64, MIN_JS_SAFE_MINUS_ONE_INT64, MAX_SIGNED_INT64, MIN_SIGNED_INT64] const map INT64_2_INT64_MAP = { SMALL_INT64: SMALL_INT64, MAX_JS_SAFE_INT64: MAX_JS_SAFE_INT64, MIN_JS_SAFE_INT64: MIN_JS_SAFE_INT64, MAX_JS_SAFE_PLUS_ONE_INT64: MAX_JS_SAFE_PLUS_ONE_INT64, MIN_JS_SAFE_MINUS_ONE_INT64: MIN_JS_SAFE_MINUS_ONE_INT64, MAX_SIGNED_INT64: MAX_SIGNED_INT64, MIN_SIGNED_INT64: MIN_SIGNED_INT64 } thrift-0.16.0/test/JavaBeansTest.thrift000066400000000000000000000022161420101504100177560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace java thrift.test struct OneOfEachBeans { 1: bool boolean_field, 2: byte a_bite, 3: i16 integer16, 4: i32 integer32, 5: i64 integer64, 6: double double_precision, 7: string some_characters, 8: binary base64, 9: list byte_list, 10: list i16_list, 11: list i64_list } service Service { i64 mymethod(i64 blah); }thrift-0.16.0/test/JavaBinaryDefault.thrift000066400000000000000000000016361420101504100206240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace java thrift.test struct StringAndBinary { 1: optional string strval = "" 2: optional binary binval = "" } thrift-0.16.0/test/JavaDeepCopyTest.thrift000066400000000000000000000006711420101504100204410ustar00rootroot00000000000000include "JavaTypes.thrift" namespace java thrift.test struct DeepCopyFoo { 1: optional list l, 2: optional set s, 3: optional map m, 4: optional list li, 5: optional set si, 6: optional map mi, 7: optional DeepCopyBar bar, } struct DeepCopyBar { 1: optional string a, 2: optional i32 b, 3: optional bool c, } thrift-0.16.0/test/JavaTypes.thrift000066400000000000000000000035311420101504100171730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace java thrift.test struct Integer { 1: i32 val } struct String { 1: string val } struct Binary { 1: binary val } struct Boolean { 1: bool val } struct Double { 1: double val } struct Long { 1: i64 val } struct Byte { 1: byte val } struct Float { 1: double val } struct List { 1: list vals } struct ArrayList { 1: list vals } struct SortedMap { 1: map vals } struct TreeMap { 1: map vals } struct HashMap { 1: map vals } struct Map { 1: map vals } struct Object { 1: Integer integer, 2: String str, 3: Boolean boolean_field, 4: Double dbl, 5: Byte bite, 6: map intmap, 7: Map somemap, } exception Exception { 1: string msg } service AsyncNonblockingService { Object mymethod( 1: Integer integer, 2: String str, 3: Boolean boolean_field, 4: Double dbl, 5: Byte bite, 6: map intmap, 7: Map somemap, ) throws (1:Exception ex); } struct SafeBytes { 1: binary bytes; } thrift-0.16.0/test/JsDeepConstructorTest.thrift000066400000000000000000000007661420101504100215540ustar00rootroot00000000000000struct Simple { 1: string value } struct Complex { 1: Simple struct_field 2: list struct_list_field 3: set struct_set_field 4: map struct_map_field 5: list>>> struct_nested_containers_field 6: map> > struct_nested_containers_field2 7: list> list_of_list_field 8: list>> list_of_list_of_list_field } struct ComplexList { 1: list struct_list_field; } thrift-0.16.0/test/Makefile.am000077500000000000000000000071501420101504100161030ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = features PRECROSS_TARGET = if WITH_C_GLIB SUBDIRS += c_glib PRECROSS_TARGET += precross-c_glib endif if WITH_CL SUBDIRS += cl PRECROSS_TARGET += precross-cl endif if WITH_CPP SUBDIRS += cpp PRECROSS_TARGET += precross-cpp endif if WITH_PERL SUBDIRS += perl PRECROSS_TARGET += precross-perl endif if WITH_PHP SUBDIRS += php PRECROSS_TARGET += precross-php endif if WITH_DART SUBDIRS += dart PRECROSS_TARGET += precross-dart endif if WITH_PYTHON SUBDIRS += py PRECROSS_TARGET += precross-py SUBDIRS += py.tornado if WITH_TWISTED_TEST SUBDIRS += py.twisted endif endif if WITH_RUBY SUBDIRS += rb PRECROSS_TARGET += precross-rb endif if WITH_HAXE SUBDIRS += haxe endif if WITH_DOTNET SUBDIRS += netstd endif if WITH_GO SUBDIRS += go PRECROSS_TARGET += precross-go endif if WITH_ERLANG SUBDIRS += erl PRECROSS_TARGET += precross-erl endif if WITH_LUA SUBDIRS += lua PRECROSS_TARGET += precross-lua endif if WITH_RS SUBDIRS += rs PRECROSS_TARGET += precross-rs endif # # generate html for ThriftTest.thrift AND validate it! # if WITH_NODEJS check-local: $(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/test/ThriftTest.thrift $(top_builddir)/node_modules/.bin/html-validator --file=gen-html/index.html --verbose $(top_builddir)/node_modules/.bin/html-validator --file=gen-html/ThriftTest.html --verbose else check-local: $(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/test/ThriftTest.thrift endif clean-local: $(RM) -r $(top_srcdir)/test/gen-html/ find . -type d -name "__pycache__" | xargs rm -rf find . -type f -name "*.pyc" | xargs rm -f dist-hook: $(RM) -r $(distdir)/gen-html/ find $(distdir) -type d -name "__pycache__" | xargs rm -rf find $(distdir) -type f -name "*.pyc" | xargs rm -f EXTRA_DIST = \ audit \ c_glib \ cl \ cpp \ crossrunner \ dart \ erl \ keys \ lua \ ocaml \ perl \ php \ py \ py.tornado \ py.twisted \ rb \ rs \ threads \ partial \ AnnotationTest.thrift \ BrokenConstants.thrift \ ConstantsDemo.thrift \ DebugProtoTest.thrift \ DenseLinkingTest.thrift \ DocTest.thrift \ DoubleConstantsTest.thrift \ EnumContainersTest.thrift \ EnumTest.thrift \ FullCamelTest.thrift \ Include.thrift \ Identifiers.thrift \ Int64Test.thrift \ JavaBeansTest.thrift \ JavaBinaryDefault.thrift \ JavaDeepCopyTest.thrift \ JavaTypes.thrift \ JsDeepConstructorTest.thrift \ ManyOptionals.thrift \ ManyTypedefs.thrift \ NameConflictTest.thrift \ OptionalRequiredTest.thrift \ Recursive.thrift \ ReuseObjects.thrift \ SmallTest.thrift \ StressTest.thrift \ ThriftTest.thrift \ TypedefTest.thrift \ Types.thrift \ UnsafeTypes.thrift \ Service.thrift \ SpecificNameTest.thrift \ known_failures_Linux.json \ test.py \ tests.json \ rebuild_known_failures.sh \ result.js \ index.html \ README.md \ valgrind.suppress precross-%: $(MAKE) -C $* precross precross: $(PRECROSS_TARGET) thrift-0.16.0/test/ManyOptionals.thrift000066400000000000000000000102101420101504100200520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // The java codegenerator has a few different codepaths depending // on how many optionals the struct has; this attempts to exercise // them. namespace java thrift.test struct Opt4 { 1: i32 def1; 2: i32 def2; 3: i32 def3; 4: i32 def4; } struct Opt13 { 1: i32 def1; 2: i32 def2; 3: i32 def3; 4: i32 def4; 5: i32 def5; 6: i32 def6; 7: i32 def7; 8: i32 def8; 9: i32 def9; 10: i32 def10; 11: i32 def11; 12: i32 def12; 13: i32 def13; } struct Opt30 { 1: i32 def1; 2: i32 def2; 3: i32 def3; 4: i32 def4; 5: i32 def5; 6: i32 def6; 7: i32 def7; 8: i32 def8; 9: i32 def9; 10: i32 def10; 11: i32 def11; 12: i32 def12; 13: i32 def13; 14: i32 def14; 15: i32 def15; 16: i32 def16; 17: i32 def17; 18: i32 def18; 19: i32 def19; 20: i32 def20; 21: i32 def21; 22: i32 def22; 23: i32 def23; 24: i32 def24; 25: i32 def25; 26: i32 def26; 27: i32 def27; 28: i32 def28; 29: i32 def29; 30: i32 def30; } struct Opt64 { 1: i32 def1; 2: i32 def2; 3: i32 def3; 4: i32 def4; 5: i32 def5; 6: i32 def6; 7: i32 def7; 8: i32 def8; 9: i32 def9; 10: i32 def10; 11: i32 def11; 12: i32 def12; 13: i32 def13; 14: i32 def14; 15: i32 def15; 16: i32 def16; 17: i32 def17; 18: i32 def18; 19: i32 def19; 20: i32 def20; 21: i32 def21; 22: i32 def22; 23: i32 def23; 24: i32 def24; 25: i32 def25; 26: i32 def26; 27: i32 def27; 28: i32 def28; 29: i32 def29; 30: i32 def30; 31: i32 def31; 32: i32 def32; 33: i32 def33; 34: i32 def34; 35: i32 def35; 36: i32 def36; 37: i32 def37; 38: i32 def38; 39: i32 def39; 40: i32 def40; 41: i32 def41; 42: i32 def42; 43: i32 def43; 44: i32 def44; 45: i32 def45; 46: i32 def46; 47: i32 def47; 48: i32 def48; 49: i32 def49; 50: i32 def50; 51: i32 def51; 52: i32 def52; 53: i32 def53; 54: i32 def54; 55: i32 def55; 56: i32 def56; 57: i32 def57; 58: i32 def58; 59: i32 def59; 60: i32 def60; 61: i32 def61; 62: i32 def62; 63: i32 def63; 64: i32 def64; } struct Opt80 { 1: i32 def1; 2: i32 def2; 3: i32 def3; 4: i32 def4; 5: i32 def5; 6: i32 def6; 7: i32 def7; 8: i32 def8; 9: i32 def9; 10: i32 def10; 11: i32 def11; 12: i32 def12; 13: i32 def13; 14: i32 def14; 15: i32 def15; 16: i32 def16; 17: i32 def17; 18: i32 def18; 19: i32 def19; 20: i32 def20; 21: i32 def21; 22: i32 def22; 23: i32 def23; 24: i32 def24; 25: i32 def25; 26: i32 def26; 27: i32 def27; 28: i32 def28; 29: i32 def29; 30: i32 def30; 31: i32 def31; 32: i32 def32; 33: i32 def33; 34: i32 def34; 35: i32 def35; 36: i32 def36; 37: i32 def37; 38: i32 def38; 39: i32 def39; 40: i32 def40; 41: i32 def41; 42: i32 def42; 43: i32 def43; 44: i32 def44; 45: i32 def45; 46: i32 def46; 47: i32 def47; 48: i32 def48; 49: i32 def49; 50: i32 def50; 51: i32 def51; 52: i32 def52; 53: i32 def53; 54: i32 def54; 55: i32 def55; 56: i32 def56; 57: i32 def57; 58: i32 def58; 59: i32 def59; 60: i32 def60; 61: i32 def61; 62: i32 def62; 63: i32 def63; 64: i32 def64; 65: i32 def65; 66: i32 def66; 67: i32 def67; 68: i32 def68; 69: i32 def69; 70: i32 def70; 71: i32 def71; 72: i32 def72; 73: i32 def73; 74: i32 def74; 75: i32 def75; 76: i32 def76; 77: i32 def77; 78: i32 def78; 79: i32 def79; 80: i32 def80; } thrift-0.16.0/test/ManyTypedefs.thrift000066400000000000000000000032371420101504100177000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // This is to make sure you don't mess something up when you change typedef code. // Generate it with the old and new thrift and make sure they are the same. /* rm -rf gen-* orig-* mkdir old new thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift mv gen-* old ../compiler/cpp/thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift mv gen-* new diff -ur old new rm -rf old new # There should be no output. */ typedef i32 int32 typedef list> biglist struct struct1 { 1: int32 myint; 2: biglist mylist; } exception exception1 { 1: biglist alist; 2: struct1 mystruct; } service AService { struct1 method1(1: int32 myint) throws (1: exception1 exn); biglist method2(); } thrift-0.16.0/test/NameConflictTest.thrift000066400000000000000000000032731420101504100204720ustar00rootroot00000000000000// Naming testcases, sepcifically for these tickets (but not limited to them) // THRIFT-2508 Uncompileable C# code due to language keywords in IDL // THRIFT-2557 error CS0542 member names cannot be the same as their enclosing type struct using { 1: double single 2: double integer } struct delegate { 1: string partial 2: delegate delegate } struct get { 1: bool sbyte } struct partial { 1: using using 2: bool read 3: bool write } enum Maybe { JUST = 1, TRUE = 2, FALSE = 3 } enum Either { LEFT = 1, RIGHT = 2 } struct foldr { 1: string id } struct of { 1: string let 2: string where } struct ofOf { 1: of Of } struct ClassAndProp { 1: bool ClassAndProp 2: bool ClassAndProp_ 3: bool ClassAndProp__ 4: bool ClassAndProper } struct second_chance { 1: bool SECOND_CHANCE 2: bool SECOND_CHANCE_ 3: bool SECOND_CHANCE__ 4: bool SECOND_CHANCES } struct NOW_EAT_THIS { 1: bool now_eat_this 2: bool now_eat_this_ 3: bool now_eat_this__ 4: bool now_eat_this_and_this } struct TheEdgeCase { 1: bool theEdgeCase 2: bool theEdgeCase_ 3: bool theEdgeCase__ 4: bool TheEdgeCase 5: bool TheEdgeCase_ 6: bool TheEdgeCase__ } struct Tricky_ { 1: bool tricky 2: bool Tricky } struct Nested { 1: ClassAndProp ClassAndProp 2: second_chance second_chance 3: NOW_EAT_THIS NOW_EAT_THIS 4: TheEdgeCase TheEdgeCase 5: Tricky_ Tricky_ 6: Nested Nested } exception Problem_ { 1: bool problem 2: bool Problem } service extern { delegate event(1: partial get) void Foo(1: Nested Foo_args) throws (1: Problem_ Foo_result) } service qualified { Maybe maybe(1: Maybe foldr) Either either(1: foldr of) } // eof thrift-0.16.0/test/OptionalRequiredTest.thrift000066400000000000000000000042041420101504100214110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace c_glib TTest namespace cpp thrift.test namespace java thrift.test struct OldSchool { 1: i16 im_int; 2: string im_str; 3: list> im_big; } struct Simple { 1: /* :) */ i16 im_default; 2: required i16 im_required; 3: optional i16 im_optional; } struct Tricky1 { 1: /* :) */ i16 im_default; } struct Tricky2 { 1: optional i16 im_optional; } struct Tricky3 { 1: required i16 im_required; } struct OptionalDefault { 1: optional i16 opt_int = 1234; 2: optional string opt_str = "default"; } struct Complex { 1: i16 cp_default; 2: required i16 cp_required; 3: optional i16 cp_optional; 4: map the_map; 5: required Simple req_simp; 6: optional Simple opt_simp; } struct ManyOpt { 1: optional i32 opt1; 2: optional i32 opt2; 3: optional i32 opt3; 4: i32 def4; 5: optional i32 opt5; 6: optional i32 opt6; } struct JavaTestHelper { 1: required i32 req_int; 2: optional i32 opt_int; 3: required string req_obj; 4: optional string opt_obj; 5: required binary req_bin; 6: optional binary opt_bin; } struct Binaries { 4: binary bin; 5: required binary req_bin; 6: optional binary opt_bin; } thrift-0.16.0/test/README.md000077500000000000000000000160431420101504100153270ustar00rootroot00000000000000# Apache Thrift - integration test suite This is the cross everything integration test suite for Apache Thrift. ## Run ### A. Using Make The test can be executed by: make cross This starts the [test.py](test.py) script which does the real cross test with different transports, protocols and languages. Note that this skips any language that is not built locally. It also skips tests that are known to be failing. If you need more control over which tests to run, read following section. ### B. Using test script directly Alternatively, you can invoke [test.py](test.py) directly. You need to run`make precross` once before executing it for the first time. For example, if you changed something in `nodejs` library and need to verify the patch, you can skip everything except `nodejs` itself and some reference implementation (currently `cpp` and `java` are recommended) like this: ./configure --without-c_glib --without-erlang --without-lua ... make precross -j8 test/test.py --server cpp,java --client nodejs test/test.py --server nodejs --client cpp,java Another useful flag is --regex. For example, to run all tests that involve Java TBinaryProtocol: test/test.py --regex "java.*binary" ## Test case definition file The cross test cases are defined in [tests.json](tests.json). The root element is collection of test target definitions. Each test target definition looks like this: { "name": "somelib", "client": { "command": ["somelib_client_executable"], "workdir": "somelib/bin", "protocols": ["binary"], "transports": ["buffered"], "sockets": ["ip"], }, "server": { "command": ["somelib_server_executable"], "workdir": "somelib/bin", "protocols": ["binary"], "transports": ["buffered"], "sockets": ["ip", "ip-ssl"], } } Either client or server definition or both should be present. Parameters that are common to both `client` and `server` can be put to target definition root: { "name": "somelib", "workdir": "somelib/bin", "protocols": ["binary"], "transports": ["buffered"], "sockets": ["ip"], "client": { "command": ["somelib_client_executable"] }, "server": { "command": ["somelib_server_executable"], "sockets": ["ip-ssl"] } } For the complete list of supported keys and their effect, see source code comment at the opt of [crossrunner/collect.py](crossrunner/collect.py). ## List of known failures Since many cross tests currently fail (mainly due to partial incompatibility around exception handling), the test script specifically report for "not known before" failures. For this purpose, test cases known to (occasionally) fail are listed in `known_failures_.json` where `` matches with python `platform.system()` string. Currently, only Linux version is included. FYI, the file is initially generated by test/test.py --update-expected-failures=overwrite after a full test run, then repeatedly test/test.py --skip-known-failures test/test.py --update-expected-failures=merge to update the known failures, run make fail ## Test executable specification ### Command line parameters Unit tests for languages are usually located under lib//test/ cross language tests according to [ThriftTest.thrift](ThriftTest.thrift) shall be provided for every language including executables with the following command line interface: **Server command line interface:** $ ./TestServer -h Allowed options: -h | --help produce help message --port=arg (9090) Port number to listen --domain-socket=arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift) --pipe=arg Windows Named Pipe (e.g. MyThriftPipe) --server-type=arg (simple) type of server, "simple", "thread-pool", "threaded", or "nonblocking" --transport=arg (buffered) transport: buffered, framed, http, anonpipe, zlib --protocol=arg (binary) protocol: binary, compact, header, json --multiplex Add TMultiplexedProtocol service name "ThriftTest" --abstract-namespace Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames) --ssl Encrypted Transport using SSL --zlib Wrapped Transport using Zlib --processor-events processor-events -n=arg | --workers=arg (=4) Number of thread pools workers. Only valid for thread-pool server type **Client command line interface:** $ ./TestClient -h Allowed options: -h | --help produce help message --host=arg (localhost) Host to connect --port=arg (9090) Port number to connect --domain-socket=arg Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port --pipe=arg Windows Named Pipe (e.g. MyThriftPipe) --anon-pipes hRead hWrite Windows Anonymous Pipes pair (handles) --abstract-namespace Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames) --transport=arg (buffered) Transport: buffered, framed, http, evhttp, zlib --protocol=arg (binary) Protocol: binary, compact, header, json --multiplex Add TMultiplexedProtocol service name "ThriftTest" --ssl Encrypted Transport using SSL --zlib Wrap Transport with Zlib -n=arg | --testloops=arg (1) Number of Tests -t=arg | --threads=arg (1) Number of Test threads If you have executed the **make check** or **make cross** then you will be able to browse [gen-html/ThriftTest.html](gen-html/ThriftTest.html) with the test documentation. ### Return code The return code (exit code) shall be 0 on success, or an integer in the range 1 - 255 on errors. In order to signal failed tests, the return code shall be composed from these bits to indicate failing tests: #define TEST_BASETYPES 1 // 0000 0001 #define TEST_STRUCTS 2 // 0000 0010 #define TEST_CONTAINERS 4 // 0000 0100 #define TEST_EXCEPTIONS 8 // 0000 1000 #define TEST_UNKNOWN 64 // 0100 0000 (Failed to prepare environment etc.) #define TEST_TIMEOUT 128 // 1000 0000 #define TEST_NOTUSED 48 // 0011 0000 (reserved bits) Tests that have not been executed at all count as errors. **Example:** During tests, the test client notices that some of the Struct tests fail. Furthermore, due to some other problem none of the Exception tests is executed. Therefore, the test client returns the code `10 = 2 | 8`, indicating the failure of both test 2 (TEST_STRUCTS) and test 8 (TEST_EXCEPTIONS). ## SSL Test Keys and Certificates are provided in multiple formats under the following directory [test/keys](keys) thrift-0.16.0/test/Recursive.thrift000066400000000000000000000022271420101504100172350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ struct RecTree { 1: list children 2: i16 item } struct RecList { 1: RecList & nextitem 3: i16 item } struct CoRec { 1: CoRec2 & other } struct CoRec2 { 1: CoRec other } struct VectorTest { 1: list lister; } service TestService { RecTree echoTree(1:RecTree tree) RecList echoList(1:RecList lst) CoRec echoCoRec(1:CoRec item) } thrift-0.16.0/test/ReuseObjects.thrift000066400000000000000000000017411420101504100176630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // The java codegenerator has option to reuse objects for deserialization namespace java thrift.test include "ThriftTest.thrift" struct Reuse { 1: i32 val1; 2: set val2; } thrift-0.16.0/test/Service.thrift000066400000000000000000000015761420101504100166740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ include "Types.thrift" service Service { Types.Type1 testEpisode(1:Types.Type1 arg) } thrift-0.16.0/test/SmallTest.thrift000066400000000000000000000031151420101504100171730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace rb TestNamespace struct Goodbyez { 1: i32 val = 325; } senum Thinger { "ASDFKJ", "r32)*F#@", "ASDFLJASDF" } struct BoolPasser { 1: bool value = 1 } struct Hello { 1: i32 simple = 53, 2: map complex = {23:532, 6243:632, 2355:532}, 3: map> complexer, 4: string words = "words", 5: Goodbyez thinz = {'val' : 36632} } const map> CMAP = { 235: {235:235}, 53:{53:53} } const i32 CINT = 325; const Hello WHOA = {'simple' : 532} exception Goodbye { 1: i32 simple, 2: map complex, 3: map> complexer, } service SmallService { Thinger testThinger(1:Thinger bootz), Hello testMe(1:i32 hello=64, 2: Hello wonk) throws (1: Goodbye g), void testVoid() throws (1: Goodbye g), i32 testI32(1:i32 boo) } thrift-0.16.0/test/SpecificNameTest.thrift000066400000000000000000000017661420101504100204630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace cpp test.specificname struct a { 1: i32 number, 2: string message, } struct b { 1: i32 number, 2: string message, } service EchoService { void echoA(1: a arg), void echoB(2: b arg), } thrift-0.16.0/test/StressTest.thrift000066400000000000000000000022071420101504100174070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace cpp test.stress namespace d thrift.test.stress namespace go stress service Service { void echoVoid(), i8 echoByte(1: i8 arg), i32 echoI32(1: i32 arg), i64 echoI64(1: i64 arg), string echoString(1: string arg), list echoList(1: list arg), set echoSet(1: set arg), map echoMap(1: map arg), } thrift-0.16.0/test/ThriftTest.thrift000066400000000000000000000262711420101504100173730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace c_glib TTest namespace cpp thrift.test namespace delphi Thrift.Test namespace go thrifttest namespace java thrift.test namespace js ThriftTest namespace lua ThriftTest namespace netstd ThriftTest namespace perl ThriftTest namespace php ThriftTest namespace py ThriftTest namespace py.twisted ThriftTest namespace rb Thrift.Test namespace st ThriftTest namespace xsd test (uri = 'http://thrift.apache.org/ns/ThriftTest') // Presence of namespaces and sub-namespaces for which there is // no generator should compile with warnings only namespace noexist ThriftTest namespace cpp.noexist ThriftTest namespace * thrift.test /** * Docstring! */ enum Numberz { ONE = 1, TWO, THREE, FIVE = 5, SIX, EIGHT = 8 } const Numberz myNumberz = Numberz.ONE; // the following is expected to fail: // const Numberz urNumberz = ONE; typedef i64 UserId struct Bonk { 1: string message, 2: i32 type } typedef map MapType struct Bools { 1: bool im_true, 2: bool im_false, } struct Xtruct { 1: string string_thing, 4: i8 byte_thing, 9: i32 i32_thing, 11: i64 i64_thing } struct Xtruct2 { 1: i8 byte_thing, // used to be byte, hence the name 2: Xtruct struct_thing, 3: i32 i32_thing } struct Xtruct3 { 1: string string_thing, 4: i32 changed, 9: i32 i32_thing, 11: i64 i64_thing } struct Insanity { 1: map userMap, 2: list xtructs } (python.immutable= "") struct CrazyNesting { 1: string string_field, 2: optional set set_field, // Do not insert line break as test/go/Makefile.am is removing this line with pattern match 3: required list (python.immutable = ""), map(python.immutable = "")> (python.immutable = "")>>>> list_field, 4: binary binary_field } union SomeUnion { 1: map map_thing, 2: string string_thing, 3: i32 i32_thing, 4: Xtruct3 xtruct_thing, 5: Insanity insanity_thing } exception Xception { 1: i32 errorCode, 2: string message } exception Xception2 { 1: i32 errorCode, 2: Xtruct struct_thing } struct EmptyStruct {} struct OneField { 1: EmptyStruct field } service ThriftTest { /** * Prints "testVoid()" and returns nothing. */ void testVoid(), /** * Prints 'testString("%s")' with thing as '%s' * @param string thing - the string to print * @return string - returns the string 'thing' */ string testString(1: string thing), /** * Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false' * @param bool thing - the bool data to print * @return bool - returns the bool 'thing' */ bool testBool(1: bool thing), /** * Prints 'testByte("%d")' with thing as '%d' * The types i8 and byte are synonyms, use of i8 is encouraged, byte still exists for the sake of compatibility. * @param byte thing - the i8/byte to print * @return i8 - returns the i8/byte 'thing' */ i8 testByte(1: i8 thing), /** * Prints 'testI32("%d")' with thing as '%d' * @param i32 thing - the i32 to print * @return i32 - returns the i32 'thing' */ i32 testI32(1: i32 thing), /** * Prints 'testI64("%d")' with thing as '%d' * @param i64 thing - the i64 to print * @return i64 - returns the i64 'thing' */ i64 testI64(1: i64 thing), /** * Prints 'testDouble("%f")' with thing as '%f' * @param double thing - the double to print * @return double - returns the double 'thing' */ double testDouble(1: double thing), /** * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data * @param binary thing - the binary data to print * @return binary - returns the binary 'thing' */ binary testBinary(1: binary thing), /** * Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values * @param Xtruct thing - the Xtruct to print * @return Xtruct - returns the Xtruct 'thing' */ Xtruct testStruct(1: Xtruct thing), /** * Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct * @param Xtruct2 thing - the Xtruct2 to print * @return Xtruct2 - returns the Xtruct2 'thing' */ Xtruct2 testNest(1: Xtruct2 thing), /** * Prints 'testMap("{%s")' where thing has been formatted into a string of 'key => value' pairs * separated by commas and new lines * @param map thing - the map to print * @return map - returns the map 'thing' */ map testMap(1: map thing), /** * Prints 'testStringMap("{%s}")' where thing has been formatted into a string of 'key => value' pairs * separated by commas and new lines * @param map thing - the map to print * @return map - returns the map 'thing' */ map testStringMap(1: map thing), /** * Prints 'testSet("{%s}")' where thing has been formatted into a string of values * separated by commas and new lines * @param set thing - the set to print * @return set - returns the set 'thing' */ set testSet(1: set thing), /** * Prints 'testList("{%s}")' where thing has been formatted into a string of values * separated by commas and new lines * @param list thing - the list to print * @return list - returns the list 'thing' */ list testList(1: list thing), /** * Prints 'testEnum("%d")' where thing has been formatted into its numeric value * @param Numberz thing - the Numberz to print * @return Numberz - returns the Numberz 'thing' */ Numberz testEnum(1: Numberz thing), /** * Prints 'testTypedef("%d")' with thing as '%d' * @param UserId thing - the UserId to print * @return UserId - returns the UserId 'thing' */ UserId testTypedef(1: UserId thing), /** * Prints 'testMapMap("%d")' with hello as '%d' * @param i32 hello - the i32 to print * @return map> - returns a dictionary with these values: * {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, } */ map> testMapMap(1: i32 hello), /** * So you think you've got this all worked out, eh? * * Creates a map with these values and prints it out: * { 1 => { 2 => argument, * 3 => argument, * }, * 2 => { 6 => , }, * } * @return map> - a map with the above values */ map> testInsanity(1: Insanity argument), /** * Prints 'testMulti()' * @param i8 arg0 - * @param i32 arg1 - * @param i64 arg2 - * @param map arg3 - * @param Numberz arg4 - * @param UserId arg5 - * @return Xtruct - returns an Xtruct with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1 * and i64_thing = arg2 */ Xtruct testMulti(1: i8 arg0, 2: i32 arg1, 3: i64 arg2, 4: map arg3, 5: Numberz arg4, 6: UserId arg5), /** * Print 'testException(%s)' with arg as '%s' * @param string arg - a string indication what type of exception to throw * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg * else if arg == "TException" throw TException * else do not throw anything */ void testException(1: string arg) throws(1: Xception err1), /** * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s' * @param string arg - a string indicating what type of exception to throw * if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception" * else if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and struct_thing.string_thing = "This is an Xception2" * else do not throw anything * @return Xtruct - an Xtruct with string_thing = arg1 */ Xtruct testMultiException(1: string arg0, 2: string arg1) throws(1: Xception err1, 2: Xception2 err2) /** * Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d' * sleep 'secondsToSleep' * Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d' * @param i32 secondsToSleep - the number of seconds to sleep */ oneway void testOneway(1:i32 secondsToSleep) } service SecondService { /** * Prints 'testString("%s")' with thing as '%s' * @param string thing - the string to print * @return string - returns the string 'thing' */ string secondtestString(1: string thing) } struct VersioningTestV1 { 1: i32 begin_in_both, 3: string old_string, 12: i32 end_in_both } struct VersioningTestV2 { 1: i32 begin_in_both, 2: i32 newint, 3: i8 newbyte, 4: i16 newshort, 5: i64 newlong, 6: double newdouble 7: Bonk newstruct, 8: list newlist, 9: set newset, 10: map newmap, 11: string newstring, 12: i32 end_in_both } struct ListTypeVersioningV1 { 1: list myints; 2: string hello; } struct ListTypeVersioningV2 { 1: list strings; 2: string hello; } struct GuessProtocolStruct { 7: map map_field, } struct LargeDeltas { 1: Bools b1, 10: Bools b10, 100: Bools b100, 500: bool check_true, 1000: Bools b1000, 1500: bool check_false, 2000: VersioningTestV2 vertwo2000, 2500: set a_set2500, 3000: VersioningTestV2 vertwo3000, 4000: list big_numbers } struct NestedListsI32x2 { 1: list> integerlist } struct NestedListsI32x3 { 1: list>> integerlist } struct NestedMixedx2 { 1: list> int_set_list 2: map> map_int_strset 3: list>> map_int_strset_list } struct ListBonks { 1: list bonk } struct NestedListsBonk { 1: list>> bonk } struct BoolTest { 1: optional bool b = true; 2: optional string s = "true"; } struct StructA { 1: required string s; } struct StructB { 1: optional StructA aa; 2: required StructA ab; } struct OptionalSetDefaultTest { 1: optional set with_default = [ "test" ] } struct OptionalBinary { 1: optional set bin_set = {} 2: optional map bin_map = {} } thrift-0.16.0/test/TypedefTest.thrift000066400000000000000000000022621420101504100175250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Contains some contributions under the Thrift Software License. * Please see doc/old-thrift-license.txt in the Thrift distribution for * details. */ namespace cpp thrift.test typedef i32 MyInt32 typedef string MyString; struct TypedefTestStruct { 1: MyInt32 field_MyInt32; 2: MyString field_MyString; 3: i32 field_Int32; 4: string field_String; } typedef TypedefTestStruct MyStruct,thrift-0.16.0/test/Types.thrift000066400000000000000000000015331420101504100163710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ struct Type1 { 1: i32 number, 2: string message, }thrift-0.16.0/test/UnsafeTypes.thrift000066400000000000000000000015531420101504100175350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace java thrift.test struct UnsafeBytes { 1: binary bytes; } thrift-0.16.0/test/audit/000077500000000000000000000000001420101504100151475ustar00rootroot00000000000000thrift-0.16.0/test/audit/README.md000066400000000000000000000020371420101504100164300ustar00rootroot00000000000000Typical usage ============= ``` thrift.exe --audit ``` Example run =========== ``` > thrift.exe --audit test.thrift break1.thrift [Thrift Audit Failure:break1.thrift] New Thrift File has missing function base_function3 [Thrift Audit Warning:break1.thrift] Constant const3 has different value ``` Problems that the audit tool can catch ====================================== Errors * Removing an enum value * Changing the type of a struct field * Changing the required-ness of a struct field * Removing a struct field * Adding a required struct field * Adding a struct field 'in the middle'. This usually indicates an old ID has been recycled * Struct removed * Oneway-ness change * Return type change * Missing function * Missing service * Change in service inheritance Warnings * Removing a language namespace declaration * Changing a namespace * Changing an enum value's name * Removing an enum class * Default value changed * Struct field name change * Removed constant * Type of constant changed * Value of constant changed thrift-0.16.0/test/audit/break1.thrift000066400000000000000000000122101420101504100175320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //Thrift Method removed from service base. namespace cpp test //constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3= [23, 32], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break10.thrift000066400000000000000000000122151420101504100176170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break10 - Struct field removed from struct2 id =1 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 2: list struct2_member2, 3: list struct2_member3 = [23, 32], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break11.thrift000066400000000000000000000122051420101504100176170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break11 - Struct field removed from struct3 id =7 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break12.thrift000066400000000000000000000122721420101504100176240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // derived1_function1 return type changed from enum1 to enum2 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum2 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break13.thrift000066400000000000000000000122761420101504100176310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // derived1_function6 return type changed from struct1 to struct2 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct2 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break14.thrift000066400000000000000000000122741420101504100176300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // derived1_function6 return type changed from string to double namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), double derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break15.thrift000066400000000000000000000123131420101504100176230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // break15 - derived2_function1 return type changed from list to list namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break16.thrift000066400000000000000000000123611420101504100176270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // break 16 - derived2_function5 return type changed from map to map namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break17.thrift000066400000000000000000000123421420101504100176270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break17 - derived2_function6 return type changed from map to map namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break18.thrift000066400000000000000000000122401420101504100176250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break18- oneway removed from base_oneway namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break19.thrift000066400000000000000000000122561420101504100176350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break19 - oneway added to base_function1 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), oneway void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break2.thrift000066400000000000000000000122411420101504100175370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //Struct field changed in test_struct1 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i32 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break20.thrift000066400000000000000000000122301420101504100176150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // break 20 - first enum value removed from enum1 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break21.thrift000066400000000000000000000122251420101504100176220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break21- last enum value removed from enum2 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break22.thrift000066400000000000000000000122331420101504100176220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break22 - in-between enum value removed from enum1 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break23.thrift000066400000000000000000000123241420101504100176240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break23 - required struct field added to struct4 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2, 3: required i64 struct4_member3 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break24.thrift000066400000000000000000000122361420101504100176270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break24 - removed inheritance from derived1. namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break25.thrift000066400000000000000000000122421420101504100176250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //Changed inheritance of derived2 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends derived1 { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break26.thrift000066400000000000000000000122761420101504100176350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break26 - Field type changed in base_function1 argument id=3 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: double function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break27.thrift000066400000000000000000000123111420101504100176240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // break27 - argument changed base_function2 list to list id =8 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break28.thrift000066400000000000000000000123071420101504100176320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break28- derived1_function5 arguement type changed map to list namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: list function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break29.thrift000066400000000000000000000122761420101504100176400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break29 - base_function2 arguemnt type changed list to string namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: string function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break3.thrift000066400000000000000000000122731420101504100175450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break3 - Struct field changed in test_struct1(enum1 to enum2) namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum2 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break30.thrift000066400000000000000000000123351420101504100176240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // break30- derived1_function6 argument changed struct1 to map namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), map derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break31.thrift000066400000000000000000000122171420101504100176240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break31 - Exception removed to base_function2 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break32.thrift000066400000000000000000000122571420101504100176310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break32- Exception1 field type changed for id =1 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i64 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break33.thrift000066400000000000000000000122631420101504100176270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break33 - derived1_function1 exception type changed. namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception1 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break34.thrift000066400000000000000000000124101420101504100176220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break34 - Field added to struct with Field ID being in between two existing field IDs namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 6: map struct3_member6, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break4.thrift000066400000000000000000000122601420101504100175420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //Field type changed in test_struct1(bool to string) namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: string struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 =[23, 32], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break5.thrift000066400000000000000000000123021420101504100175400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // member field type changed in test_struct1(bool to list) namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: list struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break6.thrift000066400000000000000000000122731420101504100175500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // Field type changed in test_struct2 (list to list) namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break7.thrift000066400000000000000000000122351420101504100175470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break7 - requiredness removed in struct6 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break8.thrift000066400000000000000000000122571420101504100175540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break8 - requiredness addedd in struct5 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: required string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/break9.thrift000066400000000000000000000122141420101504100175460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //break9 - Struct field removed from struct1 namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/test.thrift000066400000000000000000000121731420101504100173540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.3; const map const3 = {"hello":"world", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.5, 5: string struct1_member5 = "Audit test", 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 struct1_member9 } struct test_struct2 { 1: list struct2_member1, 2: list struct2_member2, 3: list struct2_member3 = [23, 32 ], 4: list struct2_member4, 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:2, 3:4}, 2: map struct3_member2 = {10:1.1, 20:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1, 2: string struct5_member2 = "Thrift Audit Test" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base { test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/audit/thrift_audit_test.pl000066400000000000000000000213371420101504100212370ustar00rootroot00000000000000#!/usr/bin/perl -w # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #break1 - Thrift method removed from service base #break2 - Struct field changed in test_struct1(i16 to i32) #break3 - Struct field changed in test_struct1(enum1 to enum2) #break4 - Field type changed in test_struct1(bool to string) #break5- member field type changed in test_struct1(bool to list) #break6- Field type changed in test_struct2 (list to list) #break7 - requiredness removed in struct6 #break8 - requiredness addedd in struct5 #break9 - Struct field removed from struct1 #break10 - Struct field removed from struct2 id = 1 #break11 - Struct field removed from struct3 last id #break12 - derived1_function1 return type changed from enum1 to enum2 #break13 - derived1_function6 return type changed from struct1 to struct2 #break14 - derived1_function4 return type changed from string to double #break15 - derived2_function1 return type changed from list to list #break16 - derived2_function5 return type changed from map to map #break17 - derived2_function6 return type changed from map to map #break18- oneway removed from base_oneway #break19 - oneway added to base_function1 #break20 - first enum value removed from enum1 #break21- last enum value removed from enum2 #break22 - in-between enum value removed from enum1 #break23 - required struct field added to struct4 #break24 - removed inheritance of derived1. #break25 - changed inheritance of derived2. #break26 - Field type changed in base_function1 argument id=3 #break27 - argument changed base_function2 list to list id =8 #break28- derived1_function5 arguement type changed map to list #break29 - base_function2 arguemnt type changed list to string #break30- derived1_function6 argument changed struct1 to map #break31 - Exception removed to base_function2 #break32- Exception1 field type changed for id =1 #break33 - derived1_function1 exception type changed. #break34 - Field added to struct with Field ID being in between two existing field IDs #warning.thrift #Changing defaults #Id=1 struct5 #id=2 struct5 #id=4 struct2(list) #id=3 struct2(list default values removed) #id 4 struct1 change in double value #id 5 struct1 (default string value removed) #id=1 struct3 (change in map values) #id2 struct3 (change in map keys) #change in inheritance for derived1 and derived2 #change in struct field names #id9 struct1 #id2 struct2 use strict; use warnings; use Getopt::Std; # globals my $gArguments = ""; # arguments that will be passed to AuditTool my $gAuditToolPath = ""; my $gPreviousThriftPath; # previous thrift path my $gCurrentThriftPath; # current thrift path my $gThriftFileFolder; my $gBreakingFilesCount =34; my $gVerbose = 0; #functions sub auditBreakingChanges; sub auditNonBreakingChanges; main(); sub main { parseOptions(); auditBreakingChanges(); auditNonBreakingChanges(); } sub parseOptions { my %options = (); if ( getopts ('vf:o:t:',\%options) ) { # current (new) thrift folder if ($options{'f'}) { $gThriftFileFolder = $options{'f'}; $gPreviousThriftPath = $gThriftFileFolder."/test.thrift"; } else { die "Missing Folder containing thrift files\n"; } if($options{'t'}) { $gAuditToolPath = $options{'t'}; } else { die "Audit Tool Path required \n"; } if ($options{'v'}) { $gVerbose = 1; } } } sub auditBreakingChanges { my $breakingFileBaseName = $gThriftFileFolder."/break"; my $newThriftFile; for(my $i=1; $i <= $gBreakingFilesCount; $i++) { $newThriftFile = $breakingFileBaseName."$i.thrift"; my $arguments = $gPreviousThriftPath." ".$newThriftFile; my ($exitCode, $output) = callThriftAuditTool($arguments); print $output if $gVerbose eq 1; if($exitCode == 1) { # thrift_audit returns 1 when it is not able to find files or other non-audit failures print "exiting with exit code =1 i = ".$i."\n"; print $output; exit $exitCode; } if($exitCode != 2) { # thrift-audit return 2 for audit failures. So for Breaking changes we should get 2 as return value. print $output; die "\nTEST FAILURE: Breaking Change not detected for thrift file $newThriftFile, code=$exitCode \n"; } if(index($output,getMessageSubString("break$i")) == -1) { #Audit tool detected failure, but not the expected one. The change in breaking thrift file does not match getMessageSubString() print $output; die "\nTest FAILURE: Audit tool detected failure, but not the expected one!\n"; } else { #Thrift audit tool has detected audit failure and has returned exited to status code 2 print "Test Pass: Audit Failure detected for thrift file break$i.thrift \n"; } } } sub auditNonBreakingChanges { my $breakingFileBaseName = $gThriftFileFolder."/warning"; my $newThriftFile; $newThriftFile = $breakingFileBaseName.".thrift"; my $arguments = $gPreviousThriftPath." ".$newThriftFile; my ($exitCode, $output) = callThriftAuditTool($arguments); print $output if $gVerbose eq 1; if($exitCode == 1) { # thrift_audit returns 1 when it is not able to find files or other non-audit failures print "exiting with exit code = 1 for file warning.thrift\n"; exit $exitCode; } elsif($exitCode != 0) { # thrift-audit return 0 if there are no audit failures. die "\nTEST FAILURE: Non Breaking changes returned failure for thrift file $newThriftFile \n"; } else { #Thrift audit tool has exited with status 0. print "Test Pass: Audit tool exits with success for warnings \n"; } } # ----------------------------------------------------------------------------------------------------- # call thriftAuditTool script sub callThriftAuditTool ( $ ) { my $args = shift; my $command = "$gAuditToolPath --audit $args"; my $output = `$command 2>&1`; my $exitCode = $? >> 8; return ($exitCode,$output); } sub getMessageSubString( $ ) { my $fileName = shift; my %lookupTable = ( "break1" => "base_function3", "break2" => "test_struct1", "break3" => "test_struct1", "break4" => "test_struct1", "break5" => "test_struct1", "break6" => "test_struct2", "break7" => "test_struct6", "break8" => "test_struct5", "break9" => "test_struct1", "break10" => "test_struct2", "break11" => "test_struct3", "break12" => "derived1_function1", "break13" => "derived1_function6", "break14" => "derived1_function4", "break15" => "derived2_function1", "break16" => "derived2_function5", "break17" => "derived2_function6", "break18" => "base_oneway", "break19" => "base_function1", "break20" => "test_enum1", "break21" => "test_enum2", "break22" => "test_enum1", "break23" => "test_struct4", "break24" => "derived1", "break25" => "derived2", "break26" => "base_function1", "break27" => "base_function2_args", "break28" => "derived1_function5_args", "break29" => "base_function2_args", "break30" => "derived1_function6", "break31" => "base_function2_exception", "break32" => "test_exception1", "break33" => "derived1_function1_exception", "break34" => "test_struct3", ); if (not exists $lookupTable{ $fileName }) { print "in the null case\n"; return "NULL"; } my $retval = $lookupTable{ $fileName }; print "$fileName => $retval\n"; return $lookupTable{ $fileName }; } thrift-0.16.0/test/audit/warning.thrift000066400000000000000000000121461420101504100200420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ namespace cpp test //Constants const i32 const1 = 123; const double const2 = 23.2; const map const3 = {"hello":"class", "thrift":"audit"}; //Exception exception test_exception1 { 1: i32 code; 2: string json; } exception test_exception2 { 1: i32 code; 2: string json; } //Enums enum test_enum1 { enum1_value0 = 0, enum1_value1 = 1, enum1_value2 = 2, enum1_value5 = 5, enum1_value7 = 7, enum1_value8 = 8 } enum test_enum2 { enum2_value0 = 0, enum2_value1 = 1, enum2_value2 = 2, enum2_value3 = 3 } enum test_enum3 { enum3_value1 = 0, enum3_value2 = 1 } struct test_struct1 { 1: i16 struct1_member1, 2: i32 struct1_member2, 3: i64 struct1_member3, 4: double struct1_member4 = 2.4, 5: string struct1_member5, 6: bool struct1_member6, 7: byte struct1_member7, 8: binary struct1_member8, 9: test_enum1 changed19 } struct test_struct2 { 1: list struct2_member1, 2: list changed22, 3: list struct2_member3, 4: list struct2_member4 =[1.0, 2.1], 5: list struct2_member5, 6: list struct2_member6, 7: list struct2_member7, 8: list struct2_member8, 9: list struct2_member9 } struct test_struct3 { 1: map struct3_member1 = {1:10, 2:20}, 2: map struct3_member2 = {1:1.1, 2:2.1}, 3: map struct3_member3, 4: map struct3_member4, 5: map struct3_member5, 7: map struct3_member7 } struct test_struct4 { 1: i32 struct4_member1, 2: optional i32 struct4_member2 } struct test_struct5{ 1: double struct5_member1 = 1.1, 2: string struct5_member2 = "Thrift Audit Tess" } struct test_struct6 { 1: i32 struct6_member1, 2: required i32 struct6_member2 } service base { oneway void base_oneway( 1: i32 arg1), void base_function1( 1: i16 function1_arg1, 2: i32 function1_arg2, 3: i64 function1_arg3, 4: double function1_arg4, 5: string function1_arg5, 6: bool function1_arg6, 7: test_enum1 function1_arg7, 8: test_struct1 function1_arg8), void base_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5, 6: list function2_arg6, 7: list function2_arg7, 8: list function2_arg8, 9: list function2_arg9) throws (1:test_exception2 e), void base_function3(), } service derived1 extends base{ test_enum1 derived1_function1( 1: i64 function1_arg1, 2: double function1_arg2, 3: test_enum1 function1_arg3) throws (1:test_exception2 e), i64 derived1_function2( 1: list function2_arg1, 2: list function2_arg2, 3: list function2_arg3, 4: list function2_arg4, 5: list function2_arg5) throws (1:test_exception2 e), double derived1_function3( 1: string function3_arg1, 2: bool function3_arg2) throws (1:test_exception2 e), string derived1_function4( 1: string function4_arg1, 2: bool function4_arg2) throws (1:test_exception2 e), bool derived1_function5( 1: map function5_arg1, 2: map function5_arg2, 3: map function5_arg3) throws (1:test_exception2 e), test_struct1 derived1_function6( 1: double function6_arg1) throws (1:test_exception2 e), } service derived2 extends base { list derived2_function1( 1: i32 function1_arg1) throws (1:test_exception2 e), list derived2_function2( 1:i64 function2_arg2) throws (1:test_exception2 e), list derived2_function3( 1:double function3_arg1) throws(1:test_exception2 e), map derived2_function4( 1:string function4_arg1) throws(1:test_exception2 e), map derived2_function5( 1:bool function5_arg1) throws(1:test_exception2 e), map derived2_function6( 1:bool function6_arg1) throws(1:test_exception2 e), } thrift-0.16.0/test/c_glib/000077500000000000000000000000001420101504100152605ustar00rootroot00000000000000thrift-0.16.0/test/c_glib/CMakeLists.txt000066400000000000000000000045721420101504100200300ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Contains the thrift specific target_link_libraries include(ThriftMacros) find_package(GLIB REQUIRED COMPONENTS gobject) include_directories(SYSTEM "${GLIB_INCLUDE_DIR}") include_directories(SYSTEM "${GLIBCONFIG_INCLUDE_DIR}") #Make sure gen-c_glib files can be included include_directories("${CMAKE_CURRENT_BINARY_DIR}") include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-c_glib") include_directories("${PROJECT_SOURCE_DIR}/lib/c_glib/src") include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") set(crosstestgencglib_SOURCES gen-c_glib/t_test_second_service.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_thrift_test_types.h ) add_library(crosstestgencglib STATIC ${crosstestgencglib_SOURCES}) target_link_libraries(crosstestgencglib thrift_c_glib) if (WITH_ZLIB) target_link_libraries(crosstestgencglib thrift_c_glib_zlib) endif () add_executable(test_server src/test_server.c src/thrift_test_handler.c src/thrift_second_service_handler.c) target_link_libraries(test_server crosstestgencglib ${ZLIB_LIBRARIES}) add_executable(test_client src/test_client.c) target_link_libraries(test_client crosstestgencglib "${OPENSSL_LIBRARIES}") # # Common thrift code generation rules # add_custom_command(OUTPUT gen-c_glib/t_test_second_service.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_thrift_test_types.h COMMAND ${THRIFT_COMPILER} --gen c_glib -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift ) thrift-0.16.0/test/c_glib/Makefile.am000077500000000000000000000051311420101504100173170ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # AUTOMAKE_OPTIONS = subdir-objects serial-tests nostdinc noinst_LTLIBRARIES = libtestcglib.la nodist_libtestcglib_la_SOURCES = \ gen-c_glib/t_test_second_service.c \ gen-c_glib/t_test_second_service.h \ gen-c_glib/t_test_thrift_test.c \ gen-c_glib/t_test_thrift_test.h \ gen-c_glib/t_test_thrift_test_types.c \ gen-c_glib/t_test_thrift_test_types.h libtestcglib_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la precross: libtestcglib.la test_client test_server check_PROGRAMS = \ test_client \ test_server test_client_SOURCES = \ src/test_client.c test_client_LDADD = \ libtestcglib.la \ $(top_builddir)/lib/c_glib/libthrift_c_glib.la test_server_SOURCES = \ src/thrift_test_handler.c \ src/thrift_test_handler.h \ src/thrift_second_service_handler.c \ src/thrift_second_service_handler.h \ src/test_server.c test_server_LDADD = \ libtestcglib.la \ $(top_builddir)/lib/c_glib/libthrift_c_glib.la # # Common thrift code generation rules # gen-c_glib/t_test_second_service.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_thrift_test_types.h: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) $(THRIFT) --gen c_glib -r $< AM_CFLAGS = -g -Wall -Wextra $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) AM_CXXFLAGS = $(AM_CFLAGS) AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib -I$(top_builddir)/lib/c_glib/src/thrift AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@ clean-local: $(RM) -r gen-c_glib/ $(RM) test_client $(RM) test_server $(RM) libtestcglib.la find . -type f -iname "*.o" | xargs rm -f dist-hook: $(RM) -r $(distdir)/gen-c_glib/ $(RM) $(distdir)/test_client $(RM) $(distdir)/test_server $(RM) $(distdir)/libtestcglib.la find $(distdir) -type f -iname "*.o" | xargs rm -f EXTRA_DIST = \ src thrift-0.16.0/test/c_glib/src/000077500000000000000000000000001420101504100160475ustar00rootroot00000000000000thrift-0.16.0/test/c_glib/src/test_client.c000066400000000000000000001643741420101504100205470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../gen-c_glib/t_test_second_service.h" #include "../gen-c_glib/t_test_thrift_test.h" /* Handle SIGPIPE signals (indicating the server has closed the connection prematurely) by outputting an error message before exiting. */ static void sigpipe_handler (int signal_number) { THRIFT_UNUSED_VAR (signal_number); /* Flush standard output to make sure the test results so far are logged */ fflush (stdout); fputs ("Broken pipe (server closed connection prematurely)\n", stderr); fflush (stderr); /* Re-raise the signal, this time invoking the default signal handler, to terminate the program */ raise (SIGPIPE); } /* Compare two gint32 values. Used for sorting and finding integer values within a GList. */ static gint gint32_compare (gconstpointer a, gconstpointer b) { gint32 int32_a = *(gint32 *)a; gint32 int32_b = *(gint32 *)b; int result = 0; if (int32_a < int32_b) result = -1; else if (int32_a > int32_b) result = 1; return result; } int main (int argc, char **argv) { static gchar * host = NULL; static gint port = 9090; static gchar * path = NULL; static gboolean ssl = FALSE; static gchar * transport_option = NULL; static gchar * protocol_option = NULL; static gint num_tests = 1; static GOptionEntry option_entries[] ={ { "host", 'h', 0, G_OPTION_ARG_STRING, &host, "Host to connect (=localhost)", NULL }, { "port", 'p', 0, G_OPTION_ARG_INT, &port, "Port number to connect (=9090)", NULL }, { "domain-socket", 0, 0, G_OPTION_ARG_STRING, &path, "Unix socket domain path to connect", NULL }, { "ssl", 's', 0, G_OPTION_ARG_NONE, &ssl, "Enable SSL", NULL }, { "transport", 't', 0, G_OPTION_ARG_STRING, &transport_option, "Transport: buffered, framed (=buffered)", NULL }, { "protocol", 'r', 0, G_OPTION_ARG_STRING, &protocol_option, "Protocol: binary, compact, multi, multic (=binary)", NULL }, { "testloops", 'n', 0, G_OPTION_ARG_INT, &num_tests, "Number of tests (=1)", NULL }, { NULL } }; struct sigaction sigpipe_action; GType socket_type = THRIFT_TYPE_SOCKET; gchar *socket_name = "ip"; GType transport_type = THRIFT_TYPE_BUFFERED_TRANSPORT; gchar *transport_name = "buffered"; GType protocol_type = THRIFT_TYPE_BINARY_PROTOCOL; gchar *protocol_name = "binary"; ThriftSocket *socket = NULL; ThriftTransport *transport = NULL; ThriftProtocol *protocol = NULL; ThriftProtocol *protocol2 = NULL; // for multiplexed tests ThriftProtocol *multiplexed_protocol = NULL; TTestThriftTestIf *test_client = NULL; TTestSecondServiceIf *second_service = NULL; // for multiplexed tests struct timeval time_start, time_stop, time_elapsed; guint64 time_elapsed_usec, time_total_usec = 0; guint64 time_min_usec = G_MAXUINT64, time_max_usec = 0, time_avg_usec; GOptionContext *option_context; gboolean options_valid = TRUE; int test_num = 0; int fail_count = 0; GError *error = NULL; #if (!GLIB_CHECK_VERSION (2, 36, 0)) g_type_init (); #endif /* Configure and parse our command-line options */ option_context = g_option_context_new (NULL); g_option_context_add_main_entries (option_context, option_entries, NULL); if (!g_option_context_parse (option_context, &argc, &argv, &error)) { fprintf (stderr, "%s\n", error->message); g_clear_error (&error); g_option_context_free (option_context); return 255; } g_option_context_free (option_context); /* Set remaining default values for unspecified options */ if (host == NULL) host = g_strdup ("localhost"); /* Validate the parsed options */ if (protocol_option != NULL) { if (strncmp (protocol_option, "compact", 8) == 0) { protocol_type = THRIFT_TYPE_COMPACT_PROTOCOL; protocol_name = "compact"; } else if (strncmp (protocol_option, "multi", 6) == 0) { protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL; protocol_name = "binary:multi"; } else if (strncmp (protocol_option, "multic", 7) == 0) { protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL; protocol_name = "compact:multic"; } else if (strncmp (protocol_option, "binary", 7) == 0) { printf("We are going with default protocol\n"); } else { fprintf (stderr, "Unknown protocol type %s\n", protocol_option); options_valid = FALSE; } } if (transport_option != NULL) { if (strncmp (transport_option, "framed", 7) == 0) { transport_type = THRIFT_TYPE_FRAMED_TRANSPORT; transport_name = "framed"; } else if (strncmp (transport_option, "buffered", 9) != 0) { fprintf (stderr, "Unknown transport type %s\n", transport_option); options_valid = FALSE; } } if (ssl) { socket_type = THRIFT_TYPE_SSL_SOCKET; socket_name = "ip-ssl"; printf("Type name %s\n", g_type_name (socket_type)); } if (!options_valid) return 254; if (path) { printf ("Connecting (%s/%s) to: %s/%s\n", transport_name, protocol_name, socket_name, path); } else { printf ("Connecting (%s/%s) to: %s/%s:%d\n", transport_name, protocol_name, socket_name, host, port); } /* Install our SIGPIPE handler, which outputs an error message to standard error before exiting so testers can know what happened */ memset (&sigpipe_action, 0, sizeof (sigpipe_action)); sigpipe_action.sa_handler = sigpipe_handler; sigpipe_action.sa_flags = SA_RESETHAND; sigaction (SIGPIPE, &sigpipe_action, NULL); if (ssl) { thrift_ssl_socket_initialize_openssl(); } /* Establish all our connection objects */ if (path) { socket = g_object_new (socket_type, "path", path, NULL); } else { socket = g_object_new (socket_type, "hostname", host, "port", port, NULL); } if (ssl && !thrift_ssl_load_cert_from_file(THRIFT_SSL_SOCKET(socket), "../keys/CA.pem")) { fprintf(stderr, "Unable to load validation certificate ../keys/CA.pem - did you run in the test/c_glib directory?\n"); g_clear_object (&socket); return 253; } transport = g_object_new (transport_type, "transport", socket, NULL); if (protocol_type == THRIFT_TYPE_MULTIPLEXED_PROTOCOL) { // TODO: A multiplexed test should also test "Second" (see Java TestServer) // The context comes from the name of the thrift file. If multiple thrift // schemas are used we have to redo the way this is done. if (strncmp(protocol_name, "binary:", 7) == 0) { multiplexed_protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL); } else if (strncmp(protocol_name, "compact:", 8) == 0) { multiplexed_protocol = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport", transport, NULL); } else { fprintf(stderr, "Unknown multiplex protocol name: %s\n", protocol_name); g_clear_object (&transport); g_clear_object (&socket); return 252; } protocol = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROTOCOL, "transport", transport, "protocol", multiplexed_protocol, "service-name", "ThriftTest", NULL);; if (NULL == protocol) { g_clear_object (&multiplexed_protocol); g_clear_object (&transport); g_clear_object (&socket); return 251; } // Make a second protocol and client running on the same multiplexed transport protocol2 = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROTOCOL, "transport", transport, "protocol", multiplexed_protocol, "service-name", "SecondService", NULL); second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_CLIENT, "input_protocol", protocol2, "output_protocol", protocol2, NULL); }else{ protocol = g_object_new (protocol_type, "transport", transport, NULL); } test_client = g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT, "input_protocol", protocol, "output_protocol", protocol, NULL); /* Execute the actual tests */ for (test_num = 0; test_num < num_tests; ++test_num) { if (thrift_transport_open (transport, &error)) { gchar *string = NULL; gboolean boolean = 0; gint8 byte = 0; gint32 int32 = 0; gint64 int64 = 0; gdouble dub = 0; gint byte_thing, i32_thing, inner_byte_thing, inner_i32_thing; gint64 i64_thing, inner_i64_thing; TTestXtruct *xtruct_out, *xtruct_out2, *xtruct_in, *inner_xtruct_in; TTestXtruct2 *xtruct2_out, *xtruct2_in; GHashTable *map_out, *map_in, *inner_map_in; GHashTable *set_out, *set_in; gpointer key, value; gint32 *i32_key_ptr, *i32_value_ptr; GHashTableIter hash_table_iter, inner_hash_table_iter; GList *keys_out, *keys_in, *keys_elem; GArray *list_out, *list_in; TTestNumberz numberz; TTestNumberz numberz2; TTestUserId user_id, *user_id_ptr, *user_id_ptr2; TTestInsanity *insanity_out, *insanity_in; GHashTable *user_map; GHashTableIter user_map_iter; GPtrArray *xtructs; TTestXception *xception = NULL; TTestXception2 *xception2 = NULL; gboolean oneway_result; struct timeval oneway_start, oneway_end, oneway_elapsed; gint oneway_elapsed_usec; gboolean first; gint32 i, j; if (path) { printf ("Test #%d, connect %s\n", test_num + 1, path); } else { printf ("Test #%d, connect %s:%d\n", test_num + 1, host, port); } gettimeofday (&time_start, NULL); /* These test routines have been ported from the C++ test client, care being taken to ensure their output remains as close as possible to the original to facilitate diffs. For simplicity comments have been omitted, but every routine has the same basic structure: - Create and populate data structures as necessary. - Format and output (to the console) a representation of the outgoing data. - Issue the remote method call to the server. - Format and output a representation of the returned data. - Verify the returned data matches what was expected. - Deallocate any created data structures. Note the recognized values and expected behaviour of each remote method are described in ThriftTest.thrift, which you'll find in the top-level "test" folder. */ /** * VOID TEST */ printf ("testVoid()"); if (t_test_thrift_test_if_test_void (test_client, &error)) { printf (" = void\n"); } else { if(error!=NULL){ printf ("%s\n", error->message); g_error_free (error); error = NULL; } fail_count++; } /** * STRING TEST */ printf ("testString(\"Test\")"); if (t_test_thrift_test_if_test_string (test_client, &string, "Test", &error)) { printf (" = \"%s\"\n", string); if (strncmp (string, "Test", 5) != 0) fail_count++; g_free (string); string = NULL; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * Multiplexed Test - do this right in the middle of the normal Test Client run */ if (second_service) { printf ("testSecondServiceMultiplexSecondTestString(\"2nd\")"); if (t_test_second_service_if_secondtest_string (second_service, &string, "2nd", &error)) { printf (" = \"%s\"\n", string); if (strcmp (string, "testString(\"2nd\")") != 0) { ++fail_count; } g_free (string); string = NULL; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; ++fail_count; } } /** * BOOL TEST */ printf ("testByte(true)"); if (t_test_thrift_test_if_test_bool (test_client, &boolean, 1, &error)) { printf (" = %s\n", boolean ? "true" : "false"); if (boolean != 1) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } printf ("testByte(false)"); if (t_test_thrift_test_if_test_bool (test_client, &boolean, 0, &error)) { printf (" = %s\n", boolean ? "true" : "false"); if (boolean != 0) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * BYTE TEST */ printf ("testByte(1)"); if (t_test_thrift_test_if_test_byte (test_client, &byte, 1, &error)) { printf (" = %d\n", byte); if (byte != 1) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } printf ("testByte(-1)"); if (t_test_thrift_test_if_test_byte (test_client, &byte, -1, &error)) { printf (" = %d\n", byte); if (byte != -1) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * I32 TEST */ printf ("testI32(-1)"); if (t_test_thrift_test_if_test_i32 (test_client, &int32, -1, &error)) { printf (" = %d\n", int32); if (int32 != -1) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * I64 TEST */ printf ("testI64(-34359738368)"); if (t_test_thrift_test_if_test_i64 (test_client, &int64, (gint64)-34359738368, &error)) { printf (" = %" PRId64 "\n", int64); if (int64 != (gint64)-34359738368) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * DOUBLE TEST */ printf("testDouble(-5.2098523)"); if (t_test_thrift_test_if_test_double (test_client, &dub, -5.2098523, &error)) { printf (" = %f\n", dub); if ((dub - (-5.2098523)) > 0.001) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * BINARY TEST */ printf ("testBinary(empty)"); GByteArray *emptyArray = g_byte_array_new(); GByteArray *result = NULL; if (t_test_thrift_test_if_test_binary (test_client, &result, emptyArray, &error)) { GBytes *response = g_byte_array_free_to_bytes(result); // frees result result = NULL; gsize siz = g_bytes_get_size(response); if (siz == 0) { printf(" = empty\n"); } else { printf(" = not empty (%ld bytes)\n", (long)siz); ++fail_count; } g_bytes_unref(response); } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_byte_array_unref(emptyArray); emptyArray = NULL; // TODO: add testBinary() with data printf ("testBinary([-128..127]) = {"); const signed char bin_data[256] = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}; GByteArray *fullArray = g_byte_array_new(); g_byte_array_append(fullArray, (guint8 *)(&bin_data[0]), 256); if (t_test_thrift_test_if_test_binary (test_client, &result, fullArray, &error)) { GBytes *response = g_byte_array_free_to_bytes(result); // frees result result = NULL; gsize siz = g_bytes_get_size(response); gconstpointer ptr = g_bytes_get_data(response, &siz); if (siz == 256) { gboolean first = 1; gboolean failed = 0; int i; for (i = 0; i < 256; ++i) { if (!first) printf(","); else first = 0; int val = ((signed char *)ptr)[i]; printf("%d", val); if (!failed && val != i - 128) { failed = 1; } } printf("} "); if (failed) { printf("FAIL (bad content) size %ld OK\n", (long)siz); ++fail_count; } else { printf("OK size %ld OK\n", (long)siz); } } else { printf(" = bad size %ld\n", (long)siz); ++fail_count; } g_bytes_unref(response); } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_byte_array_unref(fullArray); fullArray = NULL; /** * STRUCT TEST */ printf ("testStruct({\"Zero\", 1, -3, -5})"); xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT, "string_thing", "Zero", "byte_thing", 1, "i32_thing", -3, "i64_thing", -5LL, NULL); xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); if (t_test_thrift_test_if_test_struct (test_client, &xtruct_in, xtruct_out, &error)) { g_object_get (xtruct_in, "string_thing", &string, "byte_thing", &byte_thing, "i32_thing", &i32_thing, "i64_thing", &i64_thing, NULL); printf (" = {\"%s\", %d, %d, %" PRId64 "}\n", string, byte_thing, i32_thing, i64_thing); if ((string == NULL || strncmp (string, "Zero", 5) != 0) || byte_thing != 1 || i32_thing != -3 || i64_thing != (gint64)-5) fail_count++; if (string) { g_free (string); string = NULL; } } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } // g_clear_object(&xtruct_out); used below g_clear_object(&xtruct_in); /** * NESTED STRUCT TEST */ printf ("testNest({1, {\"Zero\", 1, -3, -5}), 5}"); xtruct2_out = g_object_new (T_TEST_TYPE_XTRUCT2, "byte_thing", 1, "struct_thing", xtruct_out, "i32_thing", 5, NULL); xtruct2_in = g_object_new (T_TEST_TYPE_XTRUCT2, NULL); if (t_test_thrift_test_if_test_nest (test_client, &xtruct2_in, xtruct2_out, &error)) { g_object_get (xtruct2_in, "byte_thing", &byte_thing, "struct_thing", &xtruct_in, "i32_thing", &i32_thing, NULL); g_object_get (xtruct_in, "string_thing", &string, "byte_thing", &inner_byte_thing, "i32_thing", &inner_i32_thing, "i64_thing", &inner_i64_thing, NULL); printf (" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n", byte_thing, string, inner_byte_thing, inner_i32_thing, inner_i64_thing, i32_thing); if (byte_thing != 1 || (string == NULL || strncmp (string, "Zero", 5) != 0) || inner_byte_thing != 1 || inner_i32_thing != -3 || inner_i64_thing != (gint64)-5 || i32_thing != 5) fail_count++; if (string) { g_free(string); string = NULL; } } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_clear_object(&xtruct_in); g_clear_object(&xtruct2_in); g_clear_object(&xtruct2_out); g_clear_object(&xtruct_out); /** * MAP TEST */ map_out = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free); for (i = 0; i < 5; ++i) { i32_key_ptr = g_malloc (sizeof *i32_key_ptr); i32_value_ptr = g_malloc (sizeof *i32_value_ptr); *i32_key_ptr = i; *i32_value_ptr = i - 10; g_hash_table_insert (map_out, i32_key_ptr, i32_value_ptr); } printf ("testMap({"); first = TRUE; g_hash_table_iter_init (&hash_table_iter, map_out); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { if (first) first = FALSE; else printf (", "); printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); } printf ("})"); map_in = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free); if (t_test_thrift_test_if_test_map (test_client, &map_in, map_out, &error)) { printf (" = {"); first = TRUE; g_hash_table_iter_init (&hash_table_iter, map_in); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { if (first) first = FALSE; else printf (", "); printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); } printf ("}\n"); if (g_hash_table_size (map_in) != g_hash_table_size (map_out)) fail_count++; else { g_hash_table_iter_init (&hash_table_iter, map_out); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { gpointer in_value = g_hash_table_lookup (map_in, key); if (in_value == NULL || *(gint32 *)in_value != *(gint32 *)value) { fail_count++; break; } } } } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_hash_table_unref (map_in); g_hash_table_unref (map_out); /** * STRING MAP TEST */ map_out = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert (map_out, "a", "2"); g_hash_table_insert (map_out, "b", "blah"); g_hash_table_insert (map_out, "some", "thing"); printf ("testStringMap({"); first = TRUE; g_hash_table_iter_init (&hash_table_iter, map_out); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { if (first) first = FALSE; else printf (", "); printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value); } printf (")}"); map_in = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); if (t_test_thrift_test_if_test_string_map (test_client, &map_in, map_out, &error)) { printf (" = {"); first = TRUE; g_hash_table_iter_init (&hash_table_iter, map_in); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { if (first) first = FALSE; else printf (", "); printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value); } printf ("}\n"); if (g_hash_table_size (map_in) != g_hash_table_size (map_out)) fail_count++; else { g_hash_table_iter_init (&hash_table_iter, map_out); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { gpointer in_value = g_hash_table_lookup (map_in, key); if (in_value == NULL || strcmp ((gchar *)in_value, (gchar *)value) != 0) { fail_count++; break; } } } } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_hash_table_unref (map_in); g_hash_table_unref (map_out); /** * SET TEST */ set_out = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); for (i = -2; i < 3; ++i) { i32_key_ptr = g_malloc (sizeof *i32_key_ptr); *i32_key_ptr = i; g_hash_table_insert (set_out, i32_key_ptr, NULL); } printf ("testSet({"); first = TRUE; keys_out = g_hash_table_get_keys (set_out); keys_elem = keys_out; while (keys_elem != NULL) { if (first) first = FALSE; else printf (", "); printf ("%d", *(gint32 *)keys_elem->data); keys_elem = keys_elem->next; } printf ("})"); set_in = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); if (t_test_thrift_test_if_test_set (test_client, &set_in, set_out, &error)) { printf(" = {"); first = TRUE; keys_in = g_hash_table_get_keys (set_in); keys_elem = keys_in; while (keys_elem != NULL) { if (first) first = FALSE; else printf (", "); printf ("%d", *(gint32 *)keys_elem->data); keys_elem = keys_elem->next; } printf ("}\n"); if (g_list_length (keys_in) != g_list_length (keys_out)) fail_count++; else { keys_elem = keys_out; while (keys_elem != NULL) { if (g_list_find_custom (keys_in, keys_elem->data, gint32_compare) == NULL) { fail_count++; break; } keys_elem = keys_elem->next; } } g_list_free (keys_in); } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_hash_table_unref (set_in); g_list_free (keys_out); g_hash_table_unref (set_out); /** * LIST TEST */ list_out = g_array_new (FALSE, TRUE, sizeof (gint32)); for (i = -2; i < 3; ++i) { g_array_append_val (list_out, i); } printf ("testList({"); first = TRUE; for (i = 0; i < (gint32)list_out->len; ++i) { if (first) first = FALSE; else printf (", "); printf ("%d", g_array_index (list_out, gint32, i)); } printf ("})"); list_in = g_array_new (FALSE, TRUE, sizeof (gint32)); if (t_test_thrift_test_if_test_list (test_client, &list_in, list_out, &error)) { printf (" = {"); first = TRUE; for (i = 0; i < (gint32)list_in->len; ++i) { if (first) first = FALSE; else printf (", "); printf ("%d", g_array_index (list_in, gint32, i)); } printf ("}\n"); if (list_in->len != list_out->len || memcmp (list_in->data, list_out->data, list_in->len * sizeof (gint32)) != 0) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_array_unref (list_in); g_array_unref (list_out); /** * ENUM TEST */ printf("testEnum(ONE)"); if (t_test_thrift_test_if_test_enum (test_client, &numberz, T_TEST_NUMBERZ_ONE, &error)) { printf(" = %d\n", numberz); if (numberz != T_TEST_NUMBERZ_ONE) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } printf("testEnum(TWO)"); if (t_test_thrift_test_if_test_enum (test_client, &numberz, T_TEST_NUMBERZ_TWO, &error)) { printf(" = %d\n", numberz); if (numberz != T_TEST_NUMBERZ_TWO) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } printf("testEnum(THREE)"); if (t_test_thrift_test_if_test_enum (test_client, &numberz, T_TEST_NUMBERZ_THREE, &error)) { printf(" = %d\n", numberz); if (numberz != T_TEST_NUMBERZ_THREE) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } printf("testEnum(FIVE)"); if (t_test_thrift_test_if_test_enum (test_client, &numberz, T_TEST_NUMBERZ_FIVE, &error)) { printf(" = %d\n", numberz); if (numberz != T_TEST_NUMBERZ_FIVE) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } printf("testEnum(EIGHT)"); if (t_test_thrift_test_if_test_enum (test_client, &numberz, T_TEST_NUMBERZ_EIGHT, &error)) { printf(" = %d\n", numberz); if (numberz != T_TEST_NUMBERZ_EIGHT) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * TYPEDEF TEST */ printf ("testTypedef(309858235082523)"); if (t_test_thrift_test_if_test_typedef (test_client, &user_id, 309858235082523LL, &error)) { printf(" = %" PRId64 "\n", user_id); if (user_id != 309858235082523LL) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * NESTED MAP TEST */ printf ("testMapMap(1)"); map_in = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, (GDestroyNotify)g_hash_table_unref); if (t_test_thrift_test_if_test_map_map (test_client, &map_in, 1, &error)) { g_hash_table_iter_init (&hash_table_iter, map_in); printf (" = {"); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { printf ("%d => {", *(gint32 *)key); g_hash_table_iter_init (&inner_hash_table_iter, (GHashTable *)value); while (g_hash_table_iter_next (&inner_hash_table_iter, &key, &value)) { printf ("%d => %d, ", *(gint32 *)key, *(gint32 *)value); } printf ("}, "); } printf ("}\n"); if (g_hash_table_size (map_in) != 2) fail_count++; else { gint32 inner_keys[] = {1, 2, 3, 4}; gint32 i32_key; i32_key = -4; inner_map_in = g_hash_table_lookup (map_in, &i32_key); if (inner_map_in == NULL || g_hash_table_size (inner_map_in) != 4) fail_count++; else { keys_in = g_hash_table_get_keys (inner_map_in); keys_in = g_list_sort (keys_in, gint32_compare); for (i = 0; i < 4; i++) { keys_elem = g_list_nth (keys_in, 3 - i); if (*(gint32 *)keys_elem->data != (-1 * inner_keys[i]) || *(gint32 *)g_hash_table_lookup (inner_map_in, keys_elem->data) != (-1 * inner_keys[i])) { fail_count++; break; } } g_list_free (keys_in); } i32_key = 4; inner_map_in = g_hash_table_lookup (map_in, &i32_key); if (inner_map_in == NULL || g_hash_table_size (inner_map_in) != 4) fail_count++; else { keys_in = g_hash_table_get_keys (inner_map_in); keys_in = g_list_sort (keys_in, gint32_compare); for (i = 0; i < 4; i++) { keys_elem = g_list_nth (keys_in, i); if (*(gint32 *)keys_elem->data != inner_keys[i] || *(gint32 *)g_hash_table_lookup (inner_map_in, keys_elem->data) != inner_keys[i]) { fail_count++; break; } } g_list_free (keys_in); } } } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_hash_table_unref (map_in); /** * INSANITY TEST */ insanity_out = g_object_new (T_TEST_TYPE_INSANITY, NULL); g_object_get (insanity_out, "userMap", &user_map, "xtructs", &xtructs, NULL); numberz = T_TEST_NUMBERZ_FIVE; numberz2 = T_TEST_NUMBERZ_EIGHT; user_id_ptr = g_malloc (sizeof *user_id_ptr); *user_id_ptr = 5; user_id_ptr2 = g_malloc (sizeof *user_id_ptr); *user_id_ptr2 = 8; g_hash_table_insert (user_map, (gpointer)numberz, user_id_ptr); g_hash_table_insert (user_map, (gpointer)numberz2, user_id_ptr2); g_hash_table_unref (user_map); xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT, "string_thing", "Hello2", "byte_thing", 2, "i32_thing", 2, "i64_thing", 2LL, NULL); xtruct_out2 = g_object_new (T_TEST_TYPE_XTRUCT, "string_thing", "Goodbye4", "byte_thing", 4, "i32_thing", 4, "i64_thing", 4LL, NULL); g_ptr_array_add (xtructs, xtruct_out2); g_ptr_array_add (xtructs, xtruct_out); g_ptr_array_unref (xtructs); map_in = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, (GDestroyNotify)g_hash_table_unref); printf("testInsanity()"); if (t_test_thrift_test_if_test_insanity (test_client, &map_in, insanity_out, &error)) { printf (" = {"); g_hash_table_iter_init (&hash_table_iter, map_in); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { printf ("%" PRId64 " => {", *(TTestUserId *)key); g_hash_table_iter_init (&inner_hash_table_iter, (GHashTable *)value); while (g_hash_table_iter_next (&inner_hash_table_iter, &key, &value)) { printf ("%d => {", (TTestNumberz)key); g_object_get ((TTestInsanity *)value, "userMap", &user_map, "xtructs", &xtructs, NULL); printf ("{"); g_hash_table_iter_init (&user_map_iter, user_map); while (g_hash_table_iter_next (&user_map_iter, &key, &value)) { printf ("%d => %" PRId64 ", ", (TTestNumberz)key, *(TTestUserId *)value); } printf ("}, "); g_hash_table_unref (user_map); printf("{"); for (i = 0; i < (gint32)xtructs->len; ++i) { xtruct_in = g_ptr_array_index (xtructs, i); g_object_get (xtruct_in, "string_thing", &string, "byte_thing", &byte_thing, "i32_thing", &i32_thing, "i64_thing", &i64_thing, NULL); printf ("{\"%s\", %d, %d, %" PRId64 "}, ", string, byte_thing, i32_thing, i64_thing); if (string != NULL) g_free (string); } printf ("}"); g_ptr_array_unref (xtructs); printf ("}, "); } printf("}, "); } printf("}\n"); if (g_hash_table_size (map_in) != 2) fail_count++; else { TTestNumberz numberz_key_values[] = { T_TEST_NUMBERZ_TWO, T_TEST_NUMBERZ_THREE }; gint user_map_values[] = { 5, 8 }; TTestUserId user_id_key; user_id_key = 1; inner_map_in = g_hash_table_lookup (map_in, &user_id_key); if (inner_map_in == NULL || g_hash_table_size (inner_map_in) != 2) fail_count++; else { TTestNumberz numberz_key; for (i = 0; i < 2; ++i) { numberz_key = numberz_key_values[i]; insanity_in = g_hash_table_lookup (inner_map_in, (gconstpointer)numberz_key); if (insanity_in == NULL) fail_count++; else { g_object_get (insanity_in, "userMap", &user_map, "xtructs", &xtructs, NULL); if (user_map == NULL) fail_count++; else { if (g_hash_table_size (user_map) != 2) fail_count++; else { for (j = 0; j < 2; ++j) { numberz_key = (TTestNumberz)user_map_values[j]; value = g_hash_table_lookup (user_map, (gconstpointer)numberz_key); if (value == NULL || *(TTestUserId *)value != (TTestUserId)user_map_values[j]) fail_count++; } } g_hash_table_unref (user_map); } if (xtructs == NULL) fail_count++; else { if (xtructs->len != 2) fail_count++; else { xtruct_in = g_ptr_array_index (xtructs, 0); g_object_get (xtruct_in, "string_thing", &string, "byte_thing", &byte_thing, "i32_thing", &i32_thing, "i64_thing", &i64_thing, NULL); if ((string == NULL || strncmp (string, "Goodbye4", 9) != 0) || byte_thing != 4 || i32_thing != 4 || i64_thing != 4) fail_count++; if (string != NULL) g_free (string); xtruct_in = g_ptr_array_index (xtructs, 1); g_object_get (xtruct_in, "string_thing", &string, "byte_thing", &byte_thing, "i32_thing", &i32_thing, "i64_thing", &i64_thing, NULL); if ((string == NULL || strncmp (string, "Hello2", 7) != 0) || byte_thing != 2 || i32_thing != 2 || i64_thing != 2) fail_count++; if (string != NULL) g_free (string); } g_ptr_array_unref (xtructs); } } } } user_id_key = 2; inner_map_in = g_hash_table_lookup (map_in, &user_id_key); if (inner_map_in == NULL || g_hash_table_size (inner_map_in) != 1) fail_count++; else { insanity_in = g_hash_table_lookup (inner_map_in, (gconstpointer)T_TEST_NUMBERZ_SIX); if (insanity_in == NULL) fail_count++; else { g_object_get (insanity_in, "userMap", &user_map, "xtructs", &xtructs, NULL); if (user_map == NULL) fail_count++; else { if (g_hash_table_size (user_map) != 0) fail_count++; g_hash_table_unref (user_map); } if (xtructs == NULL) fail_count++; else { if (xtructs->len != 0) fail_count++; g_ptr_array_unref (xtructs); } } } } } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } g_hash_table_unref (map_in); g_clear_object (&insanity_out); /* test exception */ printf ("testClient.testException(\"Xception\") =>"); if (!t_test_thrift_test_if_test_exception (test_client, "Xception", &xception, &error) && xception != NULL) { g_object_get (xception, "errorCode", &int32, "message", &string, NULL); printf (" {%u, \"%s\"}\n", int32, string); g_free (string); g_clear_object (&xception); g_error_free (error); error = NULL; } else { printf (" void\nFAILURE\n"); fail_count++; if (xception != NULL) { g_object_unref (xception); xception = NULL; } if (error != NULL) { g_error_free (error); error = NULL; } } printf ("testClient.testException(\"TException\") =>"); if (!t_test_thrift_test_if_test_exception (test_client, "TException", &xception, &error) && xception == NULL && error != NULL) { printf (" Caught TException\n"); g_error_free (error); error = NULL; } else { printf (" void\nFAILURE\n"); fail_count++; g_clear_object (&xception); if (error != NULL) { g_error_free (error); error = NULL; } } printf ("testClient.testException(\"success\") =>"); if (t_test_thrift_test_if_test_exception (test_client, "success", &xception, &error)) printf (" void\n"); else { printf (" void\nFAILURE\n"); fail_count++; g_clear_object (&xception); g_error_free (error); error = NULL; } g_assert (error == NULL); /* test multi exception */ printf ("testClient.testMultiException(\"Xception\", \"test 1\") =>"); xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); if (!t_test_thrift_test_if_test_multi_exception (test_client, &xtruct_in, "Xception", "test 1", &xception, &xception2, &error) && xception != NULL && xception2 == NULL) { g_object_get (xception, "errorCode", &int32, "message", &string, NULL); printf (" {%u, \"%s\"}\n", int32, string); g_free (string); g_object_unref (xception); xception = NULL; g_error_free (error); error = NULL; } else { printf (" result\nFAILURE\n"); fail_count++; g_clear_object (&xception); g_clear_object (&xception2); if (error != NULL) { g_error_free (error); error = NULL; } } g_object_unref (xtruct_in); printf ("testClient.testMultiException(\"Xception2\", \"test 2\") =>"); xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); if (!t_test_thrift_test_if_test_multi_exception (test_client, &xtruct_in, "Xception2", "test 2", &xception, &xception2, &error) && xception == NULL && xception2 != NULL) { g_object_get (xception2, "errorCode", &int32, "struct_thing", &inner_xtruct_in, NULL); g_object_get (inner_xtruct_in, "string_thing", &string, NULL); printf (" {%u, {\"%s\"}}\n", int32, string); g_free (string); g_clear_object (&inner_xtruct_in); g_clear_object (&xception2); g_error_free (error); error = NULL; } else { printf (" result\nFAILURE\n"); fail_count++; g_clear_object (&xception); g_clear_object (&xception2); if (error != NULL) { g_error_free (error); error = NULL; } } g_clear_object (&xtruct_in); printf ("testClient.testMultiException(\"success\", \"test 3\") =>"); xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); if (t_test_thrift_test_if_test_multi_exception (test_client, &xtruct_in, "success", "test 3", &xception, &xception2, &error) && xception == NULL && xception2 == NULL) { g_object_get (xtruct_in, "string_thing", &string, NULL); printf (" {{\"%s\"}}\n", string); g_free (string); } else { printf (" result\nFAILURE\n"); fail_count++; g_clear_object (&xception); g_clear_object (&xception2); if (error != NULL) { g_error_free (error); error = NULL; } } g_clear_object (&xtruct_in); /* test oneway void */ printf ("testClient.testOneway(1) =>"); gettimeofday (&oneway_start, NULL); oneway_result = t_test_thrift_test_if_test_oneway (test_client, 1, &error); gettimeofday (&oneway_end, NULL); timersub (&oneway_end, &oneway_start, &oneway_elapsed); oneway_elapsed_usec = oneway_elapsed.tv_sec * 1000 * 1000 + oneway_elapsed.tv_usec; if (oneway_result) { if (oneway_elapsed_usec > 200 * 1000) { printf (" FAILURE - took %.2f ms\n", (double)oneway_elapsed_usec / 1000.0); fail_count++; } else printf (" success - took %.2f ms\n", (double)oneway_elapsed_usec / 1000.0); } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } /** * redo a simple test after the oneway to make sure we aren't "off by * one" -- if the server treated oneway void like normal void, this next * test will fail since it will get the void confirmation rather than * the correct result. In this circumstance, the client will receive the * error: * * application error: Wrong method name */ /** * I32 TEST */ printf ("re-test testI32(-1)"); if (t_test_thrift_test_if_test_i32 (test_client, &int32, -1, &error)) { printf (" = %d\n", int32); if (int32 != -1) fail_count++; } else { printf ("%s\n", error->message); g_error_free (error); error = NULL; fail_count++; } gettimeofday (&time_stop, NULL); timersub (&time_stop, &time_start, &time_elapsed); time_elapsed_usec = time_elapsed.tv_sec * 1000 * 1000 + time_elapsed.tv_usec; printf("Total time: %" PRIu64 " us\n", time_elapsed_usec); time_total_usec += time_elapsed_usec; if (time_elapsed_usec < time_min_usec) time_min_usec = time_elapsed_usec; if (time_elapsed_usec > time_max_usec) time_max_usec = time_elapsed_usec; thrift_transport_close (transport, &error); } else { printf ("Connect failed: %s\n", error->message); g_error_free (error); error = NULL; goto out; } } /* All done---output statistics */ puts ("\nAll tests done."); printf("Number of failures: %d\n", fail_count); time_avg_usec = time_total_usec / num_tests; printf ("Min time: %" PRIu64 " us\n", time_min_usec); printf ("Max time: %" PRIu64 " us\n", time_max_usec); printf ("Avg time: %" PRIu64 " us\n", time_avg_usec); out: g_clear_object(&second_service); g_clear_object(&protocol2); g_clear_object(&test_client); g_clear_object(&protocol); g_clear_object(&multiplexed_protocol); g_clear_object(&transport); g_clear_object(&socket); if (ssl) { thrift_ssl_socket_finalize_openssl(); } return fail_count; } thrift-0.16.0/test/c_glib/src/test_server.c000066400000000000000000000264731420101504100205740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../gen-c_glib/t_test_thrift_test.h" #include "../gen-c_glib/t_test_second_service.h" #include "thrift_test_handler.h" #include "thrift_second_service_handler.h" /* Our server object, declared globally so it is accessible within the SIGINT signal handler */ ThriftServer *server = NULL; /* A flag that indicates whether the server was interrupted with SIGINT (i.e. Ctrl-C) so we can tell whether its termination was abnormal */ gboolean sigint_received = FALSE; /* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the server */ static void sigint_handler (int signal_number) { THRIFT_UNUSED_VAR (signal_number); /* Take note we were called */ sigint_received = TRUE; /* Shut down the server gracefully */ if (server != NULL) thrift_server_stop (server); } int main (int argc, char **argv) { static gint port = 9090; static gchar *path_option = NULL; static gchar *server_type_option = NULL; static gchar *transport_option = NULL; static gchar *protocol_option = NULL; static gint string_limit = 0; static gint container_limit = 0; static GOptionEntry option_entries[] = { { "port", 0, 0, G_OPTION_ARG_INT, &port, "Port number to connect (=9090)", NULL }, { "domain-socket", 0, 0, G_OPTION_ARG_STRING, &path_option, "Unix socket domain path to connect", NULL }, { "server-type", 0, 0, G_OPTION_ARG_STRING, &server_type_option, "Type of server: simple (=simple)", NULL }, { "transport", 0, 0, G_OPTION_ARG_STRING, &transport_option, "Transport: buffered, framed, zlib (=buffered)", NULL }, { "protocol", 0, 0, G_OPTION_ARG_STRING, &protocol_option, "Protocol: binary, compact (=binary)", NULL }, { "string-limit", 0, 0, G_OPTION_ARG_INT, &string_limit, "Max string length (=none)", NULL }, { "container-limit", 0, 0, G_OPTION_ARG_INT, &container_limit, "Max container length (=none)", NULL }, { NULL } }; gchar *server_name = "simple"; gchar *transport_name = "buffered"; GType transport_factory_type = THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY; gchar *protocol_name = "binary"; GType protocol_factory_type = THRIFT_TYPE_BINARY_PROTOCOL_FACTORY; TTestThriftTestHandler *handler; TTestThriftTestHandler *handler_second_service = NULL; ThriftProcessor *processor; ThriftProcessor *processor_test = NULL; ThriftProcessor *processor_second_service = NULL; ThriftServerTransport *server_transport; ThriftTransportFactory *transport_factory; ThriftProtocolFactory *protocol_factory; struct sigaction sigint_action; GOptionContext *option_context; gboolean options_valid = TRUE; GError *error = NULL; #if (!GLIB_CHECK_VERSION (2, 36, 0)) g_type_init (); #endif /* Configure and parse our command-line options */ option_context = g_option_context_new (NULL); g_option_context_add_main_entries (option_context, option_entries, NULL); if (g_option_context_parse (option_context, &argc, &argv, &error) == FALSE) { fprintf (stderr, "%s\n", error->message); g_clear_error (&error); g_option_context_free (option_context); return 255; } g_option_context_free (option_context); /* Validate the parsed options */ if (server_type_option != NULL && strncmp (server_type_option, "simple", 7) != 0) { fprintf (stderr, "Unknown server type %s\n", protocol_option); options_valid = FALSE; } if (protocol_option != NULL) { if (strncmp (protocol_option, "compact", 8) == 0) { protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY; protocol_name = "compact"; } else if (strncmp (protocol_option, "multi", 6) == 0) { protocol_name = "binary:multi"; } else if (strncmp (protocol_option, "multic", 7) == 0) { protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY; protocol_name = "compact:multic"; } else if (strncmp (protocol_option, "binary", 7) != 0) { fprintf (stderr, "Unknown protocol type %s\n", protocol_option); options_valid = FALSE; } } if (transport_option != NULL) { if (strncmp (transport_option, "framed", 7) == 0) { transport_factory_type = THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY; transport_name = "framed"; } else if (strncmp (transport_option, "zlib", 5) == 0) { transport_factory_type = THRIFT_TYPE_ZLIB_TRANSPORT_FACTORY; transport_name = "zlib"; } else if (strncmp (transport_option, "buffered", 9) != 0) { fprintf (stderr, "Unknown transport type %s\n", transport_option); options_valid = FALSE; } } if (!options_valid) return 254; /* Establish all our connection objects */ handler = g_object_new (TYPE_THRIFT_TEST_HANDLER, NULL); if(strstr(protocol_name, ":multi")){ /* When a multiplexed processor is involved the handler is not registered as usual. We create the processor and the real processor is registered. Multiple processors can be registered at once. This is why we don't have a constructor property */ processor = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROCESSOR, NULL); handler_second_service = g_object_new (TYPE_SECOND_SERVICE_HANDLER, NULL); processor_test = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR, "handler", handler, NULL); processor_second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_PROCESSOR, "handler", handler_second_service, NULL); /* We register a test processor with Multiplexed name ThriftTest */ if(!thrift_multiplexed_processor_register_processor(processor, "ThriftTest", processor_test, &error)){ g_message ("thrift_server_serve: %s", error != NULL ? error->message : "(null)"); g_clear_error (&error); } /* We register a second test processor with Multiplexed name SecondService * we are responsible of freeing the processor when it's not used anymore */ if(!thrift_multiplexed_processor_register_processor(processor, "SecondService", processor_second_service, &error)){ g_message ("thrift_server_serve: %s", error != NULL ? error->message : "(null)"); g_clear_error (&error); } }else{ processor = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR, "handler", handler, NULL); } if (path_option) { server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET, "path", path_option, NULL); } else { server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET, "port", port, NULL); } transport_factory = g_object_new (transport_factory_type, NULL); if (strstr (protocol_name, "compact") != NULL) { protocol_factory = g_object_new (protocol_factory_type, "string_limit", string_limit, "container_limit", container_limit, NULL); } else { protocol_factory = g_object_new (protocol_factory_type, NULL); } server = g_object_new (THRIFT_TYPE_SIMPLE_SERVER, "processor", processor, "server_transport", server_transport, "input_transport_factory", transport_factory, "output_transport_factory", transport_factory, "input_protocol_factory", protocol_factory, "output_protocol_factory", protocol_factory, NULL); /* Install our SIGINT handler, which handles Ctrl-C being pressed by stopping the server gracefully */ memset (&sigint_action, 0, sizeof (sigint_action)); sigint_action.sa_handler = sigint_handler; sigint_action.sa_flags = SA_RESETHAND; sigaction (SIGINT, &sigint_action, NULL); if (path_option) { printf ("Starting \"%s\" server (%s/%s) listen on: %s\n", server_name, transport_name, protocol_name, path_option); } else { printf ("Starting \"%s\" server (%s/%s) listen on: %d\n", server_name, transport_name, protocol_name, port); } fflush (stdout); /* Serve clients until SIGINT is received (Ctrl-C is pressed) */ thrift_server_serve (server, &error); /* If the server stopped for any reason other than being interrupted by the user, report the error */ if (!sigint_received) { g_message ("thrift_server_serve: %s", error != NULL ? error->message : "(null)"); } puts ("done."); g_clear_error (&error); g_object_unref (server); g_object_unref (protocol_factory); g_object_unref (transport_factory); g_object_unref (server_transport); g_object_unref (processor); g_object_unref (handler); if(handler_second_service){ g_object_unref (handler_second_service); } if(processor_test){ g_object_unref (processor_test); } if(processor_second_service){ g_object_unref (processor_second_service); } return 0; } thrift-0.16.0/test/c_glib/src/thrift_second_service_handler.c000066400000000000000000000040501420101504100242620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include "thrift_second_service_handler.h" /* A handler that implements the TTestSecondServiceIf interface */ G_DEFINE_TYPE (SecondServiceHandler, second_service_handler, T_TEST_TYPE_SECOND_SERVICE_HANDLER); gboolean second_service_handler_secondtest_string (TTestSecondServiceIf *iface, gchar **_return, const gchar *thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); gchar buffer[256]; printf ("testSecondServiceMultiplexSecondTestString(\"%s\")\n", thing); snprintf(buffer, 255, "testString(\"%s\")", thing); *_return = g_strdup (buffer); return TRUE; } static void second_service_handler_init (SecondServiceHandler *self) { THRIFT_UNUSED_VAR (self); } static void second_service_handler_class_init (SecondServiceHandlerClass *klass) { TTestSecondServiceHandlerClass *base_class = T_TEST_SECOND_SERVICE_HANDLER_CLASS (klass); base_class->secondtest_string = second_service_handler_secondtest_string; } thrift-0.16.0/test/c_glib/src/thrift_second_service_handler.h000066400000000000000000000055161420101504100242770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _SECOND_SERVICE_HANDLER_H #define _SECOND_SERVICE_HANDLER_H #include #include #include "../gen-c_glib/t_test_second_service.h" G_BEGIN_DECLS /* A handler that implements the TTestSecondServiceIf interface */ #define TYPE_SECOND_SERVICE_HANDLER (second_service_handler_get_type ()) #define SECOND_SERVICE_HANDLER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ TYPE_SECOND_SERVICE_HANDLER, \ SecondServiceHandler)) #define IS_SECOND_SERVICE_HANDLER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ TYPE_SECOND_SERVICE_HANDLER)) #define SECOND_SERVICE_HANDLER_CLASS(c) \ (G_TYPE_CHECK_CLASS_CAST ((c), \ TYPE_SECOND_SERVICE_HANDLER, \ SecondServiceHandlerClass)) #define IS_SECOND_SERVICE_HANDLER_CLASS(c) \ (G_TYPE_CHECK_CLASS_TYPE ((c), \ TYPE_SECOND_SERVICE_HANDLER)) #define SECOND_SERVICE_HANDLER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ TYPE_SECOND_SERVICE_HANDLER, \ SecondServiceHandlerClass)) typedef struct _SecondServiceHandler SecondServiceHandler; typedef struct _SecondServiceHandlerClass SecondServiceHandlerClass; struct _SecondServiceHandler { TTestSecondServiceHandler parent; }; struct _SecondServiceHandlerClass { TTestSecondServiceHandlerClass parent; }; /* Used by SECOND_SERVICE_HANDLER_GET_TYPE */ GType second_service_handler_get_type (void); gboolean second_service_handler_blah_blah (TTestSecondServiceIf *iface, GError **error); gboolean second_service_handler_secondtest_string (TTestSecondServiceIf *iface, gchar ** _return, const gchar * thing, GError **error); G_END_DECLS #endif /* _SECOND_SERVICE_HANDLER_H */ thrift-0.16.0/test/c_glib/src/thrift_test_handler.c000066400000000000000000000563171420101504100222630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include "thrift_test_handler.h" /* A handler that implements the TTestThriftTestIf interface */ G_DEFINE_TYPE (ThriftTestHandler, thrift_test_handler, T_TEST_TYPE_THRIFT_TEST_HANDLER) gboolean thrift_test_handler_test_void (TTestThriftTestIf *iface, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testVoid()\n"); return TRUE; } gboolean thrift_test_handler_test_string (TTestThriftTestIf *iface, gchar **_return, const gchar *thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testString(\"%s\")\n", thing); *_return = g_strdup (thing); return TRUE; } gboolean thrift_test_handler_test_bool (TTestThriftTestIf *iface, gboolean *_return, const gboolean thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testBool(%s)\n", thing ? "true" : "false"); *_return = thing; return TRUE; } gboolean thrift_test_handler_test_byte (TTestThriftTestIf *iface, gint8 *_return, const gint8 thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testByte(%d)\n", (gint)thing); *_return = thing; return TRUE; } gboolean thrift_test_handler_test_i32 (TTestThriftTestIf *iface, gint32 *_return, const gint32 thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testI32(%d)\n", thing); *_return = thing; return TRUE; } gboolean thrift_test_handler_test_i64 (TTestThriftTestIf *iface, gint64 *_return, const gint64 thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testI64(%" PRId64 ")\n", thing); *_return = thing; return TRUE; } gboolean thrift_test_handler_test_double (TTestThriftTestIf *iface, gdouble *_return, const gdouble thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testDouble(%f)\n", thing); *_return = thing; return TRUE; } gboolean thrift_test_handler_test_binary (TTestThriftTestIf *iface, GByteArray ** _return, const GByteArray * thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testBinary()\n"); // TODO: hex output g_byte_array_ref((GByteArray *)thing); *_return = (GByteArray *)thing; return TRUE; } gboolean thrift_test_handler_test_struct (TTestThriftTestIf *iface, TTestXtruct **_return, const TTestXtruct *thing, GError **error) { gchar *string_thing = NULL; gint byte_thing; gint i32_thing; gint64 i64_thing; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); g_object_get ((TTestXtruct *)thing, "string_thing", &string_thing, "byte_thing", &byte_thing, "i32_thing", &i32_thing, "i64_thing", &i64_thing, NULL); printf ("testStruct({\"%s\", %d, %d, %" PRId64 "})\n", string_thing, (gint)byte_thing, i32_thing, i64_thing); g_object_set (*_return, "string_thing", string_thing, "byte_thing", byte_thing, "i32_thing", i32_thing, "i64_thing", i64_thing, NULL); if (string_thing != NULL) g_free (string_thing); return TRUE; } gboolean thrift_test_handler_test_nest (TTestThriftTestIf *iface, TTestXtruct2 **_return, const TTestXtruct2 *thing, GError **error) { gchar *inner_string_thing = NULL; gint byte_thing, inner_byte_thing; gint i32_thing, inner_i32_thing; gint64 inner_i64_thing; TTestXtruct *struct_thing; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); g_object_get ((TTestXtruct2 *)thing, "byte_thing", &byte_thing, "struct_thing", &struct_thing, "i32_thing", &i32_thing, NULL); g_object_get (struct_thing, "string_thing", &inner_string_thing, "byte_thing", &inner_byte_thing, "i32_thing", &inner_i32_thing, "i64_thing", &inner_i64_thing, NULL); printf ("testNest({%d, {\"%s\", %d, %d, %" PRId64 "}, %d})\n", byte_thing, inner_string_thing, inner_byte_thing, inner_i32_thing, inner_i64_thing, i32_thing); g_object_set (*_return, "byte_thing", byte_thing, "struct_thing", struct_thing, "i32_thing", i32_thing, NULL); if (inner_string_thing != NULL) g_free (inner_string_thing); g_object_unref (struct_thing); return TRUE; } gboolean thrift_test_handler_test_map (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error) { GHashTableIter hash_table_iter; gpointer key; gpointer value; gboolean first = TRUE; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testMap({"); g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { gint32 *new_key; gint32 *new_value; if (first) first = FALSE; else printf (", "); printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); new_key = g_malloc (sizeof *new_key); *new_key = *(gint32 *)key; new_value = g_malloc (sizeof *new_value); *new_value = *(gint32 *)value; g_hash_table_insert (*_return, new_key, new_value); } printf ("})\n"); return TRUE; } gboolean thrift_test_handler_test_string_map (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error) { GHashTableIter hash_table_iter; gpointer key; gpointer value; gboolean first = TRUE; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testStringMap({"); g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { gchar *new_key; gchar *new_value; if (first) first = FALSE; else printf (", "); printf ("%s => %s", (gchar *)key, (gchar *)value); new_key = g_strdup ((gchar *)key); new_value = g_strdup ((gchar *)value); g_hash_table_insert (*_return, new_key, new_value); } printf ("})\n"); return TRUE; } gboolean thrift_test_handler_test_set (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error) { GHashTableIter hash_table_iter; gpointer key; gboolean first = TRUE; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testSet({"); g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing); while (g_hash_table_iter_next (&hash_table_iter, &key, NULL)) { gint32 *new_key; if (first) first = FALSE; else printf (", "); printf ("%d", *(gint32 *)key); new_key = g_malloc (sizeof *new_key); *new_key = *(gint32 *)key; g_hash_table_insert (*_return, new_key, NULL); } printf ("})\n"); return TRUE; } gboolean thrift_test_handler_test_list (TTestThriftTestIf *iface, GArray **_return, const GArray *thing, GError **error) { guint i; gboolean first = TRUE; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testList({"); for (i = 0; i < thing->len; i += 1) { gint32 value; gint32 new_value; if (first) first = FALSE; else printf (", "); value = g_array_index (thing, gint32, i); printf ("%d", value); new_value = value; g_array_append_val (*_return, new_value); } printf ("})\n"); return TRUE; } gboolean thrift_test_handler_test_enum (TTestThriftTestIf *iface, TTestNumberz *_return, const TTestNumberz thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testEnum(%d)\n", thing); *_return = thing; return TRUE; } gboolean thrift_test_handler_test_typedef (TTestThriftTestIf *iface, TTestUserId *_return, const TTestUserId thing, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testTypedef(%" PRId64 ")\n", thing); *_return = thing; return TRUE; } gboolean thrift_test_handler_test_map_map (TTestThriftTestIf *iface, GHashTable **_return, const gint32 hello, GError **error) { GHashTable *positive; GHashTable *negative; gint32 *key; gint32 *value; guint i; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testMapMap(%d)\n", hello); positive = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free); negative = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free); for (i = 1; i < 5; i += 1) { key = g_malloc (sizeof *key); value = g_malloc (sizeof *value); *key = i; *value = i; g_hash_table_insert (positive, key, value); key = g_malloc (sizeof *key); value = g_malloc (sizeof *value); *key = -i; *value = -i; g_hash_table_insert (negative, key, value); } key = g_malloc (sizeof *key); *key = 4; g_hash_table_insert (*_return, key, positive); key = g_malloc (sizeof *key); *key = -4; g_hash_table_insert (*_return, key, negative); return TRUE; } gboolean thrift_test_handler_test_insanity (TTestThriftTestIf *iface, GHashTable **_return, const TTestInsanity *argument, GError **error) { TTestXtruct *xtruct_in; gchar *string_thing = NULL; gint byte_thing; gint i32_thing; gint64 i64_thing; GPtrArray *xtructs; TTestInsanity *looney; GHashTable *user_map; GHashTable *first_map; GHashTable *second_map; GHashTableIter hash_table_iter; GHashTableIter inner_hash_table_iter; GHashTableIter user_map_iter; gpointer key; gpointer value; TTestUserId *user_id; guint i; THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testInsanity()\n"); first_map = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); second_map = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); g_hash_table_insert (first_map, GINT_TO_POINTER (T_TEST_NUMBERZ_TWO), (gpointer)argument); g_hash_table_insert (first_map, GINT_TO_POINTER (T_TEST_NUMBERZ_THREE), (gpointer)argument); /* Increment argument's ref count by two because first_map now holds two references to it and the caller is not aware we have made any additional references to argument. (That is, caller owns argument and will unref it explicitly in addition to unref-ing *_return.) We do this instead of creating a copy of argument in order to mimic the C++ implementation (and since, frankly, the world needs less argument, not more). */ g_object_ref ((gpointer)argument); g_object_ref ((gpointer)argument); looney = g_object_new (T_TEST_TYPE_INSANITY, NULL); g_hash_table_insert (second_map, GINT_TO_POINTER (T_TEST_NUMBERZ_SIX), looney); user_id = g_malloc (sizeof *user_id); *user_id = 1; g_hash_table_insert (*_return, user_id, first_map); user_id = g_malloc (sizeof *user_id); *user_id = 2; g_hash_table_insert (*_return, user_id, second_map); printf ("return"); printf (" = {"); g_hash_table_iter_init (&hash_table_iter, *_return); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { printf ("%" PRId64 " => {", *(TTestUserId *)key); g_hash_table_iter_init (&inner_hash_table_iter, (GHashTable *)value); while (g_hash_table_iter_next (&inner_hash_table_iter, &key, &value)) { printf ("%d => {", (TTestNumberz)key); g_object_get ((TTestInsanity *)value, "userMap", &user_map, "xtructs", &xtructs, NULL); printf ("{"); g_hash_table_iter_init (&user_map_iter, user_map); while (g_hash_table_iter_next (&user_map_iter, &key, &value)) { printf ("%d => %" PRId64 ", ", (TTestNumberz)key, *(TTestUserId *)value); } printf ("}, "); g_hash_table_unref (user_map); printf ("{"); for (i = 0; i < xtructs->len; ++i) { xtruct_in = g_ptr_array_index (xtructs, i); g_object_get (xtruct_in, "string_thing", &string_thing, "byte_thing", &byte_thing, "i32_thing", &i32_thing, "i64_thing", &i64_thing, NULL); printf ("{\"%s\", %d, %d, %" PRId64 "}, ", string_thing, byte_thing, i32_thing, i64_thing); if (string_thing != NULL) { g_free (string_thing); } } printf ("}"); g_ptr_array_unref (xtructs); printf ("}, "); } printf ("}, "); } printf ("}\n"); return TRUE; } gboolean thrift_test_handler_test_multi (TTestThriftTestIf *iface, TTestXtruct **_return, const gint8 arg0, const gint32 arg1, const gint64 arg2, const GHashTable *arg3, const TTestNumberz arg4, const TTestUserId arg5, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); THRIFT_UNUSED_VAR (arg3); THRIFT_UNUSED_VAR (arg4); THRIFT_UNUSED_VAR (arg5); printf ("testMulti()\n"); g_object_set (*_return, "string_thing", "Hello2", "byte_thing", arg0, "i32_thing", arg1, "i64_thing", arg2, NULL); return TRUE; } gboolean thrift_test_handler_test_exception (TTestThriftTestIf *iface, const gchar *arg, TTestXception **err1, GError **error) { THRIFT_UNUSED_VAR (iface); TTestXtruct *xtruct; gboolean result; printf ("testException(%s)\n", arg); /* Unlike argument objects, exception objects are not pre-created */ g_assert (*err1 == NULL); if (strncmp (arg, "Xception", 9) == 0) { /* "Throw" a custom exception: Set the corresponding exception argument, set *error to NULL and return FALSE */ *err1 = g_object_new (T_TEST_TYPE_XCEPTION, "errorCode", 1001, "message", arg, NULL); *error = NULL; result = FALSE; } else if (strncmp (arg, "TException", 11) == 0) { /* "Throw" a generic TException (ThriftApplicationException): Set all exception arguments to NULL, set *error and return FALSE */ *err1 = NULL; g_set_error (error, thrift_application_exception_error_quark (), THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN, "Default TException."); result = FALSE; } else { *err1 = NULL; *error = NULL; /* This code is duplicated from the C++ test suite, though it appears to serve no purpose */ xtruct = g_object_new (T_TEST_TYPE_XTRUCT, "string_thing", arg, NULL); g_object_unref (xtruct); result = TRUE; } return result; } gboolean thrift_test_handler_test_multi_exception (TTestThriftTestIf *iface, TTestXtruct **_return, const gchar *arg0, const gchar *arg1, TTestXception **err1, TTestXception2 **err2, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); TTestXtruct *struct_thing; gboolean result; printf ("testMultiException(%s, %s)\n", arg0, arg1); g_assert (*err1 == NULL); g_assert (*err2 == NULL); if (strncmp (arg0, "Xception", 8) == 0 && strlen(arg0) == 8) { *err1 = g_object_new (T_TEST_TYPE_XCEPTION, "errorCode", 1001, "message", "This is an Xception", NULL); result = FALSE; } else if (strncmp (arg0, "Xception2", 9) == 0) { *err2 = g_object_new (T_TEST_TYPE_XCEPTION2, "errorCode", 2002, NULL); g_object_get (*err2, "struct_thing", &struct_thing, NULL); g_object_set (struct_thing, "string_thing", "This is an Xception2", NULL); g_object_set (*err2, "struct_thing", struct_thing, NULL); g_object_unref (struct_thing); result = FALSE; } else { g_object_set (*_return, "string_thing", arg1, NULL); result = TRUE; } return result; } gboolean thrift_test_handler_test_oneway (TTestThriftTestIf *iface, const gint32 secondsToSleep, GError **error) { THRIFT_UNUSED_VAR (iface); THRIFT_UNUSED_VAR (error); printf ("testOneway(%d): Sleeping...\n", secondsToSleep); sleep (secondsToSleep); printf ("testOneway(%d): done sleeping!\n", secondsToSleep); return TRUE; } static void thrift_test_handler_init (ThriftTestHandler *self) { THRIFT_UNUSED_VAR (self); } static void thrift_test_handler_class_init (ThriftTestHandlerClass *klass) { TTestThriftTestHandlerClass *base_class = T_TEST_THRIFT_TEST_HANDLER_CLASS (klass); base_class->test_void = klass->test_void = thrift_test_handler_test_void; base_class->test_string = klass->test_string = thrift_test_handler_test_string; base_class->test_bool = klass->test_bool = thrift_test_handler_test_bool; base_class->test_byte = klass->test_byte = thrift_test_handler_test_byte; base_class->test_i32 = klass->test_i32 = thrift_test_handler_test_i32; base_class->test_i64 = klass->test_i64 = thrift_test_handler_test_i64; base_class->test_double = klass->test_double = thrift_test_handler_test_double; base_class->test_binary = klass->test_binary = thrift_test_handler_test_binary; base_class->test_struct = klass->test_struct = thrift_test_handler_test_struct; base_class->test_nest = klass->test_nest = thrift_test_handler_test_nest; base_class->test_map = klass->test_map = thrift_test_handler_test_map; base_class->test_string_map = klass->test_string_map = thrift_test_handler_test_string_map; base_class->test_set = klass->test_set = thrift_test_handler_test_set; base_class->test_list = klass->test_list = thrift_test_handler_test_list; base_class->test_enum = klass->test_enum = thrift_test_handler_test_enum; base_class->test_typedef = klass->test_typedef = thrift_test_handler_test_typedef; base_class->test_map_map = klass->test_map_map = thrift_test_handler_test_map_map; base_class->test_insanity = klass->test_insanity = thrift_test_handler_test_insanity; base_class->test_multi = klass->test_multi = thrift_test_handler_test_multi; base_class->test_exception = klass->test_exception = thrift_test_handler_test_exception; base_class->test_multi_exception = klass->test_multi_exception = thrift_test_handler_test_multi_exception; base_class->test_oneway = klass->test_oneway = thrift_test_handler_test_oneway; } thrift-0.16.0/test/c_glib/src/thrift_test_handler.h000066400000000000000000000353001420101504100222550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _THRIFT_TEST_HANDLER_H #define _THRIFT_TEST_HANDLER_H #include #include #include "../gen-c_glib/t_test_thrift_test.h" G_BEGIN_DECLS /* A handler that implements the TTestThriftTestIf interface */ #define TYPE_THRIFT_TEST_HANDLER (thrift_test_handler_get_type ()) #define THRIFT_TEST_HANDLER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ TYPE_THRIFT_TEST_HANDLER, \ ThriftTestHandler)) #define IS_THRIFT_TEST_HANDLER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ TYPE_THRIFT_TEST_HANDLER)) #define THRIFT_TEST_HANDLER_CLASS(c) \ (G_TYPE_CHECK_CLASS_CAST ((c), \ TYPE_THRIFT_TEST_HANDLER, \ ThriftTestHandlerClass)) #define IS_THRIFT_TEST_HANDLER_CLASS(c) \ (G_TYPE_CHECK_CLASS_TYPE ((c), \ TYPE_THRIFT_TEST_HANDLER)) #define THRIFT_TEST_HANDLER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ TYPE_THRIFT_TEST_HANDLER, \ ThriftTestHandlerClass)) typedef struct _ThriftTestHandler ThriftTestHandler; typedef struct _ThriftTestHandlerClass ThriftTestHandlerClass; struct _ThriftTestHandler { TTestThriftTestHandler parent; }; struct _ThriftTestHandlerClass { TTestThriftTestHandlerClass parent; gboolean (*test_void) (TTestThriftTestIf *iface, GError **error); gboolean (*test_string) (TTestThriftTestIf *iface, gchar **_return, const gchar *thing, GError **error); gboolean (*test_bool) (TTestThriftTestIf *iface, gboolean*_return, const gboolean thing, GError **error); gboolean (*test_byte) (TTestThriftTestIf *iface, gint8*_return, const gint8 thing, GError **error); gboolean (*test_i32) (TTestThriftTestIf *iface, gint32*_return, const gint32 thing, GError **error); gboolean (*test_i64) (TTestThriftTestIf *iface, gint64*_return, const gint64 thing, GError **error); gboolean (*test_double) (TTestThriftTestIf *iface, gdouble*_return, const gdouble thing, GError **error); gboolean (*test_binary) (TTestThriftTestIf *iface, GByteArray **_return, const GByteArray *thing, GError **error); gboolean (*test_struct) (TTestThriftTestIf *iface, TTestXtruct **_return, const TTestXtruct *thing, GError **error); gboolean (*test_nest) (TTestThriftTestIf *iface, TTestXtruct2 **_return, const TTestXtruct2 *thing, GError **error); gboolean (*test_map) (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error); gboolean (*test_string_map) (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error); gboolean (*test_set) (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error); gboolean (*test_list) (TTestThriftTestIf *iface, GArray **_return, const GArray *thing, GError **error); gboolean (*test_enum) (TTestThriftTestIf *iface, TTestNumberz*_return, const TTestNumberz thing, GError **error); gboolean (*test_typedef) (TTestThriftTestIf *iface, TTestUserId*_return, const TTestUserId thing, GError **error); gboolean (*test_map_map) (TTestThriftTestIf *iface, GHashTable **_return, const gint32 hello, GError **error); gboolean (*test_insanity) (TTestThriftTestIf *iface, GHashTable **_return, const TTestInsanity *argument, GError **error); gboolean (*test_multi) (TTestThriftTestIf *iface, TTestXtruct **_return, const gint8 arg0, const gint32 arg1, const gint64 arg2, const GHashTable *arg3, const TTestNumberz arg4, const TTestUserId arg5, GError **error); gboolean (*test_exception) (TTestThriftTestIf *iface, const gchar *arg, TTestXception **err1, GError **error); gboolean (*test_multi_exception) (TTestThriftTestIf *iface, TTestXtruct **_return, const gchar *arg0, const gchar *arg1, TTestXception **err1, TTestXception2 **err2, GError **error); gboolean (*test_oneway) (TTestThriftTestIf *iface, const gint32 secondsToSleep, GError **error); }; /* Used by THRIFT_TEST_HANDLER_GET_TYPE */ GType thrift_test_handler_get_type (void); gboolean thrift_test_handler_test_void (TTestThriftTestIf *iface, GError **error); gboolean thrift_test_handler_test_string (TTestThriftTestIf *iface, gchar **_return, const gchar *thing, GError **error); gboolean thrift_test_handler_test_byte (TTestThriftTestIf *iface, gint8*_return, const gint8 thing, GError **error); gboolean t_test_thrift_test_if_test_i32 (TTestThriftTestIf *iface, gint32*_return, const gint32 thing, GError **error); gboolean thrift_test_handler_test_i64 (TTestThriftTestIf *iface, gint64*_return, const gint64 thing, GError **error); gboolean thrift_test_handler_test_double (TTestThriftTestIf *iface, gdouble*_return, const gdouble thing, GError **error); gboolean thrift_test_handler_test_struct (TTestThriftTestIf *iface, TTestXtruct **_return, const TTestXtruct *thing, GError **error); gboolean thrift_test_handler_test_nest (TTestThriftTestIf *iface, TTestXtruct2 **_return, const TTestXtruct2 *thing, GError **error); gboolean thrift_test_handler_test_map (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error); gboolean thrift_test_handler_test_string_map (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error); gboolean thrift_test_handler_test_set (TTestThriftTestIf *iface, GHashTable **_return, const GHashTable *thing, GError **error); gboolean thrift_test_handler_test_list (TTestThriftTestIf *iface, GArray **_return, const GArray *thing, GError **error); gboolean thrift_test_handler_test_typedef (TTestThriftTestIf *iface, TTestUserId*_return, const TTestUserId thing, GError **error); gboolean thrift_test_handler_test_map_map (TTestThriftTestIf *iface, GHashTable **_return, const gint32 hello, GError **error); gboolean thrift_test_handler_test_insanity (TTestThriftTestIf *iface, GHashTable **_return, const TTestInsanity *argument, GError **error); gboolean thrift_test_handler_test_multi (TTestThriftTestIf *iface, TTestXtruct **_return, const gint8 arg0, const gint32 arg1, const gint64 arg2, const GHashTable *arg3, const TTestNumberz arg4, const TTestUserId arg5, GError **error); gboolean thrift_test_handler_test_exception (TTestThriftTestIf *iface, const gchar *arg, TTestXception **err1, GError **error); gboolean thrift_test_handler_test_multi_exception (TTestThriftTestIf *iface, TTestXtruct **_return, const gchar *arg0, const gchar *arg1, TTestXception **err1, TTestXception2 **err2, GError **error); gboolean thrift_test_handler_test_oneway (TTestThriftTestIf *iface, const gint32 secondsToSleep, GError **error); G_END_DECLS #endif /* _THRIFT_TEST_HANDLER_H */ thrift-0.16.0/test/cl/000077500000000000000000000000001420101504100144375ustar00rootroot00000000000000thrift-0.16.0/test/cl/Makefile.am000077500000000000000000000025321420101504100165000ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # THRIFT = $(top_builddir)/compiler/cpp/thrift stubs: ../ThriftTest.thrift $(THRIFT) --gen cl ../ThriftTest.thrift TestServer: make-test-server.lisp @echo 'cl broken, commented out due to deprecation' ## $(SBCL) --script make-test-server.lisp TestClient: make-test-client.lisp @echo 'cl broken, commented out due to deprecation' ## $(SBCL) --script make-test-client.lisp precross: stubs TestServer TestClient clean-local: $(RM) -r gen-cl $(RM) TestServer $(RM) TestClient EXTRA_DIST = \ implementation.lisp \ make-test-client.lisp \ make-test-server.lisp \ tests.lisp thrift-0.16.0/test/cl/implementation.lisp000066400000000000000000000120571420101504100203620ustar00rootroot00000000000000(in-package #:thrift.test-implementation) ;;;; 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. (defun thrift.test.thrift-test-implementation:test-void () (format t "testVoid()~%")) (defun thrift.test.thrift-test-implementation:test-string (thing) (format t "testString(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-bool (thing) (format t "testBool(~a)~%" (if thing "true" "false")) thing) (defun thrift.test.thrift-test-implementation:test-byte (thing) (format t "testByte(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-i32 (thing) (format t "testI32(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-i64 (thing) (format t "testI64(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-double (thing) (format t "testDouble(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-binary (thing) (format t "testBinary(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-struct (thing) (format t "testStruct(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-nest (thing) (format t "testNest(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-map (thing) (format t "testMap(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-string-map (thing) (format t "testStringMap(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-set (thing) (format t "testSet(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-list (thing) (format t "testList(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-enum (thing) (format t "testEnum(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-typedef (thing) (format t "testTypedef(~a)~%" thing) thing) (defun thrift.test.thrift-test-implementation:test-map-map (hello) (format t "testMapMap(~a)~%" hello) '((-4 . ((-4 . -4) (-3 . -3) (-2 . -2) (-1 . -1))) (4 . ((1 . 1) (2 . 2) (3 . 3) (4 . 4))))) (defun thrift.test.thrift-test-implementation:test-insanity (argument) (let ((result `((1 . ((2 . ,argument) (3 . ,argument))) (2 . ((6 . ,(thrift.test::make-insanity :user-map nil :xtructs nil))))))) (format t "~a~%" result) result)) (defun thrift.test.thrift-test-implementation:test-multi (arg0 arg1 arg2 arg3 arg4 arg5) (declare (ignorable arg3 arg4 arg5)) (format t "testMulti()~%") (thrift.test:make-xtruct :string-thing "Hello2" :byte-thing arg0 :i32-thing arg1 :i64-thing arg2)) (defun thrift.test.thrift-test-implementation:test-exception (arg) (format t "testException(~a)~%" arg) (cond ((string= arg "Xception") (error 'thrift.test:xception :error-code 1001 :message arg)) ((string= arg "TException") (error 'thrift.test:xception :error-code 0 :message "Stuff!")))) (defun thrift.test.thrift-test-implementation:test-multi-exception (arg0 arg1) (format t "testMultiException(~a, ~a)~%" arg0 arg1) (cond ((string= arg0 "Xception") (error 'thrift.test:xception :error-code 1001 :message "This is an Xception")) ((string= arg0 "Xception2") (error 'thrift.test:xception2 :error-code 2002 :struct-thing (thrift.test:make-xtruct :string-thing "This is an Xception2" :byte-thing 0 :i32-thing 0 :i64-thing 0)))) (thrift.test:make-xtruct :string-thing arg1 :byte-thing 0 :i32-thing 0 :i64-thing 0)) (defun thrift.test.thrift-test-implementation:test-oneway (seconds) (format t "testOneway(~a): Sleeping...~%" seconds) (sleep seconds) (format t "testOneway(~a): done sleeping!~%" seconds)) ;;; Removed from the IDL definition. #+(or) (defun thrift.test.second-service-implementation:blah-blah () (format t "blahBlah()~%")) (defun thrift.test.second-service-implementation:secondtest-string (thing) (format t "secondtestString(~a)~%" thing) (concatenate 'string "testString(\"" thing "\")")) thrift-0.16.0/test/cl/make-test-client.lisp000066400000000000000000000071041420101504100205000ustar00rootroot00000000000000(in-package #:cl-user) ;;;; 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. #+(or) (when (not (boundp 'sb-impl::default-external-format) (setf sb-impl::default-external-format :UTF-8))) (require "asdf") (load (merge-pathnames "../../lib/cl/load-locally.lisp" *load-truename*)) (asdf:load-system :net.didierverna.clon) (asdf:load-system :fiasco) (asdf:load-asd (merge-pathnames "gen-cl/ThriftTest/thrift-gen-ThriftTest.asd" *load-truename*)) (asdf:load-system :thrift-gen-thrifttest) (net.didierverna.clon:nickname-package) (defpackage #:thrift-cross (:use #:common-lisp #:fiasco) (:export #:cross-test)) (in-package #:thrift-cross) (defparameter *prot* nil) (load (merge-pathnames "tests.lisp" *load-truename*) :external-format :UTF-8) (clon:defsynopsis () (text :contents "The Common Lisp client for Thrift's cross-language test suite.") (group (:header "Allowed options:") (flag :short-name "h" :long-name "help" :description "Print this help and exit.") (stropt :long-name "host" :description "The host to connect to." :default-value "localhost" :argument-name "ARG") (stropt :long-name "port" :description "Number of the port to listen for connections on." :default-value "9090" :argument-name "ARG" :argument-type :optional) (stropt :long-name "transport" :description "Transport: transport to use (\"buffered\", \"framed\")" :default-value "buffered" :argument-name "ARG") (stropt :long-name "protocol" :description "Protocol: protocol to use (\"binary\", \"multi\")" :default-value "binary" :argument-name "ARG"))) (defun main () "Entry point for our standalone application." (clon:make-context) (when (clon:getopt :short-name "h") (clon:help) (clon:exit)) (let ((port "9090") (host "localhost") (framed nil) (multiplexed nil)) (clon:do-cmdline-options (option name value source) (print (list option name value source)) (if (string= name "host") (setf host value)) (if (string= name "port") (setf port value)) (if (string= name "transport") (cond ((string= value "buffered") (setf framed nil)) ((string= value "framed") (setf framed t)) (t (error "Unsupported transport.")))) (if (string= name "protocol") (cond ((string= value "binary") (setf multiplexed nil)) ((string= value "multi") (setf multiplexed t)) (t (error "Unsupported protocol."))))) (terpri) (setf *prot* (thrift.implementation::client (puri:parse-uri (concatenate 'string "thrift://" host ":" port)) :framed framed :multiplexed multiplexed)) (let ((result (cross-test :multiplexed multiplexed))) (thrift.implementation::close *prot*) (clon:exit result)))) (clon:dump "TestClient" main) thrift-0.16.0/test/cl/make-test-server.lisp000066400000000000000000000064211420101504100205310ustar00rootroot00000000000000(in-package #:cl-user) ;;;; 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. (require "asdf") (load (merge-pathnames "../../lib/cl/load-locally.lisp" *load-truename*)) (asdf:load-system :net.didierverna.clon) (asdf:load-asd (merge-pathnames "gen-cl/ThriftTest/thrift-gen-ThriftTest.asd" *load-truename*)) (asdf:load-system :thrift-gen-thrifttest) (load (merge-pathnames "implementation.lisp" *load-truename*)) (net.didierverna.clon:nickname-package) (clon:defsynopsis () (text :contents "The Common Lisp server for Thrift's cross-language test suite.") (group (:header "Allowed options:") (flag :short-name "h" :long-name "help" :description "Print this help and exit.") (stropt :long-name "port" :description "Number of the port to listen for connections on." :default-value "9090" :argument-name "ARG" :argument-type :optional) (stropt :long-name "server-type" :description "The type of server, currently only \"simple\" is available." :default-value "simple" :argument-name "ARG") (stropt :long-name "transport" :description "Transport: transport to use (\"buffered\" or \"framed\")" :default-value "buffered" :argument-name "ARG") (stropt :long-name "protocol" :description "Protocol: protocol to use (\"binary\" or \"multi\")" :default-value "binary" :argument-name "ARG"))) (defun main () "Entry point for our standalone application." (clon:make-context) (when (clon:getopt :short-name "h") (clon:help) (clon:exit)) (let ((port "9090") (framed nil) (multiplexed nil)) (clon:do-cmdline-options (option name value source) (print (list option name value source)) (if (string= name "port") (setf port value)) (if (string= name "transport") (cond ((string= value "buffered") (setf framed nil)) ((string= value "framed") (setf framed t)) (t (error "Unsupported transport.")))) (if (string= name "protocol") (cond ((string= value "binary") (setf multiplexed nil)) ((string= value "multi") (setf multiplexed t)) (t (error "Unsupported protocol."))))) (terpri) (let ((services (if multiplexed (list thrift.test:thrift-test thrift.test:second-service) thrift.test:thrift-test))) (thrift:serve (puri:parse-uri (concatenate 'string "thrift://127.0.0.1:" port)) services :framed framed :multiplexed multiplexed))) (clon:exit)) (clon:dump "TestServer" main) thrift-0.16.0/test/cl/tests.lisp000066400000000000000000000342311420101504100164750ustar00rootroot00000000000000(in-package #:thrift-cross) ;;;; 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. ;;;; The tests here only make sense in the context of a TestServer ;;;; running and the dynamic variable thrift-cross::*prot* ;;;; being set with a client connection to the TestServer. Normally, ;;;; this is handled in make-test-client.lisp. ;;; Standard Thrift cross-test error codes (defparameter *test_basetypes* 1) (defparameter *test_structs* 2) (defparameter *test_containers* 4) (defparameter *test_exceptions* 8) (defparameter *test_unknown* 64) (defparameter *test_timeout* 128) (defun cross-test (&key (multiplexed nil)) "The main cross-test runner." (let ((result nil)) (handler-case (progn (unless (run-package-tests :package :base-types) (pushnew *test_basetypes* result)) (unless (run-package-tests :package :structs) (pushnew *test_structs* result)) (unless (run-package-tests :package :containers) (pushnew *test_containers* result)) (unless (run-package-tests :package :exceptions) (pushnew *test_exceptions* result)) (unless (run-package-tests :package :misc) (pushnew *test_unknown* result)) ;; It doesn't seem like anyone actually uses ;; the second test service when testing multiplexing, ;; so this would fail against servers in other ;; languages. For now, anyway. #+(or) (when multiplexed (unless (run-package-tests :package :multiplex) (pushnew *test_unknown* result)))) (error (e) (pushnew *test_unknown* result))) (apply #'+ result))) (fiasco:define-test-package #:base-types) (in-package #:base-types) (defconstant *lang-string* "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語") (defparameter *trick-string* (format nil "quote: \" backslash: \\ newline: ~% backspace: ~C ~ tab: ~T junk: !@#$%&()(&%$#{}{}<><><" #\backspace)) (defconstant *binary-sequence* #(128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127)) (deftest void-test () (is (null (thrift.test.thrift-test:test-void thrift-cross::*prot*)))) (deftest boolean-test () (is (thrift.test.thrift-test:test-bool thrift-cross::*prot* t)) (is (not (thrift.test.thrift-test:test-bool thrift-cross::*prot* nil)))) (deftest integer-test () (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 127) 127)) (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* -128) -128)) (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 42) 42)) (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 0) 0)) (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* 0) 0)) (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* 2147483647) 2147483647)) (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* -2147483648) -2147483648)) (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* 0) 0)) (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* 9223372036854775807) 9223372036854775807)) (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* -9223372036854775808) -9223372036854775808))) (deftest double-test () (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* 0.0) 0)) (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* 42.0) 42)) (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* -555.0) -555)) (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* -52.3678) -52.3678))) (deftest string-test () (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* "") "")) (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* "(defun botsbuildbots () (botsbuilsbots))") "(defun botsbuildbots () (botsbuilsbots))")) (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* *lang-string*) *lang-string*)) (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* *trick-string*) *trick-string*))) (deftest binary-test () (is (equalp (thrift.test.thrift-test:test-binary thrift-cross::*prot* #()) #())) (is (equalp (thrift.test.thrift-test:test-binary thrift-cross::*prot* *binary-sequence*) *binary-sequence*))) (deftest enum-test () (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.five) thrift.test:numberz.five)) (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.eight) thrift.test:numberz.eight)) (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.one) thrift.test:numberz.one))) (deftest typedef-test () (is (= (thrift.test.thrift-test:test-typedef thrift-cross::*prot* 309858235082523) 309858235082523))) (fiasco:define-test-package #:structs) (in-package #:structs) (defparameter *test-struct* (thrift.test:make-xtruct :string-thing "Hell is empty." :byte-thing -2 :i32-thing 42 :i64-thing 42424242)) (defparameter *test-nest* (thrift.test:make-xtruct2 :byte-thing 42 :struct-thing *test-struct* :i32-thing -42)) (deftest struct-test () (let ((rec-struct (thrift.test.thrift-test:test-struct thrift-cross::*prot* *test-struct*))) (is (string= (thrift.test:xtruct-string-thing *test-struct*) (thrift.test:xtruct-string-thing rec-struct))) (is (= (thrift.test:xtruct-byte-thing *test-struct*) (thrift.test:xtruct-byte-thing rec-struct))) (is (= (thrift.test:xtruct-i32-thing *test-struct*) (thrift.test:xtruct-i32-thing rec-struct))) (is (= (thrift.test:xtruct-i64-thing *test-struct*) (thrift.test:xtruct-i64-thing rec-struct))))) (deftest nest-test () (let* ((rec-nest (thrift.test.thrift-test:test-nest thrift-cross::*prot* *test-nest*)) (rec-struct (thrift.test:xtruct2-struct-thing rec-nest))) (is (string= (thrift.test:xtruct-string-thing *test-struct*) (thrift.test:xtruct-string-thing rec-struct))) (is (= (thrift.test:xtruct-byte-thing *test-struct*) (thrift.test:xtruct-byte-thing rec-struct))) (is (= (thrift.test:xtruct-i32-thing *test-struct*) (thrift.test:xtruct-i32-thing rec-struct))) (is (= (thrift.test:xtruct-i64-thing *test-struct*) (thrift.test:xtruct-i64-thing rec-struct))) (is (= (thrift.test:xtruct2-byte-thing *test-nest*) (thrift.test:xtruct2-byte-thing rec-nest))) (is (= (thrift.test:xtruct2-i32-thing *test-nest*) (thrift.test:xtruct2-i32-thing rec-nest))))) (fiasco:define-test-package #:containers) (in-package #:containers) (deftest list-test () (is (null (thrift.test.thrift-test:test-list thrift-cross::*prot* nil))) (is (equal (thrift.test.thrift-test:test-list thrift-cross::*prot* '(42 -42 0 5)) '(42 -42 0 5)))) (deftest set-test () (is (null (thrift.test.thrift-test:test-set thrift-cross::*prot* nil))) (is (equal (sort (thrift.test.thrift-test:test-set thrift-cross::*prot* (list 42 -42 0 5)) #'<) '(-42 0 5 42)))) (defun map= (map1 map2 &key (car-predicate #'equal) (cdr-predicate #'equal)) "Compare two assoc maps according to the predicates given." (not (set-exclusive-or map1 map2 :test (lambda (el1 el2) (and (funcall car-predicate (car el1) (car el2)) (funcall cdr-predicate (cdr el1) (cdr el2))))))) (deftest map-test () (is (null (thrift.test.thrift-test:test-map thrift-cross::*prot* nil))) (is (map= (thrift.test.thrift-test:test-map thrift-cross::*prot* '((0 . 1) (42 . -42) (5 . 5))) '((0 . 1) (42 . -42) (5 . 5)))) (is (map= (thrift.test.thrift-test:test-map-map thrift-cross::*prot* 42) '((-4 . ((-4 . -4) (-3 . -3) (-2 . -2) (-1 . -1))) (4 . ((1 . 1) (2 . 2) (3 . 3) (4 . 4)))) :cdr-predicate #'map=))) (fiasco:define-test-package #:exceptions) (in-package #:exceptions) (defun test-xception (expected-code expected-message function &rest args) "A helper function to test whether xception is signalled, and whether its fields have the expected values." (handler-case (progn (apply function args) nil) (thrift.test:xception (ex) (and (= (thrift.test::xception-error-code ex) expected-code) (string= (thrift.test::xception-message ex) expected-message))))) (defun test-xception2 (expected-code expected-message function &rest args) "A helper function to test whether xception2 is signalled, and whether its fields have the expected values." (handler-case (progn (apply function args) nil) (thrift.test:xception2 (ex) (and (= (thrift.test::xception2-error-code ex) expected-code) (string= (thrift.test::xtruct-string-thing (thrift.test::xception2-struct-thing ex)) expected-message))))) (deftest exception-test () (is (test-xception 1001 "Xception" #'thrift.test.thrift-test:test-exception thrift-cross::*prot* "Xception")) (signals thrift:application-error (thrift.test.thrift-test:test-exception thrift-cross::*prot* "TException")) (finishes (thrift.test.thrift-test:test-exception thrift-cross::*prot* "success"))) (deftest multi-exception-test () (is (test-xception 1001 "This is an Xception" #'thrift.test.thrift-test:test-multi-exception thrift-cross::*prot* "Xception" "meaningless")) (is (test-xception2 2002 "This is an Xception2" #'thrift.test.thrift-test:test-multi-exception thrift-cross::*prot* "Xception2" "meaningless too!")) (is (string= "foobar" (thrift.test:xtruct-string-thing (thrift.test.thrift-test:test-multi-exception thrift-cross::*prot* "success!" "foobar"))))) (fiasco:define-test-package #:misc) (in-package #:misc) (deftest oneway-test () (is (null (thrift.test.thrift-test:test-oneway thrift-cross::*prot* 1)))) (fiasco:define-test-package #:multiplex) (in-package #:multiplex) (deftest multiplex-test () ;; Removed from the IDL definition. ;; (finishes (thrift.test.second-service:blah-blah thrift-cross::*prot*)) (is (string= "asd" (thrift.test.second-service:secondtest-string thrift-cross::*prot* "asd")))) thrift-0.16.0/test/cpp/000077500000000000000000000000001420101504100146235ustar00rootroot00000000000000thrift-0.16.0/test/cpp/CMakeLists.txt000077500000000000000000000105131420101504100173660ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # The test executables still depend on Boost include(BoostMacros) REQUIRE_BOOST_HEADERS() set(BOOST_COMPONENTS filesystem program_options random) REQUIRE_BOOST_LIBRARIES(BOOST_COMPONENTS) # Contains the thrift specific target_link_libraries include(ThriftMacros) find_package(OpenSSL REQUIRED) include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") find_package(Libevent REQUIRED) # Libevent comes with CMake support from upstream include_directories(SYSTEM ${LIBEVENT_INCLUDE_DIRS}) find_package(ZLIB REQUIRED) include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS}) #Make sure gen-cpp files can be included include_directories("${CMAKE_CURRENT_BINARY_DIR}") include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp") include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src") set(crosstestgencpp_SOURCES gen-cpp/SecondService.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp src/ThriftTest_extras.cpp ) add_library(crosstestgencpp STATIC ${crosstestgencpp_SOURCES}) target_link_libraries(crosstestgencpp thrift) set(crossstressgencpp_SOURCES gen-cpp/Service.cpp ) add_library(crossstressgencpp STATIC ${crossstressgencpp_SOURCES}) target_link_libraries(crossstressgencpp thrift) set(crossspecificnamegencpp_SOURCES gen-cpp/EchoService.cpp gen-cpp/SpecificNameTest_types.cpp ) add_library(crossspecificnamegencpp STATIC ${crossspecificnamegencpp_SOURCES}) target_link_libraries(crossspecificnamegencpp thrift) add_executable(TestServer src/TestServer.cpp) target_link_libraries(TestServer crosstestgencpp ${Boost_LIBRARIES}) target_link_libraries(TestServer thriftnb) target_link_libraries(TestServer thriftz) add_executable(TestClient src/TestClient.cpp) target_link_libraries(TestClient crosstestgencpp ${Boost_LIBRARIES}) target_link_libraries(TestClient thriftnb) target_link_libraries(TestClient thriftz) add_executable(StressTest src/StressTest.cpp) target_link_libraries(StressTest crossstressgencpp ${Boost_LIBRARIES}) target_link_libraries(StressTest thriftnb) add_test(NAME StressTest COMMAND StressTest) add_test(NAME StressTestConcurrent COMMAND StressTest --client-type=concurrent) # As of https://jira.apache.org/jira/browse/THRIFT-4282, StressTestNonBlocking # is broken on Windows. Contributions welcome. if (NOT WIN32 AND NOT CYGWIN) add_executable(StressTestNonBlocking src/StressTestNonBlocking.cpp) target_link_libraries(StressTestNonBlocking crossstressgencpp ${Boost_LIBRARIES}) target_link_libraries(StressTestNonBlocking thriftnb) target_link_libraries(StressTestNonBlocking thriftz) add_test(NAME StressTestNonBlocking COMMAND StressTestNonBlocking) endif() add_executable(SpecificNameTest src/SpecificNameTest.cpp) target_link_libraries(SpecificNameTest crossspecificnamegencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB}) target_link_libraries(SpecificNameTest thrift) target_link_libraries(SpecificNameTest thriftnb) add_test(NAME SpecificNameTest COMMAND SpecificNameTest) # # Common thrift code generation rules # add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift ) add_custom_command(OUTPUT gen-cpp/Service.cpp COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/StressTest.thrift ) add_custom_command(OUTPUT gen-cpp/EchoService.cpp gen-cpp/SpecificNameTest_types.cpp COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/SpecificNameTest.thrift ) thrift-0.16.0/test/cpp/Makefile.am000077500000000000000000000073321420101504100166670ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # AUTOMAKE_OPTIONS = subdir-objects serial-tests nostdinc BUILT_SOURCES = gen-cpp/ThriftTest.cpp \ gen-cpp/ThriftTest_types.cpp \ gen-cpp/ThriftTest_constants.cpp \ gen-cpp/SecondService.cpp \ gen-cpp/Service.cpp noinst_LTLIBRARIES = libtestgencpp.la libstresstestgencpp.la nodist_libtestgencpp_la_SOURCES = \ gen-cpp/SecondService.cpp \ gen-cpp/SecondService.h \ gen-cpp/SecondService.tcc \ gen-cpp/ThriftTest_constants.cpp \ gen-cpp/ThriftTest_constants.h \ gen-cpp/ThriftTest_types.cpp \ gen-cpp/ThriftTest_types.h \ gen-cpp/ThriftTest_types.tcc \ gen-cpp/ThriftTest.cpp \ gen-cpp/ThriftTest.h \ gen-cpp/ThriftTest.tcc \ src/ThriftTest_extras.cpp libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la nodist_libstresstestgencpp_la_SOURCES = \ gen-cpp/StressTest_types.h \ gen-cpp/Service.cpp \ gen-cpp/Service.h libstresstestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la precross: TestServer TestClient check_PROGRAMS = \ TestServer \ TestClient \ StressTest \ StressTestNonBlocking # we currently do not run the testsuite, stop c++ server issue # TESTS = \ # $(check_PROGRAMS) TestServer_SOURCES = \ src/TestServer.cpp TestServer_LDADD = \ libtestgencpp.la \ $(top_builddir)/lib/cpp/libthrift.la \ $(top_builddir)/lib/cpp/libthriftz.la \ $(top_builddir)/lib/cpp/libthriftnb.la \ -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) TestClient_SOURCES = \ src/TestClient.cpp TestClient_LDADD = \ libtestgencpp.la \ $(top_builddir)/lib/cpp/libthrift.la \ $(top_builddir)/lib/cpp/libthriftz.la \ $(top_builddir)/lib/cpp/libthriftnb.la \ -levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS) StressTest_SOURCES = \ src/StressTest.cpp StressTest_LDADD = \ libstresstestgencpp.la \ $(top_builddir)/lib/cpp/libthrift.la StressTestNonBlocking_SOURCES = \ src/StressTestNonBlocking.cpp StressTestNonBlocking_LDADD = \ libstresstestgencpp.la \ $(top_builddir)/lib/cpp/libthriftnb.la \ -levent # # Common thrift code generation rules # gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT) $(THRIFT) --gen cpp:templates,cob_style -r $< gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT) $(THRIFT) --gen cpp $< gen-cpp/SpecificNameTest_types.cpp gen-cpp/EchoService.cpp: $(top_srcdir)/test/SpecificName.thrift $(THRIFT) $(THRIFT) --gen cpp $< AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp -I. AM_CXXFLAGS = -Wall -Wextra -pedantic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) $(ZLIB_LIBS) clean-local: $(RM) -r gen-cpp/ style-local: $(CPPSTYLE_CMD) EXTRA_DIST = \ src/TestClient.cpp \ src/TestServer.cpp \ src/StressTest.cpp \ src/StressTestNonBlocking.cpp thrift-0.16.0/test/cpp/src/000077500000000000000000000000001420101504100154125ustar00rootroot00000000000000thrift-0.16.0/test/cpp/src/SpecificNameTest.cpp000066400000000000000000000020071420101504100213030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ int main(int argc, char** argv) { //Empty in main function, //because we just want to test //whether the generated source code //(IDL file contains struct named as //'a' or 'b') can be compiled. return 0; } thrift-0.16.0/test/cpp/src/StressTest.cpp000066400000000000000000000426611420101504100202520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Service.h" #include #include #include #include #include #if _WIN32 #include #endif using namespace std; using namespace apache::thrift; using namespace apache::thrift::async; using namespace apache::thrift::protocol; using namespace apache::thrift::transport; using namespace apache::thrift::server; using namespace apache::thrift::concurrency; using namespace test::stress; struct eqstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; } }; struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; // typedef hash_map, eqstr> count_map; typedef map count_map; class Server : public ServiceIf { public: Server() = default; void count(const char* method) { Guard m(lock_); int ct = counts_[method]; counts_[method] = ++ct; } void echoVoid() override { count("echoVoid"); return; } count_map getCount() { Guard m(lock_); return counts_; } int8_t echoByte(const int8_t arg) override { return arg; } int32_t echoI32(const int32_t arg) override { return arg; } int64_t echoI64(const int64_t arg) override { return arg; } void echoString(string& out, const string& arg) override { if (arg != "hello") { T_ERROR_ABORT("WRONG STRING (%s)!!!!", arg.c_str()); } out = arg; } void echoList(vector& out, const vector& arg) override { out = arg; } void echoSet(set& out, const set& arg) override { out = arg; } void echoMap(map& out, const map& arg) override { out = arg; } private: count_map counts_; Mutex lock_; }; enum TransportOpenCloseBehavior { OpenAndCloseTransportInThread, DontOpenAndCloseTransportInThread }; class ClientThread : public Runnable { public: ClientThread(std::shared_ptr transport, std::shared_ptr client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType, TransportOpenCloseBehavior behavior) : _transport(transport), _client(client), _monitor(monitor), _workerCount(workerCount), _loopCount(loopCount), _loopType(loopType), _behavior(behavior) {} void run() override { // Wait for all worker threads to start { Synchronized s(_monitor); while (_workerCount == 0) { _monitor.wait(); } } _startTime = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); if(_behavior == OpenAndCloseTransportInThread) { _transport->open(); } switch (_loopType) { case T_VOID: loopEchoVoid(); break; case T_BYTE: loopEchoByte(); break; case T_I32: loopEchoI32(); break; case T_I64: loopEchoI64(); break; case T_STRING: loopEchoString(); break; default: cerr << "Unexpected loop type" << _loopType << endl; break; } _endTime = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); if(_behavior == OpenAndCloseTransportInThread) { _transport->close(); } _done = true; { Synchronized s(_monitor); _workerCount--; if (_workerCount == 0) { _monitor.notify(); } } } void loopEchoVoid() { for (size_t ix = 0; ix < _loopCount; ix++) { _client->echoVoid(); } } void loopEchoByte() { for (size_t ix = 0; ix < _loopCount; ix++) { int8_t arg = 1; int8_t result; result = _client->echoByte(arg); (void)result; assert(result == arg); } } void loopEchoI32() { for (size_t ix = 0; ix < _loopCount; ix++) { int32_t arg = 1; int32_t result; result = _client->echoI32(arg); (void)result; assert(result == arg); } } void loopEchoI64() { for (size_t ix = 0; ix < _loopCount; ix++) { int64_t arg = 1; int64_t result; result = _client->echoI64(arg); (void)result; assert(result == arg); } } void loopEchoString() { for (size_t ix = 0; ix < _loopCount; ix++) { string arg = "hello"; string result; _client->echoString(result, arg); assert(result == arg); } } std::shared_ptr _transport; std::shared_ptr _client; Monitor& _monitor; size_t& _workerCount; size_t _loopCount; TType _loopType; int64_t _startTime; int64_t _endTime; bool _done; Monitor _sleep; TransportOpenCloseBehavior _behavior; }; class TStartObserver : public apache::thrift::server::TServerEventHandler { public: TStartObserver() : awake_(false) {} void preServe() override { apache::thrift::concurrency::Synchronized s(m_); awake_ = true; m_.notifyAll(); } void waitForService() { apache::thrift::concurrency::Synchronized s(m_); while (!awake_) m_.waitForever(); } private: apache::thrift::concurrency::Monitor m_; bool awake_; }; int main(int argc, char** argv) { #if _WIN32 transport::TWinsockSingleton::create(); #endif int port = 9091; string clientType = "regular"; string serverType = "thread-pool"; string protocolType = "binary"; size_t workerCount = 8; size_t clientCount = 4; size_t loopCount = 50000; TType loopType = T_VOID; string callName = "echoVoid"; bool runServer = true; bool logRequests = false; string requestLogPath = "./requestlog.tlog"; bool replayRequests = false; ostringstream usage; usage << argv[0] << " [--port=] [--server] [--server-type=] " "[--protocol-type=] [--workers=] " "[--clients=] [--loop=] " "[--client-type=]" << endl << "\tclients Number of client threads to create - 0 implies no clients, i.e. " "server only. Default is " << clientCount << endl << "\thelp Prints this help text." << endl << "\tcall Service method to call. Default is " << callName << endl << "\tloop The number of remote thrift calls each client makes. Default is " << loopCount << endl << "\tport The port the server and clients should bind to " "for thrift network connections. Default is " << port << endl << "\tserver Run the Thrift server in this process. Default is " << runServer << endl << "\tserver-type Type of server, \"simple\" or \"thread-pool\". Default is " << serverType << endl << "\tprotocol-type Type of protocol, \"binary\", \"ascii\", or \"xml\". Default is " << protocolType << endl << "\tlog-request Log all request to ./requestlog.tlog. Default is " << logRequests << endl << "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl << "\tworkers Number of thread pools workers. Only valid " "for thread-pool server type. Default is " << workerCount << endl << "\tclient-type Type of client, \"regular\" or \"concurrent\". Default is " << clientType << endl << endl; map args; for (int ix = 1; ix < argc; ix++) { string arg(argv[ix]); if (arg.compare(0, 2, "--") == 0) { size_t end = arg.find_first_of("=", 2); string key = string(arg, 2, end - 2); if (end != string::npos) { args[key] = string(arg, end + 1); } else { args[key] = "true"; } } else { throw invalid_argument("Unexcepted command line token: " + arg); } } try { if (!args["clients"].empty()) { clientCount = atoi(args["clients"].c_str()); } if (!args["help"].empty()) { cerr << usage.str(); return 0; } if (!args["loop"].empty()) { loopCount = atoi(args["loop"].c_str()); } if (!args["call"].empty()) { callName = args["call"]; } if (!args["port"].empty()) { port = atoi(args["port"].c_str()); } if (!args["server"].empty()) { runServer = args["server"] == "true"; } if (!args["log-request"].empty()) { logRequests = args["log-request"] == "true"; } if (!args["replay-request"].empty()) { replayRequests = args["replay-request"] == "true"; } if (!args["server-type"].empty()) { serverType = args["server-type"]; if (serverType == "simple") { } else if (serverType == "thread-pool") { } else if (serverType == "threaded") { } else { throw invalid_argument("Unknown server type " + serverType); } } if (!args["client-type"].empty()) { clientType = args["client-type"]; if (clientType == "regular") { } else if (clientType == "concurrent") { } else { throw invalid_argument("Unknown client type " + clientType); } } if (!args["workers"].empty()) { workerCount = atoi(args["workers"].c_str()); } } catch (std::exception& e) { cerr << e.what() << endl; cerr << usage.str(); } std::shared_ptr threadFactory = std::shared_ptr(new ThreadFactory()); // Dispatcher std::shared_ptr serviceHandler(new Server()); if (replayRequests) { std::shared_ptr serviceHandler(new Server()); std::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); // Transports std::shared_ptr fileTransport(new TFileTransport(requestLogPath)); fileTransport->setChunkSize(2 * 1024 * 1024); fileTransport->setMaxEventSize(1024 * 16); fileTransport->seekToEnd(); // Protocol Factory std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); TFileProcessor fileProcessor(serviceProcessor, protocolFactory, fileTransport); fileProcessor.process(0, true); exit(0); } if (runServer) { std::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); // Transport std::shared_ptr serverSocket(new TServerSocket(port)); // Transport Factory std::shared_ptr transportFactory(new TBufferedTransportFactory()); // Protocol Factory std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); if (logRequests) { // initialize the log file std::shared_ptr fileTransport(new TFileTransport(requestLogPath)); fileTransport->setChunkSize(2 * 1024 * 1024); fileTransport->setMaxEventSize(1024 * 16); transportFactory = std::shared_ptr(new TPipedTransportFactory(fileTransport)); } std::shared_ptr server; if (serverType == "simple") { server.reset( new TSimpleServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)); } else if (serverType == "threaded") { server.reset( new TThreadedServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)); } else if (serverType == "thread-pool") { std::shared_ptr threadManager = ThreadManager::newSimpleThreadManager(workerCount); threadManager->threadFactory(threadFactory); threadManager->start(); server.reset(new TThreadPoolServer(serviceProcessor, serverSocket, transportFactory, protocolFactory, threadManager)); } std::shared_ptr observer(new TStartObserver); server->setServerEventHandler(observer); std::shared_ptr serverThread = threadFactory->newThread(server); cerr << "Starting the server on port " << port << endl; serverThread->start(); observer->waitForService(); // If we aren't running clients, just wait forever for external clients if (clientCount == 0) { serverThread->join(); } } if (clientCount > 0) { //FIXME: start here for client type? Monitor monitor; size_t threadCount = 0; set > clientThreads; if (callName == "echoVoid") { loopType = T_VOID; } else if (callName == "echoByte") { loopType = T_BYTE; } else if (callName == "echoI32") { loopType = T_I32; } else if (callName == "echoI64") { loopType = T_I64; } else if (callName == "echoString") { loopType = T_STRING; } else { throw invalid_argument("Unknown service call " + callName); } if(clientType == "regular") { for (size_t ix = 0; ix < clientCount; ix++) { std::shared_ptr socket(new TSocket("127.0.0.1", port)); std::shared_ptr bufferedSocket(new TBufferedTransport(socket, 2048)); std::shared_ptr protocol(new TBinaryProtocol(bufferedSocket)); std::shared_ptr serviceClient(new ServiceClient(protocol)); clientThreads.insert(threadFactory->newThread(std::shared_ptr( new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType, OpenAndCloseTransportInThread)))); } } else if(clientType == "concurrent") { std::shared_ptr socket(new TSocket("127.0.0.1", port)); std::shared_ptr bufferedSocket(new TBufferedTransport(socket, 2048)); std::shared_ptr protocol(new TBinaryProtocol(bufferedSocket)); auto sync = std::make_shared(); std::shared_ptr serviceClient(new ServiceConcurrentClient(protocol, sync)); socket->open(); for (size_t ix = 0; ix < clientCount; ix++) { clientThreads.insert(threadFactory->newThread(std::shared_ptr( new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType, DontOpenAndCloseTransportInThread)))); } } for (auto thread = clientThreads.begin(); thread != clientThreads.end(); thread++) { (*thread)->start(); } int64_t time00; int64_t time01; { Synchronized s(monitor); threadCount = clientCount; cerr << "Launch " << clientCount << " " << clientType << " client threads" << endl; time00 = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); monitor.notifyAll(); while (threadCount > 0) { monitor.wait(); } time01 = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); } int64_t firstTime = 9223372036854775807LL; int64_t lastTime = 0; double averageTime = 0; int64_t minTime = 9223372036854775807LL; int64_t maxTime = 0; for (auto ix = clientThreads.begin(); ix != clientThreads.end(); ix++) { std::shared_ptr client = std::dynamic_pointer_cast((*ix)->runnable()); int64_t delta = client->_endTime - client->_startTime; assert(delta > 0); if (client->_startTime < firstTime) { firstTime = client->_startTime; } if (client->_endTime > lastTime) { lastTime = client->_endTime; } if (delta < minTime) { minTime = delta; } if (delta > maxTime) { maxTime = delta; } averageTime += delta; } averageTime /= clientCount; cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl; count_map count = serviceHandler->getCount(); count_map::iterator iter; for (iter = count.begin(); iter != count.end(); ++iter) { printf("%s => %d\n", iter->first, iter->second); } cerr << "done." << endl; } return 0; } thrift-0.16.0/test/cpp/src/StressTestNonBlocking.cpp000066400000000000000000000370211420101504100223700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Service.h" #include #include #include #include #include #if _WIN32 #include #endif using namespace std; using namespace apache::thrift; using namespace apache::thrift::protocol; using namespace apache::thrift::transport; using namespace apache::thrift::server; using namespace apache::thrift::concurrency; using namespace test::stress; struct eqstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; } }; struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; // typedef hash_map, eqstr> count_map; typedef map count_map; class Server : public ServiceIf { public: Server() = default; void count(const char* method) { Guard m(lock_); int ct = counts_[method]; counts_[method] = ++ct; } void echoVoid() override { count("echoVoid"); // Sleep to simulate work THRIFT_SLEEP_USEC(1); return; } count_map getCount() { Guard m(lock_); return counts_; } int8_t echoByte(const int8_t arg) override { return arg; } int32_t echoI32(const int32_t arg) override { return arg; } int64_t echoI64(const int64_t arg) override { return arg; } void echoString(string& out, const string& arg) override { if (arg != "hello") { T_ERROR_ABORT("WRONG STRING (%s)!!!!", arg.c_str()); } out = arg; } void echoList(vector& out, const vector& arg) override { out = arg; } void echoSet(set& out, const set& arg) override { out = arg; } void echoMap(map& out, const map& arg) override { out = arg; } private: count_map counts_; Mutex lock_; }; class ClientThread : public Runnable { public: ClientThread(std::shared_ptr transport, std::shared_ptr client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType) : _transport(transport), _client(client), _monitor(monitor), _workerCount(workerCount), _loopCount(loopCount), _loopType(loopType) {} void run() override { // Wait for all worker threads to start { Synchronized s(_monitor); while (_workerCount == 0) { _monitor.wait(); } } _startTime = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); _transport->open(); switch (_loopType) { case T_VOID: loopEchoVoid(); break; case T_BYTE: loopEchoByte(); break; case T_I32: loopEchoI32(); break; case T_I64: loopEchoI64(); break; case T_STRING: loopEchoString(); break; default: cerr << "Unexpected loop type" << _loopType << endl; break; } _endTime = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); _transport->close(); _done = true; { Synchronized s(_monitor); _workerCount--; if (_workerCount == 0) { _monitor.notify(); } } } void loopEchoVoid() { for (size_t ix = 0; ix < _loopCount; ix++) { _client->echoVoid(); } } void loopEchoByte() { for (size_t ix = 0; ix < _loopCount; ix++) { int8_t arg = 1; int8_t result; result = _client->echoByte(arg); (void)result; assert(result == arg); } } void loopEchoI32() { for (size_t ix = 0; ix < _loopCount; ix++) { int32_t arg = 1; int32_t result; result = _client->echoI32(arg); (void)result; assert(result == arg); } } void loopEchoI64() { for (size_t ix = 0; ix < _loopCount; ix++) { int64_t arg = 1; int64_t result; result = _client->echoI64(arg); (void)result; assert(result == arg); } } void loopEchoString() { for (size_t ix = 0; ix < _loopCount; ix++) { string arg = "hello"; string result; _client->echoString(result, arg); assert(result == arg); } } std::shared_ptr _transport; std::shared_ptr _client; Monitor& _monitor; size_t& _workerCount; size_t _loopCount; TType _loopType; int64_t _startTime; int64_t _endTime; bool _done; Monitor _sleep; }; int main(int argc, char** argv) { #if _WIN32 transport::TWinsockSingleton::create(); #endif int port = 9091; string serverType = "simple"; string protocolType = "binary"; uint32_t workerCount = 4; uint32_t clientCount = 20; uint32_t loopCount = 1000; TType loopType = T_VOID; string callName = "echoVoid"; bool runServer = true; bool logRequests = false; string requestLogPath = "./requestlog.tlog"; bool replayRequests = false; ostringstream usage; usage << argv[0] << " [--port=] [--server] [--server-type=] " "[--protocol-type=] [--workers=] " "[--clients=] [--loop=]" << endl << "\tclients Number of client threads to create - 0 implies no clients, i.e. " "server only. Default is " << clientCount << endl << "\thelp Prints this help text." << endl << "\tcall Service method to call. Default is " << callName << endl << "\tloop The number of remote thrift calls each client makes. Default is " << loopCount << endl << "\tport The port the server and clients should bind to " "for thrift network connections. Default is " << port << endl << "\tserver Run the Thrift server in this process. Default is " << runServer << endl << "\tserver-type Type of server, \"simple\" or \"thread-pool\". Default is " << serverType << endl << "\tprotocol-type Type of protocol, \"binary\", \"ascii\", or \"xml\". Default is " << protocolType << endl << "\tlog-request Log all request to ./requestlog.tlog. Default is " << logRequests << endl << "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl << "\tworkers Number of thread pools workers. Only valid " "for thread-pool server type. Default is " << workerCount << endl; map args; for (int ix = 1; ix < argc; ix++) { string arg(argv[ix]); if (arg.compare(0, 2, "--") == 0) { size_t end = arg.find_first_of("=", 2); string key = string(arg, 2, end - 2); if (end != string::npos) { args[key] = string(arg, end + 1); } else { args[key] = "true"; } } else { throw invalid_argument("Unexcepted command line token: " + arg); } } try { if (!args["clients"].empty()) { clientCount = atoi(args["clients"].c_str()); } if (!args["help"].empty()) { cerr << usage.str(); return 0; } if (!args["loop"].empty()) { loopCount = atoi(args["loop"].c_str()); } if (!args["call"].empty()) { callName = args["call"]; } if (!args["port"].empty()) { port = atoi(args["port"].c_str()); } if (!args["server"].empty()) { runServer = args["server"] == "true"; } if (!args["log-request"].empty()) { logRequests = args["log-request"] == "true"; } if (!args["replay-request"].empty()) { replayRequests = args["replay-request"] == "true"; } if (!args["server-type"].empty()) { serverType = args["server-type"]; } if (!args["workers"].empty()) { workerCount = atoi(args["workers"].c_str()); } } catch (std::exception& e) { cerr << e.what() << endl; cerr << usage.str(); } std::shared_ptr threadFactory = std::shared_ptr(new ThreadFactory()); // Dispatcher std::shared_ptr serviceHandler(new Server()); if (replayRequests) { std::shared_ptr serviceHandler(new Server()); std::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); // Transports std::shared_ptr fileTransport(new TFileTransport(requestLogPath)); fileTransport->setChunkSize(2 * 1024 * 1024); fileTransport->setMaxEventSize(1024 * 16); fileTransport->seekToEnd(); // Protocol Factory std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); TFileProcessor fileProcessor(serviceProcessor, protocolFactory, fileTransport); fileProcessor.process(0, true); exit(0); } if (runServer) { std::shared_ptr serviceProcessor(new ServiceProcessor(serviceHandler)); // Protocol Factory std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); // Transport Factory std::shared_ptr transportFactory; if (logRequests) { // initialize the log file std::shared_ptr fileTransport(new TFileTransport(requestLogPath)); fileTransport->setChunkSize(2 * 1024 * 1024); fileTransport->setMaxEventSize(1024 * 16); transportFactory = std::shared_ptr(new TPipedTransportFactory(fileTransport)); } std::shared_ptr serverThread; std::shared_ptr serverThread2; std::shared_ptr nbSocket1; std::shared_ptr nbSocket2; if (serverType == "simple") { nbSocket1.reset(new transport::TNonblockingServerSocket(port)); serverThread = threadFactory->newThread(std::shared_ptr( new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket1))); nbSocket2.reset(new transport::TNonblockingServerSocket(port + 1)); serverThread2 = threadFactory->newThread(std::shared_ptr( new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket2))); } else if (serverType == "thread-pool") { std::shared_ptr threadManager = ThreadManager::newSimpleThreadManager(workerCount); threadManager->threadFactory(threadFactory); threadManager->start(); nbSocket1.reset(new transport::TNonblockingServerSocket(port)); serverThread = threadFactory->newThread(std::shared_ptr( new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket1, threadManager))); nbSocket2.reset(new transport::TNonblockingServerSocket(port + 1)); serverThread2 = threadFactory->newThread(std::shared_ptr( new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket2, threadManager))); } cerr << "Starting the server on port " << port << " and " << (port + 1) << endl; serverThread->start(); serverThread2->start(); // If we aren't running clients, just wait forever for external clients if (clientCount == 0) { serverThread->join(); serverThread2->join(); } } THRIFT_SLEEP_SEC(1); if (clientCount > 0) { Monitor monitor; size_t threadCount = 0; set > clientThreads; if (callName == "echoVoid") { loopType = T_VOID; } else if (callName == "echoByte") { loopType = T_BYTE; } else if (callName == "echoI32") { loopType = T_I32; } else if (callName == "echoI64") { loopType = T_I64; } else if (callName == "echoString") { loopType = T_STRING; } else { throw invalid_argument("Unknown service call " + callName); } for (uint32_t ix = 0; ix < clientCount; ix++) { std::shared_ptr socket(new TSocket("127.0.0.1", port + (ix % 2))); std::shared_ptr framedSocket(new TFramedTransport(socket)); std::shared_ptr protocol(new TBinaryProtocol(framedSocket)); std::shared_ptr serviceClient(new ServiceClient(protocol)); clientThreads.insert(threadFactory->newThread(std::shared_ptr( new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType)))); } for (auto thread = clientThreads.begin(); thread != clientThreads.end(); thread++) { (*thread)->start(); } int64_t time00; int64_t time01; { Synchronized s(monitor); threadCount = clientCount; cerr << "Launch " << clientCount << " client threads" << endl; time00 = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); monitor.notifyAll(); while (threadCount > 0) { monitor.wait(); } time01 = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); } int64_t firstTime = 9223372036854775807LL; int64_t lastTime = 0; double averageTime = 0; int64_t minTime = 9223372036854775807LL; int64_t maxTime = 0; for (auto ix = clientThreads.begin(); ix != clientThreads.end(); ix++) { std::shared_ptr client = std::dynamic_pointer_cast((*ix)->runnable()); int64_t delta = client->_endTime - client->_startTime; assert(delta > 0); if (client->_startTime < firstTime) { firstTime = client->_startTime; } if (client->_endTime > lastTime) { lastTime = client->_endTime; } if (delta < minTime) { minTime = delta; } if (delta > maxTime) { maxTime = delta; } averageTime += delta; } averageTime /= clientCount; cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl; count_map count = serviceHandler->getCount(); count_map::iterator iter; for (iter = count.begin(); iter != count.end(); ++iter) { printf("%s => %d\n", iter->first, iter->second); } cerr << "done." << endl; } return 0; } thrift-0.16.0/test/cpp/src/TestClient.cpp000066400000000000000000001226441420101504100202050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #include #include #include #include #if _WIN32 #include #endif #include "SecondService.h" #include "ThriftTest.h" using namespace std; using namespace apache::thrift; using namespace apache::thrift::async; using namespace apache::thrift::protocol; using namespace apache::thrift::transport; using namespace thrift::test; // // A pedantic protocol that checks to make sure the response sequence ID // is the same as the sent sequence ID. lib/cpp always sends zero for // synchronous clients, so this bumps the number to make sure it gets // returned properly from the remote server. Any server that does not // respond with the same sequence number is violating the sequence ID // agreement between client and server. // template class TPedanticProtocol : public Proto { public: TPedanticProtocol(std::shared_ptr& transport) : Proto(transport), m_last_seqid((std::numeric_limits::max)() - 10) { } virtual uint32_t writeMessageBegin_virt(const std::string& name, const TMessageType messageType, const int32_t in_seqid) override { int32_t seqid = in_seqid; if (!seqid) { // this is typical for normal cpp generated code seqid = ++m_last_seqid; } return Proto::writeMessageBegin_virt(name, messageType, seqid); } virtual uint32_t readMessageBegin_virt(std::string& name, TMessageType& messageType, int32_t& seqid) override { uint32_t result = Proto::readMessageBegin_virt(name, messageType, seqid); if (seqid != m_last_seqid) { std::stringstream ss; ss << "ERROR: send request with seqid " << m_last_seqid << " and got reply with seqid " << seqid; throw std::logic_error(ss.str()); } /* else { std::cout << "verified seqid " << m_last_seqid << " round trip OK" << std::endl; } */ return result; } private: int32_t m_last_seqid; }; // Current time, microseconds since the epoch uint64_t now() { int64_t ret; struct timeval tv; THRIFT_GETTIMEOFDAY(&tv, nullptr); ret = tv.tv_sec; ret = ret * 1000 * 1000 + tv.tv_usec; return ret; } static void testString_clientReturn(event_base* base, int testNr, ThriftTestCobClient* client) { try { string s; client->recv_testString(s); std::ostringstream os; os << "test" << testNr; const bool ok = (s == os.str()); cout << "testString: " << s << " " << ((ok) ? "ok" : "failed") << endl; } catch (TException& exn) { cout << "Error: " << exn.what() << endl; } if (testNr == 9) event_base_loopbreak(base); // end test } static void testVoid_clientReturn(event_base* base, ThriftTestCobClient* client) { try { client->recv_testVoid(); cout << "testVoid" << endl; for (int testNr = 0; testNr < 10; ++testNr) { std::ostringstream os; os << "test" << testNr; client->testString(std::bind(testString_clientReturn, base, testNr, std::placeholders::_1), os.str()); } } catch (TException& exn) { cout << "Error: " << exn.what() << endl; } } // Workaround for absense of C++11 "auto" keyword. template bool print_eq(T expected, T actual) { cout << "(" << actual << ")" << endl; if (expected != actual) { cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl; return false; } return true; } #define BASETYPE_IDENTITY_TEST(func, value) \ cout << #func "(" << value << ") = "; \ try { \ if (!print_eq(value, testClient.func(value))) \ return_code |= ERR_BASETYPES; \ } catch (TTransportException&) { \ throw; \ } catch (exception & ex) { \ cout << "*** FAILED ***" << endl << ex.what() << endl; \ return_code |= ERR_BASETYPES; \ } int binary_test(ThriftTestClient& testClient, string::size_type siz); BOOST_CONSTEXPR_OR_CONST int ERR_BASETYPES = 1; BOOST_CONSTEXPR_OR_CONST int ERR_STRUCTS = 2; BOOST_CONSTEXPR_OR_CONST int ERR_CONTAINERS = 4; BOOST_CONSTEXPR_OR_CONST int ERR_EXCEPTIONS = 8; BOOST_CONSTEXPR_OR_CONST int ERR_UNKNOWN = 64; int main(int argc, char** argv) { cout.precision(19); string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string(); string caPath = testDir + "/keys/CA.pem"; string certPath = testDir + "/keys/client.crt"; string keyPath = testDir + "/keys/client.key"; #if _WIN32 transport::TWinsockSingleton::create(); #endif string host = "localhost"; int port = 9090; int numTests = 1; bool ssl = false; bool zlib = false; string transport_type = "buffered"; string protocol_type = "binary"; string domain_socket = ""; bool abstract_namespace = false; bool noinsane = false; int return_code = 0; boost::program_options::options_description desc("Allowed options"); desc.add_options() ("help,h", "produce help message") ("host", boost::program_options::value(&host)->default_value(host), "Host to connect") ("port", boost::program_options::value(&port)->default_value(port), "Port number to connect") ("domain-socket", boost::program_options::value(&domain_socket)->default_value(domain_socket), "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port") ("abstract-namespace", "Look for the domain socket in the Abstract Namespace" " (no connection with filesystem pathnames)") ("transport", boost::program_options::value(&transport_type)->default_value(transport_type), "Transport: buffered, framed, http, evhttp, zlib") ("protocol", boost::program_options::value(&protocol_type)->default_value(protocol_type), "Protocol: binary, compact, header, json, multi, multic, multih, multij") ("ssl", "Encrypted Transport using SSL") ("zlib", "Wrap Transport with Zlib") ("testloops,n", boost::program_options::value(&numTests)->default_value(numTests), "Number of Tests") ("noinsane", "Do not run insanity test"); boost::program_options::variables_map vm; boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); boost::program_options::notify(vm); if (vm.count("help")) { cout << desc << endl; return ERR_UNKNOWN; } try { if (!protocol_type.empty()) { if (protocol_type == "binary") { } else if (protocol_type == "compact") { } else if (protocol_type == "header") { } else if (protocol_type == "json") { } else if (protocol_type == "multi") { } else if (protocol_type == "multic") { } else if (protocol_type == "multih") { } else if (protocol_type == "multij") { } else { throw invalid_argument("Unknown protocol type " + protocol_type); } } if (!transport_type.empty()) { if (transport_type == "buffered") { } else if (transport_type == "framed") { } else if (transport_type == "http") { } else if (transport_type == "evhttp") { } else if (transport_type == "zlib") { // crosstest will pass zlib as a transport and as a flag right now.. } else { throw invalid_argument("Unknown transport type " + transport_type); } } } catch (exception& e) { cerr << e.what() << endl; cout << desc << endl; return ERR_UNKNOWN; } if (vm.count("ssl")) { ssl = true; } if (vm.count("zlib")) { zlib = true; } if (vm.count("abstract-namespace")) { abstract_namespace = true; } if (vm.count("noinsane")) { noinsane = true; } // THRIFT-4164: The factory MUST outlive any sockets it creates for correct behavior! std::shared_ptr factory; std::shared_ptr socket; std::shared_ptr transport; std::shared_ptr protocol; std::shared_ptr protocol2; // SecondService for multiplexed if (ssl) { cout << "Client Certificate File: " << certPath << endl; cout << "Client Key File: " << keyPath << endl; cout << "CA File: " << caPath << endl; factory = std::shared_ptr(new TSSLSocketFactory()); factory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); factory->loadTrustedCertificates(caPath.c_str()); factory->loadCertificate(certPath.c_str()); factory->loadPrivateKey(keyPath.c_str()); factory->authenticate(true); socket = factory->createSocket(host, port); } else { if (domain_socket != "") { if (abstract_namespace) { std::string abstract_socket("\0", 1); abstract_socket += domain_socket; socket = std::shared_ptr(new TSocket(abstract_socket)); } else { socket = std::shared_ptr(new TSocket(domain_socket)); } port = 0; } else { socket = std::shared_ptr(new TSocket(host, port)); } } if (transport_type.compare("http") == 0) { transport = std::make_shared(socket, host, "/service"); } else if (transport_type.compare("framed") == 0) { transport = std::make_shared(socket); } else { transport = std::make_shared(socket); } if (zlib) { transport = std::make_shared(transport); } if (protocol_type == "json" || protocol_type == "multij") { typedef TPedanticProtocol TPedanticJSONProtocol; protocol = std::make_shared(transport); } else if (protocol_type == "compact" || protocol_type == "multic") { typedef TPedanticProtocol TPedanticCompactProtocol; protocol = std::make_shared(transport); } else if (protocol_type == "header" || protocol_type == "multih") { typedef TPedanticProtocol TPedanticHeaderProtocol; protocol = std::make_shared(transport); } else { typedef TPedanticProtocol TPedanticBinaryProtocol; protocol = std::make_shared(transport); } if (boost::starts_with(protocol_type, "multi")) { protocol2 = std::make_shared(protocol, "SecondService"); // we don't need access to the original protocol any more, so... protocol = std::make_shared(protocol, "ThriftTest"); } // Connection info cout << "Connecting (" << transport_type << "/" << protocol_type << ") to: "; if (abstract_namespace) { cout << '@'; } cout << domain_socket; if (port != 0) { cout << host << ":" << port; } cout << endl; if (transport_type.compare("evhttp") == 0) { event_base* base = event_base_new(); cout << "Libevent Version: " << event_get_version() << endl; cout << "Libevent Method: " << event_base_get_method(base) << endl; #if LIBEVENT_VERSION_NUMBER >= 0x02000000 cout << "Libevent Features: 0x" << hex << event_base_get_features(base) << endl; #endif std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); std::shared_ptr channel( new TEvhttpClientChannel(host.c_str(), "/", host.c_str(), port, base)); ThriftTestCobClient* client = new ThriftTestCobClient(channel, protocolFactory.get()); client->testVoid(std::bind(testVoid_clientReturn, base, std::placeholders::_1)); event_base_loop(base, 0); return 0; } ThriftTestClient testClient(protocol); uint64_t time_min = 0; uint64_t time_max = 0; uint64_t time_tot = 0; int test = 0; for (test = 0; test < numTests; ++test) { try { transport->open(); } catch (TTransportException& ex) { cout << "Connect failed: " << ex.what() << endl; return ERR_UNKNOWN; } /** * CONNECT TEST */ printf("Test #%d, connect %s:%d\n", test + 1, host.c_str(), port); uint64_t start = now(); /** * VOID TEST */ try { cout << "testVoid()" << flush; testClient.testVoid(); cout << " = void" << endl; } catch (TTransportException&) { // Stop here if transport got broken throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_BASETYPES; } /** * STRING TEST */ cout << "testString(\"Test\")" << flush; string s; testClient.testString(s, "Test"); cout << " = " << s << endl; if (s != "Test") { cout << "*** FAILED ***" << endl; return_code |= ERR_BASETYPES; } // // Multiplexed protocol - call another service method // in the middle of the ThriftTest // if (boost::starts_with(protocol_type, "multi")) { SecondServiceClient ssc(protocol2); // transport is already open... try { cout << "secondService.secondTestString(\"foo\") => " << flush; std::string result; ssc.secondtestString(result, "foo"); cout << "{" << result << "}" << endl; } catch (std::exception& e) { cout << " *** FAILED *** " << e.what() << endl; return_code |= ERR_EXCEPTIONS; } } try { #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4566 ) #endif string str( "}{Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " "Bân-lâm-gú, 粵語"); #ifdef _MSC_VER #pragma warning( pop ) #endif cout << "testString(" << str << ") = " << flush; testClient.testString(s, str); cout << s << endl; if (s != str) { cout.imbue(locale("en_US.UTF8")); cout << "*** FAILED ***" << endl << "Expected string: " << str << " but got: " << s << endl << "CLEAR"; return_code |= ERR_BASETYPES; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_BASETYPES; return return_code; } try { string str( "quote: \" backslash:" " forwardslash-escaped: \\/ " " backspace: \b formfeed: \f newline: \n return: \r tab: " " now-all-of-them-together: \"\\\\/\b\n\r\t" " now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><" " char-to-test-json-parsing: ]] \"]] \\\" }}}{ [[[ "); cout << "testString(" << str << ") = " << flush; testClient.testString(s, str); cout << s << endl; if (s != str) { cout.imbue(locale("en_US.UTF8")); cout << "*** FAILED ***" << endl << "Expected string: " << str << " but got: " << s << endl << "CLEAR"; ; return_code |= ERR_BASETYPES; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_BASETYPES; return return_code; } /** * BOOL TEST */ cout << boolalpha; BASETYPE_IDENTITY_TEST(testBool, true); BASETYPE_IDENTITY_TEST(testBool, false); /** * BYTE TEST */ BASETYPE_IDENTITY_TEST(testByte, (int8_t)0); BASETYPE_IDENTITY_TEST(testByte, (int8_t)-1); BASETYPE_IDENTITY_TEST(testByte, (int8_t)42); BASETYPE_IDENTITY_TEST(testByte, (int8_t)-42); BASETYPE_IDENTITY_TEST(testByte, (int8_t)127); BASETYPE_IDENTITY_TEST(testByte, (int8_t)-128); /** * I32 TEST */ BASETYPE_IDENTITY_TEST(testI32, 0); BASETYPE_IDENTITY_TEST(testI32, -1); BASETYPE_IDENTITY_TEST(testI32, 190000013); BASETYPE_IDENTITY_TEST(testI32, -190000013); BASETYPE_IDENTITY_TEST(testI32, (numeric_limits::max)()); BASETYPE_IDENTITY_TEST(testI32, (numeric_limits::min)()); /** * I64 TEST */ BASETYPE_IDENTITY_TEST(testI64, (int64_t)0); BASETYPE_IDENTITY_TEST(testI64, (int64_t)-1); BASETYPE_IDENTITY_TEST(testI64, (int64_t)7000000000000000123LL); BASETYPE_IDENTITY_TEST(testI64, (int64_t)-7000000000000000123LL); BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast(2LL), 32)); BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast(2LL), 32)); BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast(2LL), 32) + 1); BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast(2LL), 32) - 1); BASETYPE_IDENTITY_TEST(testI64, (numeric_limits::max)()); BASETYPE_IDENTITY_TEST(testI64, (numeric_limits::min)()); /** * DOUBLE TEST */ // Comparing double values with plain equality because Thrift handles full precision of double BASETYPE_IDENTITY_TEST(testDouble, 0.0); BASETYPE_IDENTITY_TEST(testDouble, -1.0); BASETYPE_IDENTITY_TEST(testDouble, -5.2098523); BASETYPE_IDENTITY_TEST(testDouble, -0.000341012439638598279); BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast(2), 32)); BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast(2), 32) + 1); BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast(2), 53) - 1); BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast(2), 32)); BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast(2), 32) - 1); BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast(2), 53) + 1); try { double expected = pow(static_cast(10), 307); cout << "testDouble(" << expected << ") = " << flush; double actual = testClient.testDouble(expected); cout << "(" << actual << ")" << endl; if (expected - actual > pow(static_cast(10), 292)) { cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_BASETYPES; } try { double expected = pow(static_cast(10), -292); cout << "testDouble(" << expected << ") = " << flush; double actual = testClient.testDouble(expected); cout << "(" << actual << ")" << endl; if (expected - actual > pow(static_cast(10), -307)) { cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_BASETYPES; } /** * BINARY TEST */ for (string::size_type i = 0; i < 131073 && !return_code; ) { return_code |= binary_test(testClient, i); if (i > 0) { i *= 2; } else { ++i; } } /** * STRUCT TEST */ cout << "testStruct({\"Zero\", 1, -3, -5})" << flush; Xtruct out; out.string_thing = "Zero"; out.byte_thing = 1; out.i32_thing = -3; out.i64_thing = -5; Xtruct in; testClient.testStruct(in, out); printf(" = {\"%s\", %d, %d, %" PRId64 "}\n", in.string_thing.c_str(), (int)in.byte_thing, in.i32_thing, in.i64_thing); if (in != out) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } /** * NESTED STRUCT TEST */ cout << "testNest({1, {\"Zero\", 1, -3, -5}), 5}" << flush; Xtruct2 out2; out2.byte_thing = 1; out2.struct_thing = out; out2.i32_thing = 5; Xtruct2 in2; testClient.testNest(in2, out2); in = in2.struct_thing; printf(" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n", in2.byte_thing, in.string_thing.c_str(), (int)in.byte_thing, in.i32_thing, in.i64_thing, in2.i32_thing); if (in2 != out2) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } /** * MAP TEST */ map mapout; for (int32_t i = 0; i < 5; ++i) { mapout.insert(make_pair(i, i - 10)); } cout << "testMap({" << flush; map::const_iterator m_iter; bool first = true; for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) { if (first) { first = false; } else { cout << ","; } cout << m_iter->first << " => " << m_iter->second; } cout << "})"; map mapin; testClient.testMap(mapin, mapout); cout << " = {"; first = true; for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) { if (first) { first = false; } else { cout << ","; } cout << m_iter->first << " => " << m_iter->second; } cout << "}" << endl; if (mapin != mapout) { cout << "*** FAILED ***" << endl; return_code |= ERR_CONTAINERS; } /** * STRING MAP TEST */ cout << "testStringMap({a => 2, b => blah, some => thing}) = {" << flush; map smapin; map smapout; smapin["a"] = "2"; smapin["b"] = "blah"; smapin["some"] = "thing"; try { testClient.testStringMap(smapout, smapin); first = true; for (map::const_iterator it = smapout.begin(); it != smapout.end(); ++it) { if (first) cout << ","; else first = false; cout << it->first << " => " << it->second; } cout << "}" << endl; if (smapin != smapout) { cout << "*** FAILED ***" << endl; return_code |= ERR_CONTAINERS; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_CONTAINERS; } /** * SET TEST */ set setout; for (int32_t i = -2; i < 3; ++i) { setout.insert(i); } cout << "testSet({" << flush; set::const_iterator s_iter; first = true; for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) { if (first) { first = false; } else { cout << ","; } cout << *s_iter; } cout << "})"; set setin; testClient.testSet(setin, setout); cout << " = {"; first = true; for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) { if (first) { first = false; } else { cout << ","; } cout << *s_iter; } cout << "}" << endl; if (setin != setout) { cout << "*** FAILED ***" << endl; return_code |= ERR_CONTAINERS; } /** * LIST TEST */ cout << "testList(empty)" << flush; try { vector listout; testClient.testList(listout, vector()); if (!listout.empty()) { cout << "*** FAILED ***" << endl; cout << "invalid length: " << listout.size() << endl; return_code |= ERR_CONTAINERS; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_CONTAINERS; } try { vector listout; for (int32_t i = -2; i < 3; ++i) { listout.push_back(i); } cout << "testList({" << flush; vector::const_iterator l_iter; first = true; for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) { if (first) { first = false; } else { cout << ","; } cout << *l_iter; } cout << "})"; vector listin; testClient.testList(listin, listout); cout << " = {"; first = true; for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) { if (first) { first = false; } else { cout << ","; } cout << *l_iter; } cout << "}" << endl; if (listin != listout) { cout << "*** FAILED ***" << endl; return_code |= ERR_CONTAINERS; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_CONTAINERS; } /** * ENUM TEST */ cout << "testEnum(ONE)" << flush; Numberz::type ret = testClient.testEnum(Numberz::ONE); cout << " = " << ret << endl; if (ret != Numberz::ONE) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } cout << "testEnum(TWO)" << flush; ret = testClient.testEnum(Numberz::TWO); cout << " = " << ret << endl; if (ret != Numberz::TWO) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } cout << "testEnum(THREE)" << flush; ret = testClient.testEnum(Numberz::THREE); cout << " = " << ret << endl; if (ret != Numberz::THREE) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } cout << "testEnum(FIVE)" << flush; ret = testClient.testEnum(Numberz::FIVE); cout << " = " << ret << endl; if (ret != Numberz::FIVE) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } cout << "testEnum(EIGHT)" << flush; ret = testClient.testEnum(Numberz::EIGHT); cout << " = " << ret << endl; if (ret != Numberz::EIGHT) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } /** * TYPEDEF TEST */ cout << "testTypedef(309858235082523)" << flush; UserId uid = testClient.testTypedef(309858235082523LL); cout << " = " << uid << endl; if (uid != 309858235082523LL) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } /** * NESTED MAP TEST */ cout << "testMapMap(1)" << flush; map > mm; testClient.testMapMap(mm, 1); cout << " = {"; map >::const_iterator mi; for (mi = mm.begin(); mi != mm.end(); ++mi) { printf("%d => {", mi->first); map::const_iterator mi2; for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) { cout << mi2->first << " => " << mi2->second; } cout << "}, "; } cout << "}" << endl; if (mm.size() != 2 || mm[-4][-4] != -4 || mm[-4][-3] != -3 || mm[-4][-2] != -2 || mm[-4][-1] != -1 || mm[4][4] != 4 || mm[4][3] != 3 || mm[4][2] != 2 || mm[4][1] != 1) { cout << "*** FAILED ***" << endl; return_code |= ERR_CONTAINERS; } /** * INSANITY TEST */ if (!noinsane) { Insanity insane; insane.userMap.insert(make_pair(Numberz::FIVE, 5)); insane.userMap.insert(make_pair(Numberz::EIGHT, 8)); Xtruct truck; truck.string_thing = "Goodbye4"; truck.byte_thing = 4; truck.i32_thing = 4; truck.i64_thing = 4; Xtruct truck2; truck2.string_thing = "Hello2"; truck2.byte_thing = 2; truck2.i32_thing = 2; truck2.i64_thing = 2; insane.xtructs.push_back(truck); insane.xtructs.push_back(truck2); cout << "testInsanity()" << flush; map > whoa; testClient.testInsanity(whoa, insane); cout << " = {"; map >::const_iterator i_iter; for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) { printf("%" PRId64 " => {", i_iter->first); map::const_iterator i2_iter; for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) { printf("%d => {", i2_iter->first); map userMap = i2_iter->second.userMap; map::const_iterator um; cout << "{"; for (um = userMap.begin(); um != userMap.end(); ++um) { cout << um->first << " => " << um->second; } cout << "}, "; vector xtructs = i2_iter->second.xtructs; vector::const_iterator x; cout << "{"; for (x = xtructs.begin(); x != xtructs.end(); ++x) { printf("{\"%s\", %d, %d, %" PRId64 "}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing); } cout << "}"; cout << "}, "; } cout << "}, "; } cout << "}" << endl; bool failed = false; map >::const_iterator it1 = whoa.find(UserId(1)); if (whoa.size() != 2) { failed = true; } if (it1 == whoa.end()) { failed = true; } else { auto it12 = it1->second.find(Numberz::TWO); if (it12 == it1->second.end() || it12->second != insane) { failed = true; } auto it13 = it1->second.find(Numberz::THREE); if (it13 == it1->second.end() || it13->second != insane) { failed = true; } } map >::const_iterator it2 = whoa.find(UserId(2)); if (it2 == whoa.end()) { failed = true; } else { auto it26 = it2->second.find(Numberz::SIX); if (it26 == it2->second.end() || it26->second != Insanity()) { failed = true; } } if (failed) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } } /** * MULTI TEST */ cout << "testMulti()" << endl; try { map mul_map; Xtruct mul_result; mul_map[1] = "blah"; mul_map[2] = "thing"; testClient.testMulti(mul_result, 42, 4242, 424242, mul_map, Numberz::EIGHT, UserId(24)); Xtruct xxs; xxs.string_thing = "Hello2"; xxs.byte_thing = 42; xxs.i32_thing = 4242; xxs.i64_thing = 424242; if (mul_result != xxs) { cout << "*** FAILED ***" << endl; return_code |= ERR_STRUCTS; } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_STRUCTS; } /* test exception */ try { cout << "testClient.testException(\"Xception\") =>" << flush; testClient.testException("Xception"); cout << " void\n*** FAILED ***" << endl; return_code |= ERR_EXCEPTIONS; } catch (Xception& e) { printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); } try { cout << "testClient.testException(\"TException\") =>" << flush; testClient.testException("TException"); cout << " void\n*** FAILED ***" << endl; return_code |= ERR_EXCEPTIONS; } catch (const TException&) { cout << " Caught TException" << endl; } try { cout << "testClient.testException(\"success\") =>" << flush; testClient.testException("success"); cout << " void" << endl; } catch (exception & ex) { \ cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_EXCEPTIONS; } /* test multi exception */ try { cout << "testClient.testMultiException(\"Xception\", \"test 1\") =>" << flush; Xtruct result; testClient.testMultiException(result, "Xception", "test 1"); cout << " result\n*** FAILED ***" << endl; return_code |= ERR_EXCEPTIONS; } catch (Xception& e) { printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); } try { cout << "testClient.testMultiException(\"Xception2\", \"test 2\") =>" << flush; Xtruct result; testClient.testMultiException(result, "Xception2", "test 2"); cout << " result\n*** FAILED ***" << endl; return_code |= ERR_EXCEPTIONS; } catch (Xception2& e) { printf(" {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str()); } try { cout << "testClient.testMultiException(\"success\", \"test 3\") =>" << flush; Xtruct result; testClient.testMultiException(result, "success", "test 3"); printf(" {{\"%s\"}}\n", result.string_thing.c_str()); } catch (exception & ex) { \ cout << "*** FAILED ***" << endl << ex.what() << endl; return_code |= ERR_EXCEPTIONS; } /* test oneway void */ { cout << "testClient.testOneway(1) =>" << flush; uint64_t startOneway = now(); testClient.testOneway(1); uint64_t elapsed = now() - startOneway; if (elapsed > 200 * 1000) { // 0.2 seconds printf("*** FAILED *** - took %.2f ms\n", (double)elapsed / 1000.0); return_code |= ERR_BASETYPES; } else { printf(" success - took %.2f ms\n", (double)elapsed / 1000.0); } } /** * redo a simple test after the oneway to make sure we aren't "off by one" -- * if the server treated oneway void like normal void, this next test will * fail since it will get the void confirmation rather than the correct * result. In this circumstance, the client will throw the exception: * * TApplicationException: Wrong method namea */ /** * I32 TEST */ cout << "re-test testI32(-1)" << flush; int i32 = testClient.testI32(-1); cout << " = " << i32 << endl; if (i32 != -1) return_code |= ERR_BASETYPES; cout << endl << "All tests done." << endl << flush; uint64_t stop = now(); uint64_t tot = stop - start; cout << "Total time: " << stop - start << " us" << endl; time_tot += tot; if (time_min == 0 || tot < time_min) { time_min = tot; } if (tot > time_max) { time_max = tot; } cout << flush; transport->close(); } uint64_t time_avg = time_tot / numTests; cout << "Min time: " << time_min << " us" << endl; cout << "Max time: " << time_max << " us" << endl; cout << "Avg time: " << time_avg << " us" << endl; return return_code; } void binary_fill(std::string& str, string::size_type siz) { static const signed char bin_data[256] = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}; str.resize(siz); char *ptr = &str[0]; string::size_type pos = 0; for (string::size_type i = 0; i < siz; ++i) { if (pos == 255) { pos = 0; } else { ++pos; } *ptr++ = bin_data[pos]; } } int binary_test(ThriftTestClient& testClient, string::size_type siz) { string bin_request; string bin_result; cout << "testBinary(siz = " << siz << ")" << endl; binary_fill(bin_request, siz); try { testClient.testBinary(bin_result, bin_request); if (bin_request.size() != bin_result.size()) { cout << "*** FAILED: request size " << bin_request.size() << "; result size " << bin_result.size() << endl; return ERR_BASETYPES; } for (string::size_type i = 0; i < siz; ++i) { if (bin_request.at(i) != bin_result.at(i)) { cout << "*** FAILED: at position " << i << " request[i] is h" << hex << bin_request.at(i) << " result[i] is h" << hex << bin_result.at(i) << endl; return ERR_BASETYPES; } } } catch (TTransportException&) { throw; } catch (exception& ex) { cout << "*** FAILED ***" << endl << ex.what() << endl; return ERR_BASETYPES; } return 0; } thrift-0.16.0/test/cpp/src/TestServer.cpp000066400000000000000000000674441420101504100202430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SecondService.h" #include "ThriftTest.h" #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #include #include #include #include #include #include #if _WIN32 #include #endif using namespace std; using namespace apache::thrift; using namespace apache::thrift::async; using namespace apache::thrift::concurrency; using namespace apache::thrift::protocol; using namespace apache::thrift::transport; using namespace apache::thrift::server; using namespace thrift::test; // to handle a controlled shutdown, signal handling is mandatory #ifdef HAVE_SIGNAL_H apache::thrift::concurrency::Monitor gMonitor; void signal_handler(int signum) { if (signum == SIGINT) { gMonitor.notifyAll(); } } #endif class TestHandler : public ThriftTestIf { public: TestHandler() = default; void testVoid() override { printf("testVoid()\n"); } void testString(string& out, const string& thing) override { printf("testString(\"%s\")\n", thing.c_str()); out = thing; } bool testBool(const bool thing) override { printf("testBool(%s)\n", thing ? "true" : "false"); return thing; } int8_t testByte(const int8_t thing) override { printf("testByte(%d)\n", (int)thing); return thing; } int32_t testI32(const int32_t thing) override { printf("testI32(%d)\n", thing); return thing; } int64_t testI64(const int64_t thing) override { printf("testI64(%" PRId64 ")\n", thing); return thing; } double testDouble(const double thing) override { printf("testDouble(%f)\n", thing); return thing; } void testBinary(std::string& _return, const std::string& thing) override { std::ostringstream hexstr; hexstr << std::hex << thing; printf("testBinary(%lu: %s)\n", safe_numeric_cast(thing.size()), hexstr.str().c_str()); _return = thing; } void testStruct(Xtruct& out, const Xtruct& thing) override { printf("testStruct({\"%s\", %d, %d, %" PRId64 "})\n", thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing); out = thing; } void testNest(Xtruct2& out, const Xtruct2& nest) override { const Xtruct& thing = nest.struct_thing; printf("testNest({%d, {\"%s\", %d, %d, %" PRId64 "}, %d})\n", (int)nest.byte_thing, thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing, nest.i32_thing); out = nest; } void testMap(map& out, const map& thing) override { printf("testMap({"); map::const_iterator m_iter; bool first = true; for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) { if (first) { first = false; } else { printf(", "); } printf("%d => %d", m_iter->first, m_iter->second); } printf("})\n"); out = thing; } void testStringMap(map& out, const map& thing) override { printf("testMap({"); map::const_iterator m_iter; bool first = true; for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) { if (first) { first = false; } else { printf(", "); } printf("%s => %s", (m_iter->first).c_str(), (m_iter->second).c_str()); } printf("})\n"); out = thing; } void testSet(set& out, const set& thing) override { printf("testSet({"); set::const_iterator s_iter; bool first = true; for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) { if (first) { first = false; } else { printf(", "); } printf("%d", *s_iter); } printf("})\n"); out = thing; } void testList(vector& out, const vector& thing) override { printf("testList({"); vector::const_iterator l_iter; bool first = true; for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) { if (first) { first = false; } else { printf(", "); } printf("%d", *l_iter); } printf("})\n"); out = thing; } Numberz::type testEnum(const Numberz::type thing) override { printf("testEnum(%d)\n", thing); return thing; } UserId testTypedef(const UserId thing) override { printf("testTypedef(%" PRId64 ")\n", thing); return thing; } void testMapMap(map >& mapmap, const int32_t hello) override { printf("testMapMap(%d)\n", hello); map pos; map neg; for (int i = 1; i < 5; i++) { pos.insert(make_pair(i, i)); neg.insert(make_pair(-i, -i)); } mapmap.insert(make_pair(4, pos)); mapmap.insert(make_pair(-4, neg)); } void testInsanity(map >& insane, const Insanity& argument) override { printf("testInsanity()\n"); Insanity looney; map first_map; map second_map; first_map.insert(make_pair(Numberz::TWO, argument)); first_map.insert(make_pair(Numberz::THREE, argument)); second_map.insert(make_pair(Numberz::SIX, looney)); insane.insert(make_pair(1, first_map)); insane.insert(make_pair(2, second_map)); printf("return"); printf(" = {"); map >::const_iterator i_iter; for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) { printf("%" PRId64 " => {", i_iter->first); map::const_iterator i2_iter; for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) { printf("%d => {", i2_iter->first); map userMap = i2_iter->second.userMap; map::const_iterator um; printf("{"); for (um = userMap.begin(); um != userMap.end(); ++um) { printf("%d => %" PRId64 ", ", um->first, um->second); } printf("}, "); vector xtructs = i2_iter->second.xtructs; vector::const_iterator x; printf("{"); for (x = xtructs.begin(); x != xtructs.end(); ++x) { printf("{\"%s\", %d, %d, %" PRId64 "}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing); } printf("}"); printf("}, "); } printf("}, "); } printf("}\n"); } void testMulti(Xtruct& hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map& arg3, const Numberz::type arg4, const UserId arg5) override { (void)arg3; (void)arg4; (void)arg5; printf("testMulti()\n"); hello.string_thing = "Hello2"; hello.byte_thing = arg0; hello.i32_thing = arg1; hello.i64_thing = (int64_t)arg2; } void testException(const std::string& arg) override { printf("testException(%s)\n", arg.c_str()); if (arg.compare("Xception") == 0) { Xception e; e.errorCode = 1001; e.message = arg; throw e; } else if (arg.compare("TException") == 0) { apache::thrift::TException e; throw e; } else { Xtruct result; result.string_thing = arg; return; } } void testMultiException(Xtruct& result, const std::string& arg0, const std::string& arg1) override { printf("testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str()); if (arg0.compare("Xception") == 0) { Xception e; e.errorCode = 1001; e.message = "This is an Xception"; throw e; } else if (arg0.compare("Xception2") == 0) { Xception2 e; e.errorCode = 2002; e.struct_thing.string_thing = "This is an Xception2"; throw e; } else { result.string_thing = arg1; return; } } void testOneway(const int32_t aNum) override { printf("testOneway(%d): call received\n", aNum); } }; class SecondHandler : public SecondServiceIf { public: void secondtestString(std::string& result, const std::string& thing) override { result = "testString(\"" + thing + "\")"; } }; class TestProcessorEventHandler : public TProcessorEventHandler { void* getContext(const char* fn_name, void* serverContext) override { (void)serverContext; return new std::string(fn_name); } void freeContext(void* ctx, const char* fn_name) override { (void)fn_name; delete static_cast(ctx); } void preRead(void* ctx, const char* fn_name) override { communicate("preRead", ctx, fn_name); } void postRead(void* ctx, const char* fn_name, uint32_t bytes) override { (void)bytes; communicate("postRead", ctx, fn_name); } void preWrite(void* ctx, const char* fn_name) override { communicate("preWrite", ctx, fn_name); } void postWrite(void* ctx, const char* fn_name, uint32_t bytes) override { (void)bytes; communicate("postWrite", ctx, fn_name); } void asyncComplete(void* ctx, const char* fn_name) override { communicate("asyncComplete", ctx, fn_name); } void handlerError(void* ctx, const char* fn_name) override { communicate("handlerError", ctx, fn_name); } void communicate(const char* event, void* ctx, const char* fn_name) { std::cout << event << ": " << *static_cast(ctx) << " = " << fn_name << std::endl; } }; class TestHandlerAsync : public ThriftTestCobSvIf { public: TestHandlerAsync(std::shared_ptr& handler) : _delegate(handler) {} ~TestHandlerAsync() override = default; void testVoid(std::function cob) override { _delegate->testVoid(); cob(); } void testString(std::function cob, const std::string& thing) override { std::string res; _delegate->testString(res, thing); cob(res); } void testBool(std::function cob, const bool thing) override { bool res = _delegate->testBool(thing); cob(res); } void testByte(std::function cob, const int8_t thing) override { int8_t res = _delegate->testByte(thing); cob(res); } void testI32(std::function cob, const int32_t thing) override { int32_t res = _delegate->testI32(thing); cob(res); } void testI64(std::function cob, const int64_t thing) override { int64_t res = _delegate->testI64(thing); cob(res); } void testDouble(std::function cob, const double thing) override { double res = _delegate->testDouble(thing); cob(res); } void testBinary(std::function cob, const std::string& thing) override { std::string res; _delegate->testBinary(res, thing); cob(res); } void testStruct(std::function cob, const Xtruct& thing) override { Xtruct res; _delegate->testStruct(res, thing); cob(res); } void testNest(std::function cob, const Xtruct2& thing) override { Xtruct2 res; _delegate->testNest(res, thing); cob(res); } void testMap(std::function const& _return)> cob, const std::map& thing) override { std::map res; _delegate->testMap(res, thing); cob(res); } void testStringMap( std::function const& _return)> cob, const std::map& thing) override { std::map res; _delegate->testStringMap(res, thing); cob(res); } void testSet(std::function const& _return)> cob, const std::set& thing) override { std::set res; _delegate->testSet(res, thing); cob(res); } void testList(std::function const& _return)> cob, const std::vector& thing) override { std::vector res; _delegate->testList(res, thing); cob(res); } void testEnum(std::function cob, const Numberz::type thing) override { Numberz::type res = _delegate->testEnum(thing); cob(res); } void testTypedef(std::function cob, const UserId thing) override { UserId res = _delegate->testTypedef(thing); cob(res); } void testMapMap( std::function > const& _return)> cob, const int32_t hello) override { std::map > res; _delegate->testMapMap(res, hello); cob(res); } void testInsanity( std::function > const& _return)> cob, const Insanity& argument) override { std::map > res; _delegate->testInsanity(res, argument); cob(res); } void testMulti(std::function cob, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map& arg3, const Numberz::type arg4, const UserId arg5) override { Xtruct res; _delegate->testMulti(res, arg0, arg1, arg2, arg3, arg4, arg5); cob(res); } void testException( std::function cob, std::function exn_cob, const std::string& arg) override { try { _delegate->testException(arg); } catch (const apache::thrift::TException& e) { exn_cob(apache::thrift::TDelayedException::delayException(e)); return; } cob(); } void testMultiException( std::function cob, std::function exn_cob, const std::string& arg0, const std::string& arg1) override { Xtruct res; try { _delegate->testMultiException(res, arg0, arg1); } catch (const apache::thrift::TException& e) { exn_cob(apache::thrift::TDelayedException::delayException(e)); return; } cob(res); } void testOneway(std::function cob, const int32_t secondsToSleep) override { _delegate->testOneway(secondsToSleep); cob(); } protected: std::shared_ptr _delegate; }; namespace po = boost::program_options; int main(int argc, char** argv) { string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string(); string certPath = testDir + "/keys/server.crt"; string keyPath = testDir + "/keys/server.key"; #if _WIN32 transport::TWinsockSingleton::create(); #endif int port = 9090; bool ssl = false; bool zlib = false; string transport_type = "buffered"; string protocol_type = "binary"; string server_type = "simple"; string domain_socket = ""; bool abstract_namespace = false; size_t workers = 4; int string_limit = 0; int container_limit = 0; po::options_description desc("Allowed options"); desc.add_options() ("help,h", "produce help message") ("port", po::value(&port)->default_value(port), "Port number to listen") ("domain-socket", po::value(&domain_socket) ->default_value(domain_socket), "Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)") ("abstract-namespace", "Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames)") ("server-type", po::value(&server_type)->default_value(server_type), "type of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\"") ("transport", po::value(&transport_type)->default_value(transport_type), "transport: buffered, framed, http, websocket, zlib") ("protocol", po::value(&protocol_type)->default_value(protocol_type), "protocol: binary, compact, header, json, multi, multic, multih, multij") ("ssl", "Encrypted Transport using SSL") ("zlib", "Wrapped Transport using Zlib") ("processor-events", "processor-events") ("workers,n", po::value(&workers)->default_value(workers), "Number of thread pools workers. Only valid for thread-pool server type") ("string-limit", po::value(&string_limit)) ("container-limit", po::value(&container_limit)); po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if (vm.count("help")) { cout << desc << "\n"; return 1; } try { if (!server_type.empty()) { if (server_type == "simple") { } else if (server_type == "thread-pool") { } else if (server_type == "threaded") { } else if (server_type == "nonblocking") { } else { throw invalid_argument("Unknown server type " + server_type); } } if (!protocol_type.empty()) { if (protocol_type == "binary") { } else if (protocol_type == "compact") { } else if (protocol_type == "json") { } else if (protocol_type == "header") { } else if (protocol_type == "multi") { // multiplexed binary } else if (protocol_type == "multic") { // multiplexed compact } else if (protocol_type == "multih") { // multiplexed header } else if (protocol_type == "multij") { // multiplexed json } else { throw invalid_argument("Unknown protocol type " + protocol_type); } } if (!transport_type.empty()) { if (transport_type == "buffered") { } else if (transport_type == "framed") { } else if (transport_type == "http") { } else if (transport_type == "websocket") { } else if (transport_type == "zlib") { // crosstester will pass zlib as a flag and a transport right now... } else { throw invalid_argument("Unknown transport type " + transport_type); } } } catch (std::exception& e) { cerr << e.what() << endl; cout << desc << "\n"; return 1; } if (vm.count("ssl")) { ssl = true; } if (vm.count("zlib")) { zlib = true; } #if defined(HAVE_SIGNAL_H) && defined(SIGPIPE) if (ssl) { signal(SIGPIPE, SIG_IGN); // for OpenSSL, otherwise we end abruptly } #endif if (vm.count("abstract-namespace")) { abstract_namespace = true; } // Dispatcher std::shared_ptr protocolFactory; if (protocol_type == "json" || protocol_type == "multij") { std::shared_ptr jsonProtocolFactory(new TJSONProtocolFactory()); protocolFactory = jsonProtocolFactory; } else if (protocol_type == "compact" || protocol_type == "multic") { auto *compactProtocolFactory = new TCompactProtocolFactoryT(); compactProtocolFactory->setContainerSizeLimit(container_limit); compactProtocolFactory->setStringSizeLimit(string_limit); protocolFactory.reset(compactProtocolFactory); } else if (protocol_type == "header" || protocol_type == "multih") { std::shared_ptr headerProtocolFactory(new THeaderProtocolFactory()); protocolFactory = headerProtocolFactory; } else { auto* binaryProtocolFactory = new TBinaryProtocolFactoryT(); binaryProtocolFactory->setContainerSizeLimit(container_limit); binaryProtocolFactory->setStringSizeLimit(string_limit); protocolFactory.reset(binaryProtocolFactory); } // Processors std::shared_ptr testHandler(new TestHandler()); std::shared_ptr testProcessor(new ThriftTestProcessor(testHandler)); if (vm.count("processor-events")) { testProcessor->setEventHandler( std::shared_ptr(new TestProcessorEventHandler())); } // Transport std::shared_ptr sslSocketFactory; std::shared_ptr serverSocket; if (ssl) { sslSocketFactory = std::shared_ptr(new TSSLSocketFactory()); sslSocketFactory->loadCertificate(certPath.c_str()); sslSocketFactory->loadPrivateKey(keyPath.c_str()); sslSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); if (server_type != "nonblocking") { serverSocket = std::shared_ptr(new TSSLServerSocket(port, sslSocketFactory)); } } else { if (domain_socket != "") { if (abstract_namespace) { std::string abstract_socket("\0", 1); abstract_socket += domain_socket; serverSocket = std::shared_ptr(new TServerSocket(abstract_socket)); } else { unlink(domain_socket.c_str()); serverSocket = std::shared_ptr(new TServerSocket(domain_socket)); } port = 0; } else { serverSocket = std::shared_ptr(new TServerSocket(port)); } } // Factory std::shared_ptr transportFactory; if (transport_type == "http" && server_type != "nonblocking") { transportFactory = std::make_shared(); } else if (transport_type == "websocket" && server_type != "nonblocking") { if (protocol_type == "json" || protocol_type == "multij") { transportFactory = std::make_shared(); } else { transportFactory = std::make_shared(); } } else if (transport_type == "framed") { transportFactory = std::make_shared(); } else { transportFactory = std::make_shared(); } if (zlib) { // currently TZlibTransportFactory is the only factory than can wrap another: transportFactory = std::make_shared(transportFactory); } // Server Info cout << "Starting \"" << server_type << "\" server (" << transport_type << "/" << protocol_type << ") listen on: "; if (abstract_namespace) { cout << '@'; } cout << domain_socket; if (port != 0) { cout << port; } cout << endl; // Multiplexed Processor if needed if (boost::starts_with(protocol_type, "multi")) { std::shared_ptr secondHandler(new SecondHandler()); std::shared_ptr secondProcessor(new SecondServiceProcessor(secondHandler)); std::shared_ptr multiplexedProcessor(new TMultiplexedProcessor()); multiplexedProcessor->registerDefault(testProcessor); // non-multi clients go to the default processor (multi:binary, multic:compact, ...) multiplexedProcessor->registerProcessor("ThriftTest", testProcessor); multiplexedProcessor->registerProcessor("SecondService", secondProcessor); testProcessor = std::dynamic_pointer_cast(multiplexedProcessor); } // Server std::shared_ptr server; if (server_type == "simple") { server.reset(new TSimpleServer(testProcessor, serverSocket, transportFactory, protocolFactory)); } else if (server_type == "thread-pool") { std::shared_ptr threadFactory = std::shared_ptr(new ThreadFactory()); std::shared_ptr threadManager = ThreadManager::newSimpleThreadManager(workers); threadManager->threadFactory(threadFactory); threadManager->start(); server.reset(new TThreadPoolServer(testProcessor, serverSocket, transportFactory, protocolFactory, threadManager)); } else if (server_type == "threaded") { server.reset( new TThreadedServer(testProcessor, serverSocket, transportFactory, protocolFactory)); } else if (server_type == "nonblocking") { if (transport_type == "http") { std::shared_ptr testHandlerAsync(new TestHandlerAsync(testHandler)); std::shared_ptr testProcessorAsync( new ThriftTestAsyncProcessor(testHandlerAsync)); std::shared_ptr testBufferProcessor( new TAsyncProtocolProcessor(testProcessorAsync, protocolFactory)); // not loading nonblockingServer into "server" because // TEvhttpServer doesn't inherit from TServer, and doesn't // provide a stop method. TEvhttpServer nonblockingServer(testBufferProcessor, port); nonblockingServer.serve(); } else if (transport_type == "framed") { std::shared_ptr nbSocket; nbSocket.reset( ssl ? new transport::TNonblockingSSLServerSocket(port, sslSocketFactory) : new transport::TNonblockingServerSocket(port)); server.reset(new TNonblockingServer(testProcessor, protocolFactory, nbSocket)); } else { cerr << "server-type nonblocking requires transport of http or framed" << endl; exit(1); } } if (server.get() != nullptr) { if (protocol_type == "header") { // Tell the server to use the same protocol for input / output // if using header server->setOutputProtocolFactory(std::shared_ptr()); } apache::thrift::concurrency::ThreadFactory factory; factory.setDetached(false); std::shared_ptr serverThreadRunner(server); std::shared_ptr thread = factory.newThread(serverThreadRunner); #ifdef HAVE_SIGNAL_H signal(SIGINT, signal_handler); #endif thread->start(); gMonitor.waitForever(); // wait for a shutdown signal #ifdef HAVE_SIGNAL_H signal(SIGINT, SIG_DFL); #endif server->stop(); thread->join(); server.reset(); } cout << "done." << endl; return 0; } thrift-0.16.0/test/cpp/src/ThriftTest_extras.cpp000066400000000000000000000022141420101504100216030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // Extra functions required for ThriftTest_types to work #include #include "gen-cpp/ThriftTest_types.h" namespace thrift { namespace test { bool Insanity::operator<(thrift::test::Insanity const& other) const { using apache::thrift::ThriftDebugString; return ThriftDebugString(*this) < ThriftDebugString(other); } } } thrift-0.16.0/test/crossrunner/000077500000000000000000000000001420101504100164245ustar00rootroot00000000000000thrift-0.16.0/test/crossrunner/__init__.py000066400000000000000000000017571420101504100205470ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from .test import test_name # noqa from .collect import collect_cross_tests, collect_feature_tests # noqa from .run import TestDispatcher # noqa from .report import generate_known_failures, load_known_failures # noqa thrift-0.16.0/test/crossrunner/collect.py000066400000000000000000000144101420101504100204230ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import platform import re from itertools import product from .util import merge_dict from .test import TestEntry # Those keys are passed to execution as is. # Note that there are keys other than these, namely: # delay: After server is started, client start is delayed for the value # (seconds). # timeout: Test timeout after client is started (seconds). # platforms: Supported platforms. Should match platform.system() value. # protocols: list of supported protocols # transports: list of supported transports # sockets: list of supported sockets # # protocols and transports entries can be colon separated "spec:impl" pair # (e.g. binary:accel) where test is run for any matching "spec" while actual # argument passed to test executable is "impl". # Otherwise "spec" is equivalent to "spec:spec" pair. # (e.g. "binary" is equivalent to "binary:binary" in tests.json) # VALID_JSON_KEYS = [ 'name', # name of the library, typically a language name 'workdir', # work directory where command is executed 'command', # test command 'extra_args', # args appended to command after other args are appended 'remote_args', # args added to the other side of the program 'join_args', # whether args should be passed as single concatenated string 'env', # additional environmental variable ] DEFAULT_MAX_DELAY = 5 DEFAULT_SIGNAL = 1 DEFAULT_TIMEOUT = 5 def _collect_testlibs(config, server_match, client_match=[None]): """Collects server/client configurations from library configurations""" def expand_libs(config): for lib in config: sv = lib.pop('server', None) cl = lib.pop('client', None) yield lib, sv, cl def yield_testlibs(base_configs, configs, match): for base, conf in zip(base_configs, configs): if conf: if not match or base['name'] in match: platforms = conf.get('platforms') or base.get('platforms') if not platforms or platform.system() in platforms: yield merge_dict(base, conf) libs, svs, cls = zip(*expand_libs(config)) servers = list(yield_testlibs(libs, svs, server_match)) clients = list(yield_testlibs(libs, cls, client_match)) return servers, clients def collect_features(config, match): res = list(map(re.compile, match)) return list(filter(lambda c: any(map(lambda r: r.search(c['name']), res)), config)) def _do_collect_tests(servers, clients): def intersection(key, o1, o2): """intersection of two collections. collections are replaced with sets the first time""" def cached_set(o, key): v = o[key] if not isinstance(v, set): v = set(v) o[key] = v return v return cached_set(o1, key) & cached_set(o2, key) def intersect_with_spec(key, o1, o2): # store as set of (spec, impl) tuple def cached_set(o): def to_spec_impl_tuples(values): for v in values: spec, _, impl = v.partition(':') yield spec, impl or spec v = o[key] if not isinstance(v, set): v = set(to_spec_impl_tuples(set(v))) o[key] = v return v for spec1, impl1 in cached_set(o1): for spec2, impl2 in cached_set(o2): if spec1 == spec2: name = impl1 if impl1 == impl2 else '%s-%s' % (impl1, impl2) yield name, impl1, impl2 def maybe_max(key, o1, o2, default): """maximum of two if present, otherwise default value""" v1 = o1.get(key) v2 = o2.get(key) return max(v1, v2) if v1 and v2 else v1 or v2 or default def filter_with_validkeys(o): ret = {} for key in VALID_JSON_KEYS: if key in o: ret[key] = o[key] return ret def merge_metadata(o, **ret): for key in VALID_JSON_KEYS: if key in o: ret[key] = o[key] return ret for sv, cl in product(servers, clients): for proto, proto1, proto2 in intersect_with_spec('protocols', sv, cl): for trans, trans1, trans2 in intersect_with_spec('transports', sv, cl): for sock in intersection('sockets', sv, cl): yield { 'server': merge_metadata(sv, **{'protocol': proto1, 'transport': trans1}), 'client': merge_metadata(cl, **{'protocol': proto2, 'transport': trans2}), 'delay': maybe_max('delay', sv, cl, DEFAULT_MAX_DELAY), 'stop_signal': maybe_max('stop_signal', sv, cl, DEFAULT_SIGNAL), 'timeout': maybe_max('timeout', sv, cl, DEFAULT_TIMEOUT), 'protocol': proto, 'transport': trans, 'socket': sock } def _filter_entries(tests, regex): if regex: return filter(lambda t: re.search(regex, TestEntry.get_name(**t)), tests) return tests def collect_cross_tests(tests_dict, server_match, client_match, regex): sv, cl = _collect_testlibs(tests_dict, server_match, client_match) return list(_filter_entries(_do_collect_tests(sv, cl), regex)) def collect_feature_tests(tests_dict, features_dict, server_match, feature_match, regex): sv, _ = _collect_testlibs(tests_dict, server_match) ft = collect_features(features_dict, feature_match) return list(_filter_entries(_do_collect_tests(sv, ft), regex)) thrift-0.16.0/test/crossrunner/compat.py000066400000000000000000000010661420101504100202640ustar00rootroot00000000000000import os import sys if sys.version_info[0] == 2: _ENCODE = sys.getfilesystemencoding() def path_join(*args): bin_args = map(lambda a: a.decode(_ENCODE), args) return os.path.join(*bin_args).encode(_ENCODE) def str_join(left, right): bin_args = map(lambda a: a.decode(_ENCODE), right) b = left.decode(_ENCODE) return b.join(bin_args).encode(_ENCODE) logfile_open = open else: path_join = os.path.join str_join = str.join def logfile_open(*args): return open(*args, errors='replace') thrift-0.16.0/test/crossrunner/report.py000066400000000000000000000402011420101504100203060ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from __future__ import print_function import datetime import json import multiprocessing import os import platform import re import subprocess import sys import time import traceback from .compat import logfile_open, path_join, str_join from .test import TestEntry LOG_DIR = 'log' RESULT_HTML = 'index.html' RESULT_JSON = 'results.json' FAIL_JSON = 'known_failures_%s.json' def generate_known_failures(testdir, overwrite, save, out): def collect_failures(results): success_index = 5 for r in results: if not r[success_index]: yield TestEntry.get_name(*r) try: with logfile_open(path_join(testdir, RESULT_JSON), 'r') as fp: results = json.load(fp) except IOError: sys.stderr.write('Unable to load last result. Did you run tests ?\n') return False fails = collect_failures(results['results']) if not overwrite: known = load_known_failures(testdir) known.extend(fails) fails = known fails_json = json.dumps(sorted(set(fails)), indent=2, separators=(',', ': ')) if save: with logfile_open(os.path.join(testdir, FAIL_JSON % platform.system()), 'w+') as fp: fp.write(fails_json) sys.stdout.write('Successfully updated known failures.\n') if out: sys.stdout.write(fails_json) sys.stdout.write('\n') return True def load_known_failures(testdir): try: with logfile_open(path_join(testdir, FAIL_JSON % platform.system()), 'r') as fp: return json.load(fp) except IOError: return [] class TestReporter(object): # Unfortunately, standard library doesn't handle timezone well # DATETIME_FORMAT = '%a %b %d %H:%M:%S %Z %Y' DATETIME_FORMAT = '%a %b %d %H:%M:%S %Y' def __init__(self): self._log = multiprocessing.get_logger() self._lock = multiprocessing.Lock() @classmethod def test_logfile(cls, test_name, prog_kind, dir=None): relpath = path_join('log', '%s_%s.log' % (test_name, prog_kind)) return relpath if not dir else os.path.realpath(path_join(dir, relpath)) def _start(self): self._start_time = time.time() @property def _elapsed(self): return time.time() - self._start_time @classmethod def _format_date(cls): return '%s' % datetime.datetime.now().strftime(cls.DATETIME_FORMAT) def _print_date(self): print(self._format_date(), file=self.out) def _print_bar(self, out=None): print( '===============================================================================', file=(out or self.out)) def _print_exec_time(self): print('Test execution took {:.1f} seconds.'.format(self._elapsed), file=self.out) class ExecReporter(TestReporter): def __init__(self, testdir, test, prog): super(ExecReporter, self).__init__() self._test = test self._prog = prog self.logpath = self.test_logfile(test.name, prog.kind, testdir) self.out = None def begin(self): self._start() self._open() if self.out and not self.out.closed: self._print_header() else: self._log.debug('Output stream is not available.') def end(self, returncode): self._lock.acquire() try: if self.out and not self.out.closed: self._print_footer(returncode) self._close() self.out = None else: self._log.debug('Output stream is not available.') finally: self._lock.release() def killed(self): print(file=self.out) print('Server process is successfully killed.', file=self.out) self.end(None) def died(self): print(file=self.out) print('*** Server process has died unexpectedly ***', file=self.out) self.end(None) _init_failure_exprs = { 'server': list(map(re.compile, [ '[Aa]ddress already in use', 'Could not bind', 'EADDRINUSE', ])), 'client': list(map(re.compile, [ '[Cc]onnection refused', 'Could not connect to', 'Could not open UNIX ', # domain socket (rb) 'ECONNREFUSED', 'econnrefused', # erl 'CONNECTION-REFUSED-ERROR', # cl 'connect ENOENT', # nodejs domain socket 'No such file or directory', # domain socket 'Sockets.TcpClient.Connect', # csharp ])), } def maybe_false_positive(self): """Searches through log file for socket bind error. Returns True if suspicious expression is found, otherwise False""" try: if self.out and not self.out.closed: self.out.flush() exprs = self._init_failure_exprs[self._prog.kind] def match(line): for expr in exprs: if expr.search(line): self._log.info("maybe false positive: %s" % line) return True with logfile_open(self.logpath, 'r') as fp: if any(map(match, fp)): return True except (KeyboardInterrupt, SystemExit): raise except Exception as ex: self._log.warn('[%s]: Error while detecting false positive: %s' % (self._test.name, str(ex))) self._log.info(traceback.print_exc()) return False def _open(self): self.out = logfile_open(self.logpath, 'w+') def _close(self): self.out.close() def _print_header(self): self._print_date() print('Executing: %s' % str_join(' ', self._prog.command), file=self.out) print('Directory: %s' % self._prog.workdir, file=self.out) print('config:delay: %s' % self._test.delay, file=self.out) print('config:timeout: %s' % self._test.timeout, file=self.out) self._print_bar() self.out.flush() def _print_footer(self, returncode=None): self._print_bar() if returncode is not None: print('Return code: %d (negative values indicate kill by signal)' % returncode, file=self.out) else: print('Process is killed.', file=self.out) self._print_exec_time() self._print_date() class SummaryReporter(TestReporter): def __init__(self, basedir, testdir_relative, concurrent=True): super(SummaryReporter, self).__init__() self._basedir = basedir self._testdir_rel = testdir_relative self.logdir = path_join(self.testdir, LOG_DIR) self.out_path = path_join(self.testdir, RESULT_JSON) self.concurrent = concurrent self.out = sys.stdout self._platform = platform.system() self._revision = self._get_revision() self._tests = [] if not os.path.exists(self.logdir): os.mkdir(self.logdir) self._known_failures = load_known_failures(self.testdir) self._unexpected_success = [] self._flaky_success = [] self._unexpected_failure = [] self._expected_failure = [] self._print_header() @property def testdir(self): return path_join(self._basedir, self._testdir_rel) def _result_string(self, test): if test.success: if test.retry_count == 0: return 'success' elif test.retry_count == 1: return 'flaky(1 retry)' else: return 'flaky(%d retries)' % test.retry_count elif test.expired: return 'failure(timeout)' else: return 'failure(%d)' % test.returncode def _get_revision(self): p = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], cwd=self.testdir, stdout=subprocess.PIPE) out, _ = p.communicate() return out.strip() def _format_test(self, test, with_result=True): name = '%s-%s' % (test.server.name, test.client.name) trans = '%s-%s' % (test.transport, test.socket) if not with_result: return '{:24s}{:18s}{:25s}'.format(name[:23], test.protocol[:17], trans[:24]) else: return '{:24s}{:18s}{:25s}{:s}\n'.format(name[:23], test.protocol[:17], trans[:24], self._result_string(test)) def _print_test_header(self): self._print_bar() print( '{:24s}{:18s}{:25s}{:s}'.format('server-client:', 'protocol:', 'transport:', 'result:'), file=self.out) def _print_header(self): self._start() print('Apache Thrift - Integration Test Suite', file=self.out) self._print_date() self._print_test_header() def _print_unexpected_failure(self): if len(self._unexpected_failure) > 0: self.out.writelines([ '*** Following %d failures were unexpected ***:\n' % len(self._unexpected_failure), 'If it is introduced by you, please fix it before submitting the code.\n', # 'If not, please report at https://issues.apache.org/jira/browse/THRIFT\n', ]) self._print_test_header() for i in self._unexpected_failure: self.out.write(self._format_test(self._tests[i])) self._print_bar() else: print('No unexpected failures.', file=self.out) def _print_flaky_success(self): if len(self._flaky_success) > 0: print( 'Following %d tests were expected to cleanly succeed but needed retry:' % len(self._flaky_success), file=self.out) self._print_test_header() for i in self._flaky_success: self.out.write(self._format_test(self._tests[i])) self._print_bar() def _print_unexpected_success(self): if len(self._unexpected_success) > 0: print( 'Following %d tests were known to fail but succeeded (maybe flaky):' % len(self._unexpected_success), file=self.out) self._print_test_header() for i in self._unexpected_success: self.out.write(self._format_test(self._tests[i])) self._print_bar() def _http_server_command(self, port): if sys.version_info[0] < 3: return 'python -m SimpleHTTPServer %d' % port else: return 'python -m http.server %d' % port def _print_footer(self): fail_count = len(self._expected_failure) + len(self._unexpected_failure) self._print_bar() self._print_unexpected_success() self._print_flaky_success() self._print_unexpected_failure() self._write_html_data() self._assemble_log('unexpected failures', self._unexpected_failure) self._assemble_log('known failures', self._expected_failure) self.out.writelines([ 'You can browse results at:\n', '\tfile://%s/%s\n' % (self.testdir, RESULT_HTML), '# If you use Chrome, run:\n', '# \tcd %s\n#\t%s\n' % (self._basedir, self._http_server_command(8001)), '# then browse:\n', '# \thttp://localhost:%d/%s/\n' % (8001, self._testdir_rel), 'Full log for each test is here:\n', '\ttest/log/server_client_protocol_transport_client.log\n', '\ttest/log/server_client_protocol_transport_server.log\n', '%d failed of %d tests in total.\n' % (fail_count, len(self._tests)), ]) self._print_exec_time() self._print_date() def _render_result(self, test): return [ test.server.name, test.client.name, test.protocol, test.transport, test.socket, test.success, test.as_expected, test.returncode, { 'server': self.test_logfile(test.name, test.server.kind), 'client': self.test_logfile(test.name, test.client.kind), }, ] def _write_html_data(self): """Writes JSON data to be read by result html""" results = [self._render_result(r) for r in self._tests] with logfile_open(self.out_path, 'w+') as fp: fp.write(json.dumps({ 'date': self._format_date(), 'revision': str(self._revision), 'platform': self._platform, 'duration': '{:.1f}'.format(self._elapsed), 'results': results, }, indent=2)) def _assemble_log(self, title, indexes): if len(indexes) > 0: def add_prog_log(fp, test, prog_kind): print('*************************** %s message ***************************' % prog_kind, file=fp) path = self.test_logfile(test.name, prog_kind, self.testdir) if os.path.exists(path): with logfile_open(path, 'r') as prog_fp: print(prog_fp.read(), file=fp) filename = title.replace(' ', '_') + '.log' with logfile_open(os.path.join(self.logdir, filename), 'w+') as fp: for test in map(self._tests.__getitem__, indexes): fp.write('TEST: [%s]\n' % test.name) add_prog_log(fp, test, test.server.kind) add_prog_log(fp, test, test.client.kind) fp.write('**********************************************************************\n\n') print('%s are logged to %s/%s/%s' % (title.capitalize(), self._testdir_rel, LOG_DIR, filename)) def end(self): self._print_footer() return len(self._unexpected_failure) == 0 def add_test(self, test_dict): test = TestEntry(self.testdir, **test_dict) self._lock.acquire() try: if not self.concurrent: self.out.write(self._format_test(test, False)) self.out.flush() self._tests.append(test) return len(self._tests) - 1 finally: self._lock.release() def add_result(self, index, returncode, expired, retry_count): self._lock.acquire() try: failed = returncode is None or returncode != 0 flaky = not failed and retry_count != 0 test = self._tests[index] known = test.name in self._known_failures if failed: if known: self._log.debug('%s failed as expected' % test.name) self._expected_failure.append(index) else: self._log.info('unexpected failure: %s' % test.name) self._unexpected_failure.append(index) elif flaky and not known: self._log.info('unexpected flaky success: %s' % test.name) self._flaky_success.append(index) elif not flaky and known: self._log.info('unexpected success: %s' % test.name) self._unexpected_success.append(index) test.success = not failed test.returncode = returncode test.retry_count = retry_count test.expired = expired test.as_expected = known == failed if not self.concurrent: self.out.write(self._result_string(test) + '\n') else: self.out.write(self._format_test(test)) finally: self._lock.release() thrift-0.16.0/test/crossrunner/run.py000066400000000000000000000401311420101504100176010ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import contextlib import multiprocessing import multiprocessing.managers import os import platform import random import socket import subprocess import sys import time from .compat import str_join from .report import ExecReporter, SummaryReporter from .test import TestEntry from .util import domain_socket_path RESULT_ERROR = 64 RESULT_TIMEOUT = 128 SIGNONE = 0 SIGKILL = 15 # globals ports = None stop = None class ExecutionContext(object): def __init__(self, cmd, cwd, env, stop_signal, is_server, report): self._log = multiprocessing.get_logger() self.cmd = cmd self.cwd = cwd self.env = env self.stop_signal = stop_signal self.is_server = is_server self.report = report self.expired = False self.killed = False self.proc = None def _popen_args(self): args = { 'cwd': self.cwd, 'env': self.env, 'stdout': self.report.out, 'stderr': subprocess.STDOUT, } # make sure child processes doesn't remain after killing if platform.system() == 'Windows': DETACHED_PROCESS = 0x00000008 args.update(creationflags=DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP) else: args.update(preexec_fn=os.setsid) return args def start(self): joined = str_join(' ', self.cmd) self._log.debug('COMMAND: %s', joined) self._log.debug('WORKDIR: %s', self.cwd) self._log.debug('LOGFILE: %s', self.report.logpath) self.report.begin() self.proc = subprocess.Popen(self.cmd, **self._popen_args()) self._log.debug(' PID: %d', self.proc.pid) self._log.debug(' PGID: %d', os.getpgid(self.proc.pid)) return self._scoped() @contextlib.contextmanager def _scoped(self): yield self if self.is_server: # the server is supposed to run until we stop it if self.returncode is not None: self.report.died() else: if self.stop_signal != SIGNONE: if self.sigwait(self.stop_signal): self.report.end(self.returncode) else: self.report.killed() else: self.sigwait(SIGKILL) else: # the client is supposed to exit normally if self.returncode is not None: self.report.end(self.returncode) else: self.sigwait(SIGKILL) self.report.killed() self._log.debug('[{0}] exited with return code {1}'.format(self.proc.pid, self.returncode)) # Send a signal to the process and then wait for it to end # If the signal requested is SIGNONE, no signal is sent, and # instead we just wait for the process to end; further if it # does not end normally with SIGNONE, we mark it as expired. # If the process fails to end and the signal is not SIGKILL, # it re-runs with SIGKILL so that a real process kill occurs # returns True if the process ended, False if it may not have def sigwait(self, sig=SIGKILL, timeout=2): try: if sig != SIGNONE: self._log.debug('[{0}] send signal {1}'.format(self.proc.pid, sig)) if sig == SIGKILL: self.killed = True try: if platform.system() != 'Windows': os.killpg(os.getpgid(self.proc.pid), sig) else: self.proc.send_signal(sig) except Exception: self._log.info('[{0}] Failed to kill process'.format(self.proc.pid), exc_info=sys.exc_info()) self._log.debug('[{0}] wait begin, timeout {1} sec(s)'.format(self.proc.pid, timeout)) self.proc.communicate(timeout=timeout) self._log.debug('[{0}] process ended with return code {1}'.format(self.proc.pid, self.returncode)) self.report.end(self.returncode) return True except subprocess.TimeoutExpired: self._log.info('[{0}] timeout waiting for process to end'.format(self.proc.pid)) if sig == SIGNONE: self.expired = True return False if sig == SIGKILL else self.sigwait(SIGKILL, 1) # called on the client process to wait for it to end naturally def wait(self, timeout): self.sigwait(SIGNONE, timeout) @property def returncode(self): return self.proc.returncode if self.proc else None def exec_context(port, logdir, test, prog, is_server): report = ExecReporter(logdir, test, prog) prog.build_command(port) return ExecutionContext(prog.command, prog.workdir, prog.env, prog.stop_signal, is_server, report) def run_test(testdir, logdir, test_dict, max_retry, async_mode=True): logger = multiprocessing.get_logger() def ensure_socket_open(sv, port, test): slept = 0.1 time.sleep(slept) sleep_step = 0.1 while True: if slept > test.delay: logger.warn('[{0}] slept for {1} seconds but server is not open'.format(sv.proc.pid, slept)) return False if test.socket == 'domain': if not os.path.exists(domain_socket_path(port)): logger.debug('[{0}] domain(unix) socket not available yet. slept for {1} seconds so far'.format(sv.proc.pid, slept)) time.sleep(sleep_step) slept += sleep_step elif test.socket == 'abstract': return True else: # Create sockets every iteration because refused sockets cannot be # reused on some systems. sock4 = socket.socket() sock6 = socket.socket(family=socket.AF_INET6) try: if sock4.connect_ex(('127.0.0.1', port)) == 0 \ or sock6.connect_ex(('::1', port)) == 0: return True if sv.proc.poll() is not None: logger.warn('[{0}] server process is exited'.format(sv.proc.pid)) return False logger.debug('[{0}] socket not available yet. slept for {1} seconds so far'.format(sv.proc.pid, slept)) time.sleep(sleep_step) slept += sleep_step finally: sock4.close() sock6.close() logger.debug('[{0}] server ready - waited for {1} seconds'.format(sv.proc.pid, slept)) return True try: max_bind_retry = 3 retry_count = 0 bind_retry_count = 0 test = TestEntry(testdir, **test_dict) while True: if stop.is_set(): logger.debug('Skipping because shutting down') return (retry_count, None) logger.debug('Start') with PortAllocator.alloc_port_scoped(ports, test.socket) as port: logger.debug('Start with port %d' % port) sv = exec_context(port, logdir, test, test.server, True) cl = exec_context(port, logdir, test, test.client, False) logger.debug('Starting server') with sv.start(): port_ok = ensure_socket_open(sv, port, test) if port_ok: connect_retry_count = 0 max_connect_retry = 12 connect_retry_wait = 0.25 while True: if sv.proc.poll() is not None: logger.info('not starting client because server process is absent') break logger.debug('Starting client') cl.start() logger.debug('Waiting client (up to %d secs)' % test.timeout) cl.wait(test.timeout) if not cl.report.maybe_false_positive() or connect_retry_count >= max_connect_retry: if connect_retry_count > 0 and connect_retry_count < max_connect_retry: logger.info('[%s]: Connected after %d retry (%.2f sec each)' % (test.server.name, connect_retry_count, connect_retry_wait)) # Wait for 50ms to see if server does not die at the end. time.sleep(0.05) break logger.debug('Server may not be ready, waiting %.2f second...' % connect_retry_wait) time.sleep(connect_retry_wait) connect_retry_count += 1 if sv.report.maybe_false_positive() and bind_retry_count < max_bind_retry: logger.warn('[%s]: Detected socket bind failure, retrying...', test.server.name) bind_retry_count += 1 else: result = RESULT_TIMEOUT if cl.expired else cl.returncode if (cl.proc and cl.proc.poll()) is not None else RESULT_ERROR # For servers that handle a controlled shutdown by signal # if they are killed, or return an error code, that is a # problem. For servers that are not signal-aware, we simply # kill them off; if we didn't kill them off, something else # happened (crashed?) if test.server.stop_signal != 0: if sv.killed or sv.returncode > 0: result |= RESULT_ERROR else: if not sv.killed: result |= RESULT_ERROR if result == 0 or retry_count >= max_retry: return (retry_count, result) else: logger.info('[%s-%s]: test failed, retrying...', test.server.name, test.client.name) retry_count += 1 except Exception: if not async_mode: raise logger.warn('Error executing [%s]', test.name, exc_info=True) return (retry_count, RESULT_ERROR) except Exception: logger.info('Interrupted execution', exc_info=True) if not async_mode: raise stop.set() return (retry_count, RESULT_ERROR) class PortAllocator(object): def __init__(self): self._log = multiprocessing.get_logger() self._lock = multiprocessing.Lock() self._ports = set() self._dom_ports = set() self._last_alloc = 0 def _get_tcp_port(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(('', 0)) port = sock.getsockname()[1] self._lock.acquire() try: ok = port not in self._ports if ok: self._ports.add(port) self._last_alloc = time.time() finally: self._lock.release() sock.close() return port if ok else self._get_tcp_port() def _get_domain_port(self): port = random.randint(1024, 65536) self._lock.acquire() try: ok = port not in self._dom_ports if ok: self._dom_ports.add(port) finally: self._lock.release() return port if ok else self._get_domain_port() def alloc_port(self, socket_type): if socket_type in ('domain', 'abstract'): return self._get_domain_port() else: return self._get_tcp_port() # static method for inter-process invokation @staticmethod @contextlib.contextmanager def alloc_port_scoped(allocator, socket_type): port = allocator.alloc_port(socket_type) yield port allocator.free_port(socket_type, port) def free_port(self, socket_type, port): self._log.debug('free_port') self._lock.acquire() try: if socket_type == 'domain': self._dom_ports.remove(port) path = domain_socket_path(port) if os.path.exists(path): os.remove(path) elif socket_type == 'abstract': self._dom_ports.remove(port) else: self._ports.remove(port) except IOError: self._log.info('Error while freeing port', exc_info=sys.exc_info()) finally: self._lock.release() class NonAsyncResult(object): def __init__(self, value): self._value = value def get(self, timeout=None): return self._value def wait(self, timeout=None): pass def ready(self): return True def successful(self): return self._value == 0 class TestDispatcher(object): def __init__(self, testdir, basedir, logdir_rel, concurrency): self._log = multiprocessing.get_logger() self.testdir = testdir self._report = SummaryReporter(basedir, logdir_rel, concurrency > 1) self.logdir = self._report.testdir # seems needed for python 2.x to handle keyboard interrupt self._stop = multiprocessing.Event() self._async = concurrency > 1 if not self._async: self._pool = None global stop global ports stop = self._stop ports = PortAllocator() else: self._m = multiprocessing.managers.BaseManager() self._m.register('ports', PortAllocator) self._m.start() self._pool = multiprocessing.Pool(concurrency, self._pool_init, (self._m.address,)) self._log.debug( 'TestDispatcher started with %d concurrent jobs' % concurrency) def _pool_init(self, address): global stop global m global ports stop = self._stop m = multiprocessing.managers.BaseManager(address) m.connect() ports = m.ports() def _dispatch_sync(self, test, cont, max_retry): r = run_test(self.testdir, self.logdir, test, max_retry, async_mode=False) cont(r) return NonAsyncResult(r) def _dispatch_async(self, test, cont, max_retry): self._log.debug('_dispatch_async') return self._pool.apply_async(func=run_test, args=(self.testdir, self.logdir, test, max_retry), callback=cont) def dispatch(self, test, max_retry): index = self._report.add_test(test) def cont(result): if not self._stop.is_set(): if result and len(result) == 2: retry_count, returncode = result else: retry_count = 0 returncode = RESULT_ERROR self._log.debug('freeing port') self._log.debug('adding result') self._report.add_result(index, returncode, returncode == RESULT_TIMEOUT, retry_count) self._log.debug('finish continuation') fn = self._dispatch_async if self._async else self._dispatch_sync return fn(test, cont, max_retry) def wait(self): if self._async: self._pool.close() self._pool.join() self._m.shutdown() return self._report.end() def terminate(self): self._stop.set() if self._async: self._pool.terminate() self._pool.join() self._m.shutdown() thrift-0.16.0/test/crossrunner/setup.cfg000066400000000000000000000000371420101504100202450ustar00rootroot00000000000000[flake8] max-line-length = 100 thrift-0.16.0/test/crossrunner/test.py000066400000000000000000000121711420101504100177570ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import copy import multiprocessing import os import sys from .compat import path_join from .util import merge_dict, domain_socket_path class TestProgram(object): def __init__(self, kind, name, protocol, transport, socket, workdir, stop_signal, command, env=None, extra_args=[], extra_args2=[], join_args=False, **kwargs): self.kind = kind self.name = name self.protocol = protocol self.transport = transport self.socket = socket self.workdir = workdir self.stop_signal = stop_signal self.command = None self._base_command = self._fix_cmd_path(command) if env: self.env = copy.copy(os.environ) self.env.update(env) else: self.env = os.environ self._extra_args = extra_args self._extra_args2 = extra_args2 self._join_args = join_args def _fix_cmd_path(self, cmd): # if the arg is a file in the current directory, make it path def abs_if_exists(arg): p = path_join(self.workdir, arg) return p if os.path.exists(p) else arg if cmd[0] == 'python': cmd[0] = sys.executable else: cmd[0] = abs_if_exists(cmd[0]) return cmd def _socket_args(self, socket, port): return { 'ip-ssl': ['--ssl'], 'domain': ['--domain-socket=%s' % domain_socket_path(port)], 'abstract': ['--abstract-namespace', '--domain-socket=%s' % domain_socket_path(port)], }.get(socket, None) def _transport_args(self, transport): return { 'zlib': ['--zlib'], }.get(transport, None) def build_command(self, port): cmd = copy.copy(self._base_command) args = copy.copy(self._extra_args2) args.append('--protocol=' + self.protocol) args.append('--transport=' + self.transport) transport_args = self._transport_args(self.transport) if transport_args: args += transport_args socket_args = self._socket_args(self.socket, port) if socket_args: args += socket_args args.append('--port=%d' % port) if self._join_args: cmd.append('%s' % " ".join(args)) else: cmd.extend(args) if self._extra_args: cmd.extend(self._extra_args) self.command = cmd return self.command class TestEntry(object): def __init__(self, testdir, server, client, delay, timeout, **kwargs): self.testdir = testdir self._log = multiprocessing.get_logger() self._config = kwargs self.protocol = kwargs['protocol'] self.transport = kwargs['transport'] self.socket = kwargs['socket'] srv_dict = self._fix_workdir(merge_dict(self._config, server)) cli_dict = self._fix_workdir(merge_dict(self._config, client)) cli_dict['extra_args2'] = srv_dict.pop('remote_args', []) srv_dict['extra_args2'] = cli_dict.pop('remote_args', []) self.server = TestProgram('server', **srv_dict) self.client = TestProgram('client', **cli_dict) self.delay = delay self.timeout = timeout self._name = None # results self.success = None self.as_expected = None self.returncode = None self.expired = False self.retry_count = 0 def _fix_workdir(self, config): key = 'workdir' path = config.get(key, None) if not path: path = self.testdir if os.path.isabs(path): path = os.path.realpath(path) else: path = os.path.realpath(path_join(self.testdir, path)) config.update({key: path}) return config @classmethod def get_name(cls, server, client, protocol, transport, socket, *args, **kwargs): return '%s-%s_%s_%s-%s' % (server, client, protocol, transport, socket) @property def name(self): if not self._name: self._name = self.get_name( self.server.name, self.client.name, self.protocol, self.transport, self.socket) return self._name @property def transport_name(self): return '%s-%s' % (self.transport, self.socket) def test_name(server, client, protocol, transport, socket, **kwargs): return TestEntry.get_name(server['name'], client['name'], protocol, transport, socket) thrift-0.16.0/test/crossrunner/util.py000066400000000000000000000022131420101504100177510ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import copy def domain_socket_path(port): return '/tmp/ThriftTest.thrift.%d' % port def merge_dict(base, update): """Update dict concatenating list values""" res = copy.deepcopy(base) for k, v in list(update.items()): if k in list(res.keys()) and isinstance(v, list): res[k].extend(v) else: res[k] = v return res thrift-0.16.0/test/dart/000077500000000000000000000000001420101504100147735ustar00rootroot00000000000000thrift-0.16.0/test/dart/Makefile.am000066400000000000000000000032601420101504100170300ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-dart/thrift_test/lib/thrift_test.dart: ../ThriftTest.thrift $(THRIFT) --gen dart ../ThriftTest.thrift pub-get-gen: gen-dart/thrift_test/lib/thrift_test.dart cd gen-dart/thrift_test; ${DARTPUB} get pub-get: pub-get-gen cd test_client; ${DARTPUB} get stubs: gen-dart/thrift_test/lib/thrift_test.dart pub-get precross: stubs check: stubs clean-local: $(RM) -r gen-dart/ test_client/.pub find . -type d -name ".dart_tool" | xargs $(RM) -r find . -type d -name "packages" | xargs $(RM) -r find . -type f -name ".packages" | xargs $(RM) find . -type f -name "pubspec.lock" | xargs $(RM) dist-hook: $(RM) -r $(distdir)/gen-dart/ $(distdir)/test_client/.pub find $(distdir) -type d -name ".dart_tool" | xargs $(RM) -r find $(distdir) -type d -name "packages" | xargs $(RM) -r find $(distdir) -type f -name ".packages" | xargs $(RM) client: stubs ${DART} test_client/bin/main.dart EXTRA_DIST = \ test_client thrift-0.16.0/test/dart/test_client/000077500000000000000000000000001420101504100173105ustar00rootroot00000000000000thrift-0.16.0/test/dart/test_client/bin/000077500000000000000000000000001420101504100200605ustar00rootroot00000000000000thrift-0.16.0/test/dart/test_client/bin/main.dart000066400000000000000000000237301420101504100216650ustar00rootroot00000000000000/// Licensed to the Apache Software Foundation (ASF) under one /// or more contributor license agreements. See the NOTICE file /// distributed with this work for additional information /// regarding copyright ownership. The ASF licenses this file /// to you under the Apache License, Version 2.0 (the /// 'License'); you may not use this file except in compliance /// with the License. You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, /// software distributed under the License is distributed on an /// 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY /// KIND, either express or implied. See the License for the /// specific language governing permissions and limitations /// under the License. import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:args/args.dart'; import 'package:collection/collection.dart'; import 'package:http/http.dart' as http; import 'package:thrift/thrift.dart'; import 'package:thrift/thrift_console.dart'; import 'package:thrift_test/thrift_test.dart'; const TEST_BASETYPES = 1; // 0000 0001 const TEST_STRUCTS = 2; // 0000 0010 const TEST_CONTAINERS = 4; // 0000 0100 const TEST_EXCEPTIONS = 8; // 0000 1000 const TEST_UNKNOWN = 64; // 0100 0000 (Failed to prepare environemt etc.) const TEST_TIMEOUT = 128; // 1000 0000 const TEST_NOTUSED = 48; // 0011 0000 (reserved bits) typedef Future FutureFunction(); class TTest { final int errorCode; final String name; final FutureFunction func; TTest(this.errorCode, this.name, this.func); } class TTestError extends Error { final actual; final expected; TTestError(this.actual, this.expected); String toString() => '$actual != $expected'; } List _tests; ThriftTestClient client; bool verbose; /// Adapted from TestClient.php main(List args) async { ArgResults results = _parseArgs(args); if (results == null) { exit(TEST_UNKNOWN); } verbose = results['verbose'] == true; await _initTestClient( host: results['host'], port: int.parse(results['port']), transportType: results['transport'], protocolType: results['protocol']).catchError((e) { stdout.writeln('Error:'); stdout.writeln('$e'); if (e is Error) { stdout.writeln('${e.stackTrace}'); } exit(TEST_UNKNOWN); }); // run tests _tests = _createTests(); int result = 0; for (TTest test in _tests) { if (verbose) stdout.write('${test.name}... '); try { await test.func(); if (verbose) stdout.writeln('success!'); } catch (e) { if (verbose) stdout.writeln('$e'); result = result | test.errorCode; } } exit(result); } ArgResults _parseArgs(List args) { var parser = new ArgParser(); parser.addOption('host', defaultsTo: 'localhost', help: 'The server host'); parser.addOption('port', defaultsTo: '9090', help: 'The port to connect to'); parser.addOption('transport', defaultsTo: 'buffered', allowed: ['buffered', 'framed', 'http'], help: 'The transport name', allowedHelp: { 'buffered': 'TBufferedTransport', 'framed': 'TFramedTransport' }); parser.addOption('protocol', defaultsTo: 'binary', allowed: ['binary', 'compact', 'json'], help: 'The protocol name', allowedHelp: { 'binary': 'TBinaryProtocol', 'compact': 'TCompactProtocol', 'json': 'TJsonProtocol' }); parser.addFlag('verbose', defaultsTo: true); ArgResults results; try { results = parser.parse(args); } catch (e) { stdout.writeln('$e\n'); } if (results == null) stdout.write(parser.usage); return results; } TProtocolFactory getProtocolFactory(String protocolType) { if (protocolType == 'binary') { return new TBinaryProtocolFactory(); } else if (protocolType == 'compact') { return new TCompactProtocolFactory(); } else if (protocolType == 'json') { return new TJsonProtocolFactory(); } throw new ArgumentError.value(protocolType); } Future _initTestClient( {String host, int port, String transportType, String protocolType}) async { TTransport transport; var protocolFactory = getProtocolFactory(protocolType); if (transportType == 'http') { var httpClient = new http.IOClient(); var uri = Uri.parse('http://$host:$port'); var config = new THttpConfig(uri, {}); transport = new THttpClientTransport(httpClient, config); } else { var socket = await Socket.connect(host, port); transport = new TClientSocketTransport(new TTcpSocket(socket)); if (transportType == 'framed') { transport = new TFramedTransport(transport); } } var protocol = protocolFactory.getProtocol(transport); client = new ThriftTestClient(protocol); await transport.open(); } List _createTests() { List tests = []; var xtruct = new Xtruct() ..string_thing = 'Zero' ..byte_thing = 1 ..i32_thing = -3 ..i64_thing = -5; tests.add(new TTest(TEST_BASETYPES, 'testVoid', () async { await client.testVoid(); })); tests.add(new TTest(TEST_BASETYPES, 'testString', () async { var input = 'Test'; var result = await client.testString(input); if (result != input) throw new TTestError(result, input); })); tests.add(new TTest(TEST_BASETYPES, 'testBool', () async { var input = true; var result = await client.testBool(input); if (result != input) throw new TTestError(result, input); })); tests.add(new TTest(TEST_BASETYPES, 'testByte', () async { var input = 64; var result = await client.testByte(input); if (result != input) throw new TTestError(result, input); })); tests.add(new TTest(TEST_BASETYPES, 'testI32', () async { var input = 2147483647; var result = await client.testI32(input); if (result != input) throw new TTestError(result, input); })); tests.add(new TTest(TEST_BASETYPES, 'testI64', () async { var input = 9223372036854775807; var result = await client.testI64(input); if (result != input) throw new TTestError(result, input); })); tests.add(new TTest(TEST_BASETYPES, 'testDouble', () async { var input = 3.1415926; var result = await client.testDouble(input); if (result != input) throw new TTestError(result, input); })); tests.add(new TTest(TEST_BASETYPES, 'testBinary', () async { var utf8Codec = const Utf8Codec(); var input = utf8Codec.encode('foo'); var result = await client.testBinary(input); var equality = const ListEquality(); if (!equality.equals(result, input)) throw new TTestError(result, input); })); tests.add(new TTest(TEST_CONTAINERS, 'testStruct', () async { var result = await client.testStruct(xtruct); if ('$result' != '$xtruct') throw new TTestError(result, xtruct); })); tests.add(new TTest(TEST_CONTAINERS, 'testNest', () async { var input = new Xtruct2() ..byte_thing = 1 ..struct_thing = xtruct ..i32_thing = -3; var result = await client.testNest(input); if ('$result' != '$input') throw new TTestError(result, input); })); tests.add(new TTest(TEST_CONTAINERS, 'testMap', () async { Map input = {1: -10, 2: -9, 3: -8, 4: -7, 5: -6}; var result = await client.testMap(input); var equality = const MapEquality(); if (!equality.equals(result, input)) throw new TTestError(result, input); })); tests.add(new TTest(TEST_CONTAINERS, 'testSet', () async { var input = new Set.from([-2, -1, 0, 1, 2]); var result = await client.testSet(input); var equality = const SetEquality(); if (!equality.equals(result, input)) throw new TTestError(result, input); })); tests.add(new TTest(TEST_CONTAINERS, 'testList', () async { var input = [-2, -1, 0, 1, 2]; var result = await client.testList(input); var equality = const ListEquality(); if (!equality.equals(result, input)) throw new TTestError(result, input); })); tests.add(new TTest(TEST_CONTAINERS, 'testEnum', () async { await _testEnum(Numberz.ONE); await _testEnum(Numberz.TWO); await _testEnum(Numberz.THREE); await _testEnum(Numberz.FIVE); await _testEnum(Numberz.EIGHT); })); tests.add(new TTest(TEST_BASETYPES, 'testTypedef', () async { var input = 309858235082523; var result = await client.testTypedef(input); if (result != input) throw new TTestError(result, input); })); tests.add(new TTest(TEST_CONTAINERS, 'testMapMap', () async { Map> result = await client.testMapMap(1); if (result.isEmpty || result[result.keys.first].isEmpty) { throw new TTestError(result, 'Map>'); } })); tests.add(new TTest(TEST_CONTAINERS, 'testInsanity', () async { var input = new Insanity(); input.userMap = {Numberz.FIVE: 5000}; input.xtructs = [xtruct]; Map> result = await client.testInsanity(input); if (result.isEmpty || result[result.keys.first].isEmpty) { throw new TTestError(result, 'Map>'); } })); tests.add(new TTest(TEST_CONTAINERS, 'testMulti', () async { var input = new Xtruct() ..string_thing = 'Hello2' ..byte_thing = 123 ..i32_thing = 456 ..i64_thing = 789; var result = await client.testMulti(input.byte_thing, input.i32_thing, input.i64_thing, {1: 'one'}, Numberz.EIGHT, 5678); if ('$result' != '$input') throw new TTestError(result, input); })); tests.add(new TTest(TEST_EXCEPTIONS, 'testException', () async { try { await client.testException('Xception'); } on Xception catch (_) { return; } throw new TTestError(null, 'Xception'); })); tests.add(new TTest(TEST_EXCEPTIONS, 'testMultiException', () async { try { await client.testMultiException('Xception2', 'foo'); } on Xception2 catch (_) { return; } throw new TTestError(null, 'Xception2'); })); return tests; } Future _testEnum(int input) async { var result = await client.testEnum(input); if (result != input) throw new TTestError(result, input); } thrift-0.16.0/test/dart/test_client/pubspec.yaml000066400000000000000000000022711420101504100216370ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # 'License'); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. name: thrift_test_client version: 0.16.0 description: A client integration test for the Dart Thrift library author: Apache Thrift Developers homepage: http://thrift.apache.org environment: sdk: ">=1.24.3 <3.0.0" dependencies: args: ">=0.13.0 <2.0.0" http: ^0.11.0 thrift: path: ../../../lib/dart thrift_test: path: ../gen-dart/thrift_test dev_dependencies: test: ">=0.12.30 <2.0.0" thrift-0.16.0/test/erl/000077500000000000000000000000001420101504100146235ustar00rootroot00000000000000thrift-0.16.0/test/erl/Makefile.am000066400000000000000000000026251420101504100166640ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # THRIFT_FILES = $(wildcard ../*.thrift) ERL_FLAG = erl # make sure ThriftTest.thrift is generated last to prevent conflicts with other *.thrift files .generated: $(THRIFT_FILES) for f in $(THRIFT_FILES) ; do \ $(THRIFT) --gen $(ERL_FLAG) -o src $$f ; \ done ; \ $(THRIFT) --gen $(ERL_FLAG) -o src ../ThriftTest.thrift touch .generated precross: .generated $(REBAR) compile maintainer-clean-local: $(RM) -r ebin/ clean: $(REBAR) clean $(RM) .generated $(RM) -r .rebar/ $(RM) -r src/gen-erl/ dist-hook: $(RM) $(distdir)/.generated $(RM) -r $(distdir)/.rebar/ $(RM) -r $(distdir)/ebin/ $(RM) -r $(distdir)/src/gen-erl/ thrift-0.16.0/test/erl/rebar.config000066400000000000000000000001361420101504100171050ustar00rootroot00000000000000{sub_dirs, ["../../lib/erl"]}. {erl_opts, [ debug_info, {i, "../../lib/erl/include"} ]}. thrift-0.16.0/test/erl/src/000077500000000000000000000000001420101504100154125ustar00rootroot00000000000000thrift-0.16.0/test/erl/src/test_client.erl000066400000000000000000000163061420101504100204410ustar00rootroot00000000000000%% %% Licensed to the Apache Software Foundation (ASF) under one %% or more contributor license agreements. See the NOTICE file %% distributed with this work for additional information %% regarding copyright ownership. The ASF licenses this file %% to you under the Apache License, Version 2.0 (the %% "License"); you may not use this file except in compliance %% with the License. You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, %% software distributed under the License is distributed on an %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. %% -module(test_client). -export([start/0, start/1]). -include("gen-erl/thrift_test_types.hrl"). -record(options, {port = 9090, client_opts = []}). parse_args(Args) -> parse_args(Args, #options{}). parse_args([], Opts) -> Opts; parse_args([Head | Rest], Opts) -> NewOpts = case Head of "--port=" ++ Port -> case string:to_integer(Port) of {IntPort,_} when is_integer(IntPort) -> Opts#options{port = IntPort}; _Else -> erlang:error({bad_arg, Head}) end; "--transport=" ++ Trans -> % TODO: Enable Buffered and HTTP transport case Trans of "framed" -> Opts#options{client_opts = [{framed, true} | Opts#options.client_opts]}; _Else -> Opts end; "--ssl" -> ssl:start(), SslOptions = {ssloptions, [ {cacertfile, "../keys/CA.pem"}, {certfile, "../keys/client.pem"}, {keyfile, "../keys/client.key"} ]}, Opts#options{client_opts = [{ssltransport, true} | [SslOptions | Opts#options.client_opts]]}; "--protocol=" ++ Proto -> Opts#options{client_opts = [{protocol, list_to_atom(Proto)}]}; _Else -> erlang:error({bad_arg, Head}) end, parse_args(Rest, NewOpts). start() -> start(init:get_plain_arguments()). start(Args) -> #options{port = Port, client_opts = ClientOpts} = parse_args(Args), {ok, Client0} = thrift_client_util:new( "127.0.0.1", Port, thrift_test_thrift, ClientOpts), DemoXtruct = #'thrift.test.Xtruct'{ string_thing = <<"Zero">>, byte_thing = 1, i32_thing = 9128361, i64_thing = 9223372036854775807}, DemoNest = #'thrift.test.Xtruct2'{ byte_thing = 7, struct_thing = DemoXtruct, % Note that we don't set i32_thing, it will come back as undefined % from the Python server, but 0 from the C++ server, since it is not % optional i32_thing = 2}, % Is it safe to match these things? DemoDict = dict:from_list([ {Key, Key-10} || Key <- lists:seq(0,10) ]), DemoSet = sets:from_list([ Key || Key <- lists:seq(-3,3) ]), DemoInsane = #'thrift.test.Insanity'{ userMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_FIVE, 5000}]), xtructs = [#'thrift.test.Xtruct'{ string_thing = <<"Truck">>, byte_thing = 8, i32_thing = 8, i64_thing = 8}]}, error_logger:info_msg("testVoid"), {Client01, {ok, ok}} = thrift_client:call(Client0, testVoid, []), error_logger:info_msg("testString"), {Client02, {ok, <<"Test">>}} = thrift_client:call(Client01, testString, ["Test"]), error_logger:info_msg("testString"), {Client03, {ok, <<"Test">>}} = thrift_client:call(Client02, testString, [<<"Test">>]), error_logger:info_msg("testByte"), {Client04, {ok, 63}} = thrift_client:call(Client03, testByte, [63]), error_logger:info_msg("testI32"), {Client05, {ok, -1}} = thrift_client:call(Client04, testI32, [-1]), error_logger:info_msg("testI32"), {Client06, {ok, 0}} = thrift_client:call(Client05, testI32, [0]), error_logger:info_msg("testI64"), {Client07, {ok, -34359738368}} = thrift_client:call(Client06, testI64, [-34359738368]), error_logger:info_msg("testDouble"), {Client08, {ok, -5.2098523}} = thrift_client:call(Client07, testDouble, [-5.2098523]), %% TODO: add testBinary() call error_logger:info_msg("testStruct"), {Client09, {ok, DemoXtruct}} = thrift_client:call(Client08, testStruct, [DemoXtruct]), error_logger:info_msg("testNest"), {Client10, {ok, DemoNest}} = thrift_client:call(Client09, testNest, [DemoNest]), error_logger:info_msg("testMap"), {Client11, {ok, DemoDict}} = thrift_client:call(Client10, testMap, [DemoDict]), error_logger:info_msg("testSet"), {Client12, {ok, DemoSet}} = thrift_client:call(Client11, testSet, [DemoSet]), error_logger:info_msg("testList"), {Client13, {ok, [-1,2,3]}} = thrift_client:call(Client12, testList, [[-1,2,3]]), error_logger:info_msg("testEnum"), {Client14, {ok, 1}} = thrift_client:call(Client13, testEnum, [?THRIFT_TEST_NUMBERZ_ONE]), error_logger:info_msg("testTypedef"), {Client15, {ok, 309858235082523}} = thrift_client:call(Client14, testTypedef, [309858235082523]), error_logger:info_msg("testInsanity"), {Client16, {ok, InsaneResult}} = thrift_client:call(Client15, testInsanity, [DemoInsane]), io:format("~p~n", [InsaneResult]), {Client17, {ok, #'thrift.test.Xtruct'{string_thing = <<"Message">>}}} = thrift_client:call(Client16, testMultiException, ["Safe", "Message"]), Client18 = try {ClientS1, Result1} = thrift_client:call(Client17, testMultiException, ["Xception", "Message"]), io:format("Unexpected return! ~p~n", [Result1]), ClientS1 catch throw:{ClientS2, {exception, ExnS1 = #'thrift.test.Xception'{}}} -> #'thrift.test.Xception'{errorCode = 1001, message = <<"This is an Xception">>} = ExnS1, ClientS2; throw:{ClientS2, {exception, _ExnS1 = #'thrift.test.Xception2'{}}} -> io:format("Wrong exception type!~n", []), ClientS2 end, Client19 = try {ClientS3, Result2} = thrift_client:call(Client18, testMultiException, ["Xception2", "Message"]), io:format("Unexpected return! ~p~n", [Result2]), ClientS3 catch throw:{ClientS4, {exception, _ExnS2 = #'thrift.test.Xception'{}}} -> io:format("Wrong exception type!~n", []), ClientS4; throw:{ClientS4, {exception, ExnS2 = #'thrift.test.Xception2'{}}} -> #'thrift.test.Xception2'{errorCode = 2002, struct_thing = #'thrift.test.Xtruct'{ string_thing = <<"This is an Xception2">>}} = ExnS2, ClientS4 end, %% Started = erlang:monotonic_time(milli_seconds), {_, StartSec, StartUSec} = erlang:timestamp(), error_logger:info_msg("testOneway"), {Client20, {ok, ok}} = thrift_client:call(Client19, testOneway, [1]), {_, EndSec, EndUSec} = erlang:timestamp(), Elapsed = (EndSec - StartSec) * 1000 + (EndUSec - StartUSec) / 1000, if Elapsed > 1000 -> exit(1); true -> true end, thrift_client:close(Client20). thrift-0.16.0/test/erl/src/test_thrift_server.erl000066400000000000000000000200231420101504100220400ustar00rootroot00000000000000%% %% Licensed to the Apache Software Foundation (ASF) under one %% or more contributor license agreements. See the NOTICE file %% distributed with this work for additional information %% regarding copyright ownership. The ASF licenses this file %% to you under the Apache License, Version 2.0 (the %% "License"); you may not use this file except in compliance %% with the License. You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, %% software distributed under the License is distributed on an %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. %% -module(test_thrift_server). -export([start/0, start/1, start_link/2, handle_function/2]). -include("thrift_constants.hrl"). -include("gen-erl/thrift_test_types.hrl"). -record(options, {port = 9090, server_opts = []}). parse_args(Args) -> parse_args(Args, #options{}). parse_args([], Opts) -> Opts; parse_args([Head | Rest], Opts) -> NewOpts = case Head of "--port=" ++ Port -> case string:to_integer(Port) of {IntPort,_} when is_integer(IntPort) -> Opts#options{port = IntPort}; _Else -> erlang:error({bad_arg, Head}) end; "--transport=" ++ Trans -> case Trans of "framed" -> Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]}; _Else -> Opts end; "--ssl" -> ssl:start(), SslOptions = {ssloptions, [ {certfile, "../keys/server.pem"} ,{keyfile, "../keys/server.key"} ]}, Opts#options{server_opts = [{ssltransport, true} | [SslOptions | Opts#options.server_opts]]}; "--protocol=" ++ Proto -> Opts#options{server_opts = [{protocol, list_to_atom(Proto)} | Opts#options.server_opts]}; _Else -> erlang:error({bad_arg, Head}) end, parse_args(Rest, NewOpts). start() -> start(init:get_plain_arguments()). start(Args) -> #options{port = Port, server_opts = ServerOpts} = parse_args(Args), spawn(fun() -> start_link(Port, ServerOpts), receive after infinity -> ok end end). start_link(Port, ServerOpts) -> thrift_socket_server:start([{handler, ?MODULE}, {service, thrift_test_thrift}, {port, Port}] ++ ServerOpts). handle_function(testVoid, {}) -> io:format("testVoid~n"), ok; handle_function(testString, {S}) when is_binary(S) -> io:format("testString: ~p~n", [S]), {reply, S}; handle_function(testBool, {B}) when is_boolean(B) -> io:format("testBool: ~p~n", [B]), {reply, B}; handle_function(testByte, {I8}) when is_integer(I8) -> io:format("testByte: ~p~n", [I8]), {reply, I8}; handle_function(testI32, {I32}) when is_integer(I32) -> io:format("testI32: ~p~n", [I32]), {reply, I32}; handle_function(testI64, {I64}) when is_integer(I64) -> io:format("testI64: ~p~n", [I64]), {reply, I64}; handle_function(testDouble, {Double}) when is_float(Double) -> io:format("testDouble: ~p~n", [Double]), {reply, Double}; handle_function(testBinary, {S}) when is_binary(S) -> io:format("testBinary: ~p~n", [S]), {reply, S}; handle_function(testStruct, {Struct = #'thrift.test.Xtruct'{string_thing = String, byte_thing = Byte, i32_thing = I32, i64_thing = I64}}) when is_binary(String), is_integer(Byte), is_integer(I32), is_integer(I64) -> io:format("testStruct: ~p~n", [Struct]), {reply, Struct}; handle_function(testNest, {Nest}) when is_record(Nest, 'thrift.test.Xtruct2'), is_record(Nest#'thrift.test.Xtruct2'.struct_thing, 'thrift.test.Xtruct') -> io:format("testNest: ~p~n", [Nest]), {reply, Nest}; handle_function(testMap, {Map}) -> io:format("testMap: ~p~n", [dict:to_list(Map)]), {reply, Map}; handle_function(testStringMap, {Map}) -> io:format("testStringMap: ~p~n", [dict:to_list(Map)]), {reply, Map}; handle_function(testSet, {Set}) -> true = sets:is_set(Set), io:format("testSet: ~p~n", [sets:to_list(Set)]), {reply, Set}; handle_function(testList, {List}) when is_list(List) -> io:format("testList: ~p~n", [List]), {reply, List}; handle_function(testEnum, {Enum}) when is_integer(Enum) -> io:format("testEnum: ~p~n", [Enum]), {reply, Enum}; handle_function(testTypedef, {UserID}) when is_integer(UserID) -> io:format("testTypedef: ~p~n", [UserID]), {reply, UserID}; handle_function(testMapMap, {Hello}) -> io:format("testMapMap: ~p~n", [Hello]), PosList = [{I, I} || I <- lists:seq(1, 4)], NegList = [{-I, -I} || I <- lists:seq(1, 4)], MapMap = dict:from_list([{4, dict:from_list(PosList)}, {-4, dict:from_list(NegList)}]), {reply, MapMap}; handle_function(testInsanity, {Insanity}) when is_record(Insanity, 'thrift.test.Insanity') -> Hello = #'thrift.test.Xtruct'{string_thing = <<"Hello2">>, byte_thing = 2, i32_thing = 2, i64_thing = 2}, Goodbye = #'thrift.test.Xtruct'{string_thing = <<"Goodbye4">>, byte_thing = 4, i32_thing = 4, i64_thing = 4}, Crazy = #'thrift.test.Insanity'{ userMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_EIGHT, 8}]), xtructs = [Goodbye] }, Looney = #'thrift.test.Insanity'{}, FirstMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_TWO, Insanity}, {?THRIFT_TEST_NUMBERZ_THREE, Insanity}]), SecondMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_SIX, Looney}]), Insane = dict:from_list([{1, FirstMap}, {2, SecondMap}]), io:format("Return = ~p~n", [Insane]), {reply, Insane}; handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5}) when is_integer(Arg0), is_integer(Arg1), is_integer(Arg2), is_integer(Arg4), is_integer(Arg5) -> io:format("testMulti(~p)~n", [Args]), {reply, #'thrift.test.Xtruct'{string_thing = <<"Hello2">>, byte_thing = Arg0, i32_thing = Arg1, i64_thing = Arg2}}; handle_function(testException, {String}) when is_binary(String) -> io:format("testException(~p)~n", [String]), case String of <<"Xception">> -> throw(#'thrift.test.Xception'{errorCode = 1001, message = String}); <<"TException">> -> throw({?TApplicationException_Structure}); _ -> ok end; handle_function(testMultiException, {Arg0, Arg1}) -> io:format("testMultiException(~p, ~p)~n", [Arg0, Arg1]), case Arg0 of <<"Xception">> -> throw(#'thrift.test.Xception'{errorCode = 1001, message = <<"This is an Xception">>}); <<"Xception2">> -> throw(#'thrift.test.Xception2'{errorCode = 2002, struct_thing = #'thrift.test.Xtruct'{string_thing = <<"This is an Xception2">>}}); _ -> {reply, #'thrift.test.Xtruct'{string_thing = Arg1}} end; handle_function(testOneway, {Seconds}) -> io:format("testOneway: ~p~n", [Seconds]), timer:sleep(1000 * Seconds), ok. thrift-0.16.0/test/erl/src/thrift_test.app.src000066400000000000000000000037601420101504100212470ustar00rootroot00000000000000%% %% Licensed to the Apache Software Foundation (ASF) under one %% or more contributor license agreements. See the NOTICE file %% distributed with this work for additional information %% regarding copyright ownership. The ASF licenses this file %% to you under the Apache License, Version 2.0 (the %% "License"); you may not use this file except in compliance %% with the License. You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, %% software distributed under the License is distributed on an %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. %% %%% -*- mode:erlang -*- {application, thrift_test, [ % A quick description of the application. {description, "Thrift cross language test"}, % The version of the applicaton {vsn, "0.16.0"}, % All modules used by the application. {modules, [ test_client, test_thrift_server ]}, % All of the registered names the application uses. This can be ignored. {registered, []}, % Applications that are to be started prior to this one. This can be ignored % leave it alone unless you understand it well and let the .rel files in % your release handle this. {applications, [kernel, stdlib]}, % OTP application loader will load, but not start, included apps. Again % this can be ignored as well. To load but not start an application it % is easier to include it in the .rel file followed by the atom 'none' {included_applications, []}, % configuration parameters similar to those in the config file specified % on the command line. can be fetched with gas:get_env {env, [ % If an error/crash occurs during processing of a function, % should the TApplicationException serialized back to the client % include the erlang backtrace? {exceptions_include_traces, true} ]} ]}. thrift-0.16.0/test/features/000077500000000000000000000000001420101504100156575ustar00rootroot00000000000000thrift-0.16.0/test/features/Makefile.am000066400000000000000000000016041420101504100177140ustar00rootroot00000000000000# distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # EXTRA_DIST = \ local_thrift \ index.html \ container_limit.py \ index.html \ known_failures_Linux.json \ Makefile.am \ nosslv3.sh \ string_limit.py \ tests.json \ theader_binary.py \ setup.cfg \ tls.sh \ util.py thrift-0.16.0/test/features/container_limit.py000066400000000000000000000037061420101504100214170ustar00rootroot00000000000000#!/usr/bin/env python import argparse import sys from util import add_common_args, init_protocol from local_thrift import thrift # noqa from thrift.Thrift import TMessageType, TType # TODO: generate from ThriftTest.thrift def test_list(proto, value): method_name = 'testList' ttype = TType.LIST etype = TType.I32 proto.writeMessageBegin(method_name, TMessageType.CALL, 3) proto.writeStructBegin(method_name + '_args') proto.writeFieldBegin('thing', ttype, 1) proto.writeListBegin(etype, len(value)) for e in value: proto.writeI32(e) proto.writeListEnd() proto.writeFieldEnd() proto.writeFieldStop() proto.writeStructEnd() proto.writeMessageEnd() proto.trans.flush() _, mtype, _ = proto.readMessageBegin() assert mtype == TMessageType.REPLY proto.readStructBegin() _, ftype, fid = proto.readFieldBegin() assert fid == 0 assert ftype == ttype etype2, len2 = proto.readListBegin() assert etype == etype2 assert len2 == len(value) for i in range(len2): v = proto.readI32() assert v == value[i] proto.readListEnd() proto.readFieldEnd() _, ftype, _ = proto.readFieldBegin() assert ftype == TType.STOP proto.readStructEnd() proto.readMessageEnd() def main(argv): p = argparse.ArgumentParser() add_common_args(p) p.add_argument('--limit', type=int) args = p.parse_args() proto = init_protocol(args) # TODO: test set and map test_list(proto, list(range(args.limit - 1))) test_list(proto, list(range(args.limit - 1))) print('[OK]: limit - 1') test_list(proto, list(range(args.limit))) test_list(proto, list(range(args.limit))) print('[OK]: just limit') try: test_list(proto, list(range(args.limit + 1))) except Exception: print('[OK]: limit + 1') else: print('[ERROR]: limit + 1') assert False if __name__ == '__main__': sys.exit(main(sys.argv[1:])) thrift-0.16.0/test/features/index.html000066400000000000000000000032661420101504100176630ustar00rootroot00000000000000 Apache Thrift - integration test suite

Apache Thrift - integration test suite: Results

Server Client Protocol Transport Result (log) Expected

Test Information



browse raw log files



thrift-0.16.0/test/features/known_failures_Linux.json000066400000000000000000000052351420101504100227640ustar00rootroot00000000000000[
    "c_glib-limit_container_length_binary_buffered-ip",
    "c_glib-limit_string_length_binary_buffered-ip",
    "cl-limit_string_length_binary_buffered-ip",
    "cl-limit_container_length_binary_buffered-ip",
    "cpp-theader_framed_binary_multih-header_buffered-ip",
    "cpp-theader_framed_compact_multih-header_buffered-ip",
    "cpp-theader_unframed_binary_multih-header_buffered-ip",
    "cpp-theader_unframed_compact_multih-header_buffered-ip",
    "netstd-limit_container_length_binary_buffered-ip",
    "netstd-limit_container_length_compact_buffered-ip",
    "netstd-limit_string_length_binary_buffered-ip",
    "netstd-limit_string_length_compact_buffered-ip",
    "netstd-tls_binary_buffered-ip-ssl",
    "d-limit_container_length_binary_buffered-ip",
    "d-limit_container_length_compact_buffered-ip",
    "d-limit_string_length_binary_buffered-ip",
    "d-limit_string_length_compact_buffered-ip",
    "erl-limit_container_length_binary_buffered-ip",
    "erl-limit_container_length_compact_buffered-ip",
    "erl-limit_string_length_binary_buffered-ip",
    "erl-limit_string_length_compact_buffered-ip",
    "go-limit_container_length_binary_buffered-ip",
    "go-limit_container_length_compact_buffered-ip",
    "go-limit_string_length_binary_buffered-ip",
    "go-limit_string_length_compact_buffered-ip",
    "hs-limit_container_length_binary_buffered-ip",
    "hs-limit_container_length_compact_buffered-ip",
    "hs-limit_string_length_binary_buffered-ip",
    "hs-limit_string_length_compact_buffered-ip",
    "nodejs-limit_container_length_binary_buffered-ip",
    "nodejs-limit_container_length_compact_buffered-ip",
    "nodejs-limit_string_length_binary_buffered-ip",
    "nodejs-limit_string_length_compact_buffered-ip",
    "perl-limit_container_length_binary_buffered-ip",
    "perl-limit_string_length_binary_buffered-ip",
    "rb-limit_container_length_accel-binary_buffered-ip",
    "rb-limit_container_length_binary_buffered-ip",
    "rb-limit_container_length_compact_buffered-ip",
    "rb-limit_string_length_accel-binary_buffered-ip",
    "rb-limit_string_length_binary_buffered-ip",
    "rb-limit_string_length_compact_buffered-ip",
    "rs-limit_container_length_binary_buffered-ip",
    "rs-limit_container_length_compact_buffered-ip",
    "rs-limit_container_length_multic-compact_buffered-ip",
    "rs-limit_string_length_binary_buffered-ip",
    "rs-limit_string_length_compact_buffered-ip",
    "rs-limit_string_length_multic-compact_buffered-ip",
    "netstd-limit_string_length_compact_buffered-ip",
    "netstd-limit_container_length_compact_buffered-ip",
    "nodejs-theader_framed_binary_header_buffered-ip",
    "nodejs-theader_framed_compact_header_buffered-ip"
]
thrift-0.16.0/test/features/local_thrift/000077500000000000000000000000001420101504100203315ustar00rootroot00000000000000thrift-0.16.0/test/features/local_thrift/__init__.py000066400000000000000000000023061420101504100224430ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

import glob
import os
import sys

_SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__))
_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(_SCRIPT_DIR)))
_LIBDIR = os.path.join(_ROOT_DIR, 'lib', 'py', 'build', 'lib.*')

for libpath in glob.glob(_LIBDIR):
    if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])):
        sys.path.insert(0, libpath)
        thrift = __import__('thrift')
        break
thrift-0.16.0/test/features/nosslv3.sh000077500000000000000000000021301420101504100176210ustar00rootroot00000000000000#!/bin/bash

#
# Checks to make sure SSLv3 is not allowed by a server.
#

THRIFTHOST=localhost
THRIFTPORT=9090

while [[ $# -ge 1 ]]; do
  arg="$1"
  argIN=(${arg//=/ })

  case ${argIN[0]} in
    -h|--host)
    THRIFTHOST=${argIN[1]}
    shift # past argument
    ;;
    -p|--port)
    THRIFTPORT=${argIN[1]}
    shift # past argument
    ;;
    *)
          # unknown option ignored
    ;;
  esac

  shift   # past argument or value
done

function nosslv3
{
  local nego
  local negodenied
  local opensslv

  opensslv=$(openssl version | cut -d' ' -f2)
  if [[ $opensslv > "1.0" ]]; then
    echo "[pass] OpenSSL 1.1 or later - no need to check ssl3"
    return 0
  fi

  # echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null"
  nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null)
  negodenied=$?

  if [[ $negodenied -ne 0 ]]; then
    echo "[pass] SSLv3 negotiation disabled"
    echo $nego
    return 0
  fi

  echo "[fail] SSLv3 negotiation enabled!  stdout:"
  echo $nego
  return 1
}

nosslv3
exit $?
thrift-0.16.0/test/features/setup.cfg000066400000000000000000000000371420101504100175000ustar00rootroot00000000000000[flake8]
max-line-length = 100
thrift-0.16.0/test/features/string_limit.py000066400000000000000000000032241420101504100207360ustar00rootroot00000000000000#!/usr/bin/env python

import argparse
import sys

from util import add_common_args, init_protocol
from local_thrift import thrift  # noqa
from thrift.Thrift import TMessageType, TType


# TODO: generate from ThriftTest.thrift
def test_string(proto, value):
    method_name = 'testString'
    ttype = TType.STRING
    proto.writeMessageBegin(method_name, TMessageType.CALL, 3)
    proto.writeStructBegin(method_name + '_args')
    proto.writeFieldBegin('thing', ttype, 1)
    proto.writeString(value)
    proto.writeFieldEnd()
    proto.writeFieldStop()
    proto.writeStructEnd()
    proto.writeMessageEnd()
    proto.trans.flush()

    _, mtype, _ = proto.readMessageBegin()
    assert mtype == TMessageType.REPLY
    proto.readStructBegin()
    _, ftype, fid = proto.readFieldBegin()
    assert fid == 0
    assert ftype == ttype
    result = proto.readString()
    proto.readFieldEnd()
    _, ftype, _ = proto.readFieldBegin()
    assert ftype == TType.STOP
    proto.readStructEnd()
    proto.readMessageEnd()
    assert value == result


def main(argv):
    p = argparse.ArgumentParser()
    add_common_args(p)
    p.add_argument('--limit', type=int)
    args = p.parse_args()
    proto = init_protocol(args)
    test_string(proto, 'a' * (args.limit - 1))
    test_string(proto, 'a' * (args.limit - 1))
    print('[OK]: limit - 1')
    test_string(proto, 'a' * args.limit)
    test_string(proto, 'a' * args.limit)
    print('[OK]: just limit')
    try:
        test_string(proto, 'a' * (args.limit + 1))
    except Exception:
        print('[OK]: limit + 1')
    else:
        print('[ERROR]: limit + 1')
        assert False


if __name__ == '__main__':
    main(sys.argv[1:])
thrift-0.16.0/test/features/tests.json000066400000000000000000000050151420101504100177150ustar00rootroot00000000000000[
  {
    "description": "THeader detects unframed binary wire format",
    "name": "theader_unframed_binary",
    "command": [
      "python",
      "theader_binary.py",
      "--override-protocol=binary",
      "--override-transport=buffered"
    ],
    "protocols": ["header"],
    "transports": ["buffered"],
    "sockets": ["ip"],
    "workdir": "features"
  },
  {
    "description": "THeader detects framed binary wire format",
    "name": "theader_framed_binary",
    "command": [
      "python",
      "theader_binary.py",
      "--override-protocol=binary",
      "--override-transport=framed"
    ],
    "protocols": ["header"],
    "transports": ["buffered"],
    "sockets": ["ip"],
    "workdir": "features"
  },
  {
    "description": "THeader detects unframed compact wire format",
    "name": "theader_unframed_compact",
    "command": [
      "python",
      "theader_binary.py",
      "--override-protocol=compact",
      "--override-transport=buffered"
    ],
    "protocols": ["header"],
    "transports": ["buffered"],
    "sockets": ["ip"],
    "workdir": "features"
  },
  {
    "description": "THeader detects framed compact wire format",
    "name": "theader_framed_compact",
    "command": [
      "python",
      "theader_binary.py",
      "--override-protocol=compact",
      "--override-transport=framed"
    ],
    "protocols": ["header"],
    "transports": ["buffered"],
    "sockets": ["ip"],
    "workdir": "features"
  },
  {
    "name": "limit_string_length",
    "command": [
      "python",
      "string_limit.py",
      "--limit=50"
    ],
    "remote_args": [
      "--string-limit=50"
    ],
    "protocols": [
      "compact"
    ],
    "transports": ["buffered"],
    "sockets": ["ip"],
    "workdir": "features"
  },
  {
    "name": "limit_container_length",
    "command": [
      "python",
      "container_limit.py",
      "--limit=50"
    ],
    "remote_args": [
      "--container-limit=50"
    ],
    "protocols": [
      "compact"
    ],
    "transports": ["buffered"],
    "sockets": ["ip"],
    "workdir": "features"
  },
  {
    "name": "nosslv3",
    "comment": "check to make sure SSLv3 is not supported",
    "command": [
      "nosslv3.sh"
    ],
    "protocols": ["binary"],
    "transports": ["buffered"],
    "sockets": ["ip-ssl"],
    "workdir": "features"
  },
  {
    "name": "tls",
    "comment": "check to make sure TLSv1.0 or later is supported",
    "command": [
      "tls.sh"
    ],
    "protocols": ["binary"],
    "transports": ["buffered"],
    "sockets": ["ip-ssl"],
    "workdir": "features"
  }
]
thrift-0.16.0/test/features/theader_binary.py000066400000000000000000000041741420101504100212170ustar00rootroot00000000000000#!/usr/bin/env python

import argparse
import socket
import sys

from util import add_common_args
from local_thrift import thrift  # noqa
from thrift.Thrift import TMessageType, TType
from thrift.transport.TSocket import TSocket
from thrift.transport.TTransport import TBufferedTransport, TFramedTransport
from thrift.protocol.TBinaryProtocol import TBinaryProtocol
from thrift.protocol.TCompactProtocol import TCompactProtocol


def test_void(proto):
    proto.writeMessageBegin('testVoid', TMessageType.CALL, 3)
    proto.writeStructBegin('testVoid_args')
    proto.writeFieldStop()
    proto.writeStructEnd()
    proto.writeMessageEnd()
    proto.trans.flush()

    _, mtype, _ = proto.readMessageBegin()
    assert mtype == TMessageType.REPLY
    proto.readStructBegin()
    _, ftype, _ = proto.readFieldBegin()
    assert ftype == TType.STOP
    proto.readStructEnd()
    proto.readMessageEnd()


# THeader stack should accept binary protocol with optionally framed transport
def main(argv):
    p = argparse.ArgumentParser()
    add_common_args(p)
    # Since THeaderTransport acts as framed transport when detected frame, we
    # cannot use --transport=framed as it would result in 2 layered frames.
    p.add_argument('--override-transport')
    p.add_argument('--override-protocol')
    args = p.parse_args()
    assert args.protocol == 'header'
    assert args.transport == 'buffered'
    assert not args.ssl

    sock = TSocket(args.host, args.port, socket_family=socket.AF_INET)
    if not args.override_transport or args.override_transport == 'buffered':
        trans = TBufferedTransport(sock)
    elif args.override_transport == 'framed':
        print('TFRAMED')
        trans = TFramedTransport(sock)
    else:
        raise ValueError('invalid transport')
    trans.open()

    if not args.override_protocol or args.override_protocol == 'binary':
        proto = TBinaryProtocol(trans)
    elif args.override_protocol == 'compact':
        proto = TCompactProtocol(trans)
    else:
        raise ValueError('invalid transport')

    test_void(proto)
    test_void(proto)

    trans.close()


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
thrift-0.16.0/test/features/tls.sh000077500000000000000000000027731420101504100170310ustar00rootroot00000000000000#!/bin/bash

#
# Checks to make sure TLSv1.0 or later is allowed by a server.
#

THRIFTHOST=localhost
THRIFTPORT=9090

while [[ $# -ge 1 ]]; do
  arg="$1"
  argIN=(${arg//=/ })

  case ${argIN[0]} in
    -h|--host)
    THRIFTHOST=${argIN[1]}
    shift # past argument
    ;;
    -p|--port)
    THRIFTPORT=${argIN[1]}
    shift # past argument
    ;;
    *)
          # unknown option ignored
    ;;
  esac

  shift   # past argument or value
done

declare -A EXPECT_NEGOTIATE
EXPECT_NEGOTIATE[tls1]=1
EXPECT_NEGOTIATE[tls1_1]=1
EXPECT_NEGOTIATE[tls1_2]=1
EXPECT_NEGOTIATE[tls1_3]=1

failures=0

function tls
{
  for PROTO in "${!EXPECT_NEGOTIATE[@]}"; do

    local nego
    local negodenied
    local res

    echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null"
    nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null)
    negodenied=$?
    echo "result of command: $negodenied"

    res="enabled"; if [[ ${EXPECT_NEGOTIATE[$PROTO]} -eq 0 ]]; then res="disabled"; fi

    if [[ $negodenied -ne ${EXPECT_NEGOTIATE[$PROTO]} ]]; then
      echo "$PROTO negotiation allowed"
    else
      echo "[warn] $PROTO negotiation did not work"
      echo $nego
      ((failures++))
    fi
  done
}

tls

if [[ $failures -eq 4 ]]; then
  echo "[fail] At least one of TLSv1.0, TLSv1.1, TLSv1.2, or TLSv1.3 needs to work, but does not"
  exit $failures
fi

echo "[pass] At least one of TLSv1.0, TLSv1.1, TLSv1.2, or TLSv1.3 worked"
exit 0
thrift-0.16.0/test/features/util.py000066400000000000000000000023501420101504100172060ustar00rootroot00000000000000import argparse
import socket

from local_thrift import thrift  # noqa
from thrift.transport.TSocket import TSocket
from thrift.transport.TTransport import TBufferedTransport, TFramedTransport
from thrift.transport.THttpClient import THttpClient
from thrift.protocol.TBinaryProtocol import TBinaryProtocol
from thrift.protocol.TCompactProtocol import TCompactProtocol
from thrift.protocol.TJSONProtocol import TJSONProtocol


def add_common_args(p):
    p.add_argument('--host', default='localhost')
    p.add_argument('--port', type=int, default=9090)
    p.add_argument('--protocol', default='binary')
    p.add_argument('--transport', default='buffered')
    p.add_argument('--ssl', action='store_true')


def parse_common_args(argv):
    p = argparse.ArgumentParser()
    add_common_args(p)
    return p.parse_args(argv)


def init_protocol(args):
    sock = TSocket(args.host, args.port, socket_family=socket.AF_INET)
    sock.setTimeout(500)
    trans = {
        'buffered': TBufferedTransport,
        'framed': TFramedTransport,
        'http': THttpClient,
    }[args.transport](sock)
    trans.open()
    return {
        'binary': TBinaryProtocol,
        'compact': TCompactProtocol,
        'json': TJSONProtocol,
    }[args.protocol](trans)
thrift-0.16.0/test/go/000077500000000000000000000000001420101504100144465ustar00rootroot00000000000000thrift-0.16.0/test/go/Makefile.am000066400000000000000000000036151420101504100165070ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

BUILT_SOURCES = gopath

THRIFTCMD = $(THRIFT) -out src/gen --gen go:thrift_import=github.com/apache/thrift/lib/go/thrift,package_prefix=github.com/apache/thrift/test/go/src/gen/$(COMPILER_EXTRAFLAG)
THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift

precross: bin/testclient bin/testserver

ThriftTest.thrift: $(THRIFTTEST)
	grep -v list.*map.*list.*map $(THRIFTTEST) > ThriftTest.thrift

.PHONY: gopath

# Thrift for GO has problems with complex map keys: THRIFT-2063
gopath: $(THRIFT) ThriftTest.thrift
	mkdir -p src/gen
	$(THRIFTCMD) ThriftTest.thrift
	$(THRIFTCMD) ../StressTest.thrift
	touch gopath

bin/testclient: gopath
	GOPATH=`pwd` $(GO) install -mod=mod ./src/bin/testclient

bin/testserver: gopath
	GOPATH=`pwd` $(GO) install -mod=mod ./src/bin/testserver

bin/stress: gopath
	GOPATH=`pwd` $(GO) install -mod=mod ./src/bin/stress

clean-local:
	$(RM) -r src/gen src/github.com/golang src/thrift bin pkg gopath ThriftTest.thrift

check_PROGRAMS: bin/testclient bin/testserver bin/stress

check: gopath genmock
	$(GO) test -mod=mod -v ./src/common/...

genmock: gopath
	sh genmock.sh

EXTRA_DIST = \
	src/bin \
	src/common \
	genmock.sh
thrift-0.16.0/test/go/genmock.sh000066400000000000000000000005321420101504100164250ustar00rootroot00000000000000#!/bin/sh

set -e

export GOPATH=$(mktemp -d -t gopath-XXXXXXXXXX)

GO111MODULE=on go install -mod=mod github.com/golang/mock/mockgen

`go env GOPATH`/bin/mockgen -build_flags "-mod=mod" -destination=src/common/mock_handler.go -package=common github.com/apache/thrift/test/go/src/gen/thrifttest ThriftTest

chmod a+w -R $GOPATH && rm -Rf $GOPATH
thrift-0.16.0/test/go/src/000077500000000000000000000000001420101504100152355ustar00rootroot00000000000000thrift-0.16.0/test/go/src/bin/000077500000000000000000000000001420101504100160055ustar00rootroot00000000000000thrift-0.16.0/test/go/src/bin/stress/000077500000000000000000000000001420101504100173305ustar00rootroot00000000000000thrift-0.16.0/test/go/src/bin/stress/main.go000066400000000000000000000155141420101504100206110ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"sync"
	"sync/atomic"
	"time"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/apache/thrift/test/go/src/gen/stress"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
var memprofile = flag.String("memprofile", "", "write memory profile to this file")

var (
	host      = flag.String("host", "localhost", "Host to connect")
	port      = flag.Int64("port", 9091, "Port number to connect")
	loop      = flag.Int("loops", 50000, "The number of remote thrift calls each client makes")
	runserver = flag.Int("server", 1, "Run the Thrift server in this process")
	clients   = flag.Int("clients", 20, "Number of client threads to create - 0 implies no clients, i.e. server only")
	callName  = flag.String("call", "echoVoid", "Service method to call, one of echoVoid, echoByte, echoI32, echoI64, echoString, echiList, echoSet, echoMap")
	compact   = flag.Bool("compact", false, "Use compact protocol instead of binary.")
	framed    = flag.Bool("framed", false, "Use framed transport instead of buffered.")
)
var hostPort string

type callT int64

const (
	echoVoid callT = iota
	echoByte
	echoI32
	echoI64
	echoString
	echiList
	echoSet
	echoMap
)

var callTMap = map[string]callT{
	"echoVoid":   echoVoid,
	"echoByte":   echoByte,
	"echoI32":    echoI32,
	"echoI64":    echoI64,
	"echoString": echoString,
	"echiList":   echiList,
	"echoSet":    echoSet,
	"echoMap":    echoMap,
}
var callType callT

var ready, done sync.WaitGroup

var clicounter int64 = 0
var counter int64 = 0

func main() {
	flag.Parse()
	if *memprofile != "" {
		runtime.MemProfileRate = 100
	}
	var ok bool
	if callType, ok = callTMap[*callName]; !ok {
		log.Fatal("Unknown service call", *callName)
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	hostPort = fmt.Sprintf("%s:%d", *host, *port)
	var protocolFactory thrift.TProtocolFactory
	var transportFactory thrift.TTransportFactory

	if *compact {
		protocolFactory = thrift.NewTCompactProtocolFactoryConf(nil)
	} else {
		protocolFactory = thrift.NewTBinaryProtocolFactoryConf(nil)
	}

	if *framed {
		transportFactory = thrift.NewTTransportFactory()
		transportFactory = thrift.NewTFramedTransportFactoryConf(transportFactory, nil)
	} else {
		transportFactory = thrift.NewTBufferedTransportFactory(8192)
	}

	if *runserver > 0 {
		serverTransport, err := thrift.NewTServerSocket(hostPort)
		if err != nil {
			log.Fatalf("Unable to create server socket: %s", err)
		}

		processor := stress.NewServiceProcessor(&handler{})
		server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
		if *clients == 0 {
			server.Serve()
		} else {
			go server.Serve()
		}
	}
	//start clients
	if *clients != 0 {
		ready.Add(*clients + 1)
		done.Add(*clients)
		for i := 0; i < *clients; i++ {
			go client(protocolFactory)
		}
		ready.Done()
		ready.Wait()
		//run!
		startTime := time.Now()
		//wait for completion
		done.Wait()
		endTime := time.Now()
		duration := endTime.Sub(startTime)
		log.Printf("%d calls in %v (%f calls per second)\n", clicounter, duration, float64(clicounter)/duration.Seconds())
	}
	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}
}

func client(protocolFactory thrift.TProtocolFactory) {
	ctx := context.Background()
	trans := thrift.NewTSocketConf(hostPort, nil)
	btrans := thrift.NewTBufferedTransport(trans, 2048)
	client := stress.NewServiceClientFactory(btrans, protocolFactory)
	err := trans.Open()
	if err != nil {
		log.Fatalf("Unable to open connection: %s", err)
	}
	ready.Done()
	ready.Wait()
	switch callType {
	case echoVoid:
		for i := 0; i < *loop; i++ {
			client.EchoVoid(ctx)
			atomic.AddInt64(&clicounter, 1)
		}
	case echoByte:
		for i := 0; i < *loop; i++ {
			client.EchoByte(ctx, 42)
			atomic.AddInt64(&clicounter, 1)
		}
	case echoI32:
		for i := 0; i < *loop; i++ {
			client.EchoI32(ctx, 4242)
			atomic.AddInt64(&clicounter, 1)
		}
	case echoI64:
		for i := 0; i < *loop; i++ {
			client.EchoI64(ctx, 424242)
			atomic.AddInt64(&clicounter, 1)
		}
	case echoString:
		for i := 0; i < *loop; i++ {
			client.EchoString(ctx, "TestString")
			atomic.AddInt64(&clicounter, 1)
		}
	case echiList:
		l := []int8{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8}
		for i := 0; i < *loop; i++ {
			client.EchoList(ctx, l)
			atomic.AddInt64(&clicounter, 1)
		}
	case echoSet:
		s := []int8{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8}
		for i := 0; i < *loop; i++ {
			client.EchoSet(ctx, s)
			atomic.AddInt64(&clicounter, 1)
		}
	case echoMap:
		m := map[int8]int8{-10: 10, -9: 9, -8: 8, -7: 7, -6: 6, -5: 5, -4: 4, -3: 3, -2: 2, -1: 1, 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8}
		for i := 0; i < *loop; i++ {
			client.EchoMap(ctx, m)
			atomic.AddInt64(&clicounter, 1)
		}
	}

	done.Done()
}

type handler struct{}

func (h *handler) EchoVoid(ctx context.Context) (err error) {
	atomic.AddInt64(&counter, 1)
	return nil
}
func (h *handler) EchoByte(ctx context.Context, arg int8) (r int8, err error) {
	atomic.AddInt64(&counter, 1)
	return arg, nil
}
func (h *handler) EchoI32(ctx context.Context, arg int32) (r int32, err error) {
	atomic.AddInt64(&counter, 1)
	return arg, nil
}
func (h *handler) EchoI64(ctx context.Context, arg int64) (r int64, err error) {
	atomic.AddInt64(&counter, 1)
	return arg, nil
}
func (h *handler) EchoString(ctx context.Context, arg string) (r string, err error) {
	atomic.AddInt64(&counter, 1)
	return arg, nil
}
func (h *handler) EchoList(ctx context.Context, arg []int8) (r []int8, err error) {
	atomic.AddInt64(&counter, 1)
	return arg, nil
}
func (h *handler) EchoSet(ctx context.Context, arg []int8) (r []int8, err error) {
	atomic.AddInt64(&counter, 1)
	return arg, nil
}
func (h *handler) EchoMap(ctx context.Context, arg map[int8]int8) (r map[int8]int8, err error) {
	atomic.AddInt64(&counter, 1)
	return arg, nil
}
thrift-0.16.0/test/go/src/bin/testclient/000077500000000000000000000000001420101504100201635ustar00rootroot00000000000000thrift-0.16.0/test/go/src/bin/testclient/main.go000066400000000000000000000232771420101504100214510ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package main

import (
	"context"
	"flag"
	t "log"
	"reflect"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/apache/thrift/test/go/src/common"
	"github.com/apache/thrift/test/go/src/gen/thrifttest"
)

var host = flag.String("host", "localhost", "Host to connect")
var port = flag.Int64("port", 9090, "Port number to connect")
var domain_socket = flag.String("domain-socket", "", "Domain Socket (e.g. /tmp/thrifttest.thrift), instead of host and port")
var transport = flag.String("transport", "buffered", "Transport: buffered, framed, http, zlib")
var protocol = flag.String("protocol", "binary", "Protocol: binary, compact, json")
var ssl = flag.Bool("ssl", false, "Encrypted Transport using SSL")
var testloops = flag.Int("testloops", 1, "Number of Tests")

func main() {
	flag.Parse()
	client, _, err := common.StartClient(*host, *port, *domain_socket, *transport, *protocol, *ssl)
	if err != nil {
		t.Fatalf("Unable to start client: ", err)
	}
	for i := 0; i < *testloops; i++ {
		callEverything(client)
	}
}

var rmapmap = map[int32]map[int32]int32{
	-4: {-4: -4, -3: -3, -2: -2, -1: -1},
	4:  {4: 4, 3: 3, 2: 2, 1: 1},
}

var xxs = &thrifttest.Xtruct{
	StringThing: "Hello2",
	ByteThing:   42,
	I32Thing:    4242,
	I64Thing:    424242,
}

var xcept = &thrifttest.Xception{ErrorCode: 1001, Message: "Xception"}
var defaultCtx = context.Background()

func callEverything(client *thrifttest.ThriftTestClient) {
	var err error
	if err = client.TestVoid(defaultCtx); err != nil {
		t.Fatalf("Unexpected error in TestVoid() call: ", err)
	}

	thing, err := client.TestString(defaultCtx, "thing")
	if err != nil {
		t.Fatalf("Unexpected error in TestString() call: ", err)
	}
	if thing != "thing" {
		t.Fatalf("Unexpected TestString() result, expected 'thing' got '%s' ", thing)
	}

	bl, err := client.TestBool(defaultCtx, true)
	if err != nil {
		t.Fatalf("Unexpected error in TestBool() call: ", err)
	}
	if !bl {
		t.Fatalf("Unexpected TestBool() result expected true, got %f ", bl)
	}
	bl, err = client.TestBool(defaultCtx, false)
	if err != nil {
		t.Fatalf("Unexpected error in TestBool() call: ", err)
	}
	if bl {
		t.Fatalf("Unexpected TestBool() result expected false, got %f ", bl)
	}

	b, err := client.TestByte(defaultCtx, 42)
	if err != nil {
		t.Fatalf("Unexpected error in TestByte() call: ", err)
	}
	if b != 42 {
		t.Fatalf("Unexpected TestByte() result expected 42, got %d ", b)
	}

	i32, err := client.TestI32(defaultCtx, 4242)
	if err != nil {
		t.Fatalf("Unexpected error in TestI32() call: ", err)
	}
	if i32 != 4242 {
		t.Fatalf("Unexpected TestI32() result expected 4242, got %d ", i32)
	}

	i64, err := client.TestI64(defaultCtx, 424242)
	if err != nil {
		t.Fatalf("Unexpected error in TestI64() call: ", err)
	}
	if i64 != 424242 {
		t.Fatalf("Unexpected TestI64() result expected 424242, got %d ", i64)
	}

	d, err := client.TestDouble(defaultCtx, 42.42)
	if err != nil {
		t.Fatalf("Unexpected error in TestDouble() call: ", err)
	}
	if d != 42.42 {
		t.Fatalf("Unexpected TestDouble() result expected 42.42, got %f ", d)
	}

	binout := make([]byte, 256)
	for i := 0; i < 256; i++ {
		binout[i] = byte(i)
	}
	bin, err := client.TestBinary(defaultCtx, binout)
	if err != nil {
		t.Fatalf("TestBinary failed with %v", err)
	}
	for i := 0; i < 256; i++ {
		if binout[i] != bin[i] {
			t.Fatalf("Unexpected TestBinary() result expected %d, got %d ", binout[i], bin[i])
		}
	}

	xs := thrifttest.NewXtruct()
	xs.StringThing = "thing"
	xs.ByteThing = 42
	xs.I32Thing = 4242
	xs.I64Thing = 424242
	xsret, err := client.TestStruct(defaultCtx, xs)
	if err != nil {
		t.Fatalf("Unexpected error in TestStruct() call: ", err)
	}
	if *xs != *xsret {
		t.Fatalf("Unexpected TestStruct() result expected %#v, got %#v ", xs, xsret)
	}

	x2 := thrifttest.NewXtruct2()
	x2.StructThing = xs
	x2ret, err := client.TestNest(defaultCtx, x2)
	if err != nil {
		t.Fatalf("Unexpected error in TestNest() call: ", err)
	}
	if !reflect.DeepEqual(x2, x2ret) {
		t.Fatalf("Unexpected TestNest() result expected %#v, got %#v ", x2, x2ret)
	}

	m := map[int32]int32{1: 2, 3: 4, 5: 42}
	mret, err := client.TestMap(defaultCtx, m)
	if err != nil {
		t.Fatalf("Unexpected error in TestMap() call: ", err)
	}
	if !reflect.DeepEqual(m, mret) {
		t.Fatalf("Unexpected TestMap() result expected %#v, got %#v ", m, mret)
	}

	sm := map[string]string{"a": "2", "b": "blah", "some": "thing"}
	smret, err := client.TestStringMap(defaultCtx, sm)
	if err != nil {
		t.Fatalf("Unexpected error in TestStringMap() call: ", err)
	}
	if !reflect.DeepEqual(sm, smret) {
		t.Fatalf("Unexpected TestStringMap() result expected %#v, got %#v ", sm, smret)
	}

	s := []int32{1, 2, 42}
	sret, err := client.TestSet(defaultCtx, s)
	if err != nil {
		t.Fatalf("Unexpected error in TestSet() call: ", err)
	}
	// Sets can be in any order, but Go slices are ordered, so reflect.DeepEqual won't work.
	stemp := map[int32]struct{}{}
	for _, val := range s {
		stemp[val] = struct{}{}
	}
	for _, val := range sret {
		if _, ok := stemp[val]; !ok {
			t.Fatalf("Unexpected TestSet() result expected %#v, got %#v ", s, sret)
		}
	}

	l := []int32{1, 2, 42}
	lret, err := client.TestList(defaultCtx, l)
	if err != nil {
		t.Fatalf("Unexpected error in TestList() call: ", err)
	}
	if !reflect.DeepEqual(l, lret) {
		t.Fatalf("Unexpected TestList() result expected %#v, got %#v ", l, lret)
	}

	eret, err := client.TestEnum(defaultCtx, thrifttest.Numberz_TWO)
	if err != nil {
		t.Fatalf("Unexpected error in TestEnum() call: ", err)
	}
	if eret != thrifttest.Numberz_TWO {
		t.Fatalf("Unexpected TestEnum() result expected %#v, got %#v ", thrifttest.Numberz_TWO, eret)
	}

	tret, err := client.TestTypedef(defaultCtx, thrifttest.UserId(42))
	if err != nil {
		t.Fatalf("Unexpected error in TestTypedef() call: ", err)
	}
	if tret != thrifttest.UserId(42) {
		t.Fatalf("Unexpected TestTypedef() result expected %#v, got %#v ", thrifttest.UserId(42), tret)
	}

	mapmap, err := client.TestMapMap(defaultCtx, 42)
	if err != nil {
		t.Fatalf("Unexpected error in TestMapMap() call: ", err)
	}
	if !reflect.DeepEqual(mapmap, rmapmap) {
		t.Fatalf("Unexpected TestMapMap() result expected %#v, got %#v ", rmapmap, mapmap)
	}

	crazy := thrifttest.NewInsanity()
	crazy.UserMap = map[thrifttest.Numberz]thrifttest.UserId{
		thrifttest.Numberz_FIVE:  5,
		thrifttest.Numberz_EIGHT: 8,
	}
	truck1 := thrifttest.NewXtruct()
	truck1.StringThing = "Goodbye4"
	truck1.ByteThing = 4
	truck1.I32Thing = 4
	truck1.I64Thing = 4
	truck2 := thrifttest.NewXtruct()
	truck2.StringThing = "Hello2"
	truck2.ByteThing = 2
	truck2.I32Thing = 2
	truck2.I64Thing = 2
	crazy.Xtructs = []*thrifttest.Xtruct{
		truck1,
		truck2,
	}
	insanity, err := client.TestInsanity(defaultCtx, crazy)
	if err != nil {
		t.Fatalf("Unexpected error in TestInsanity() call: ", err)
	}
	if !reflect.DeepEqual(crazy, insanity[1][2]) {
		t.Fatalf("Unexpected TestInsanity() first result expected %#v, got %#v ",
			crazy,
			insanity[1][2])
	}
	if !reflect.DeepEqual(crazy, insanity[1][3]) {
		t.Fatalf("Unexpected TestInsanity() second result expected %#v, got %#v ",
			crazy,
			insanity[1][3])
	}
	if len(insanity[2][6].UserMap) > 0 || len(insanity[2][6].Xtructs) > 0 {
		t.Fatalf("Unexpected TestInsanity() non-empty result got %#v ",
			insanity[2][6])
	}

	xxsret, err := client.TestMulti(defaultCtx, 42, 4242, 424242, map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24))
	if err != nil {
		t.Fatalf("Unexpected error in TestMulti() call: ", err)
	}
	if !reflect.DeepEqual(xxs, xxsret) {
		t.Fatalf("Unexpected TestMulti() result expected %#v, got %#v ", xxs, xxsret)
	}

	err = client.TestException(defaultCtx, "Xception")
	if err == nil {
		t.Fatalf("Expecting exception in TestException() call")
	}
	if !reflect.DeepEqual(err, xcept) {
		t.Fatalf("Unexpected TestException() result expected %#v, got %#v ", xcept, err)
	}

	err = client.TestException(defaultCtx, "TException")
	_, ok := err.(thrift.TApplicationException)
	if err == nil || !ok {
		t.Fatalf("Unexpected TestException() result expected ApplicationError, got %#v ", err)
	}

	ign, err := client.TestMultiException(defaultCtx, "Xception", "ignoreme")
	if ign != nil || err == nil {
		t.Fatalf("Expecting exception in TestMultiException() call")
	}
	if !reflect.DeepEqual(err, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}) {
		t.Fatalf("Unexpected TestMultiException() %#v ", err)
	}

	ign, err = client.TestMultiException(defaultCtx, "Xception2", "ignoreme")
	if ign != nil || err == nil {
		t.Fatalf("Expecting exception in TestMultiException() call")
	}
	expecting := &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}

	if !reflect.DeepEqual(err, expecting) {
		t.Fatalf("Unexpected TestMultiException() %#v ", err)
	}

	err = client.TestOneway(defaultCtx, 2)
	if err != nil {
		t.Fatalf("Unexpected error in TestOneway() call: ", err)
	}

	//Make sure the connection still alive
	if err = client.TestVoid(defaultCtx); err != nil {
		t.Fatalf("Unexpected error in TestVoid() call: ", err)
	}
}
thrift-0.16.0/test/go/src/bin/testserver/000077500000000000000000000000001420101504100202135ustar00rootroot00000000000000thrift-0.16.0/test/go/src/bin/testserver/main.go000066400000000000000000000046141420101504100214730ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/apache/thrift/test/go/src/common"
)

var host = flag.String("host", "localhost", "Host to connect")
var port = flag.Int64("port", 9090, "Port number to connect")
var domain_socket = flag.String("domain-socket", "", "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
var transport = flag.String("transport", "buffered", "Transport: buffered, framed, http, zlib")
var protocol = flag.String("protocol", "binary", "Protocol: binary, compact, json, header")
var ssl = flag.Bool("ssl", false, "Encrypted Transport using SSL")
var certPath = flag.String("certPath", "keys", "Directory that contains SSL certificates")

func main() {
	flag.Parse()

	processor, serverTransport, transportFactory, protocolFactory, err := common.GetServerParams(*host, *port, *domain_socket, *transport, *protocol, *ssl, *certPath, common.PrintingHandler)

	if err != nil {
		log.Fatalf("Unable to process server params: %v", err)
	}

	if *transport == "http" {
		http.HandleFunc("/", thrift.NewThriftHandlerFunc(processor, protocolFactory, protocolFactory))

		if *ssl {
			err := http.ListenAndServeTLS(fmt.Sprintf(":%d", *port),
				*certPath+"/server.pem", *certPath+"/server.key", nil)

			if err != nil {
				fmt.Println(err)
				return
			}
		} else {
			http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
		}
	} else {
		server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
		if err = server.Listen(); err != nil {
			return
		}
		go server.AcceptLoop()
		server.Serve()
	}
}
thrift-0.16.0/test/go/src/common/000077500000000000000000000000001420101504100165255ustar00rootroot00000000000000thrift-0.16.0/test/go/src/common/client.go000066400000000000000000000066031420101504100203370ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package common

import (
	"compress/zlib"
	"crypto/tls"
	"flag"
	"fmt"
	"net/http"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/apache/thrift/test/go/src/gen/thrifttest"
)

var debugClientProtocol bool

func init() {
	flag.BoolVar(&debugClientProtocol, "debug_client_protocol", false, "turn client protocol trace on")
}

func StartClient(
	host string,
	port int64,
	domain_socket string,
	transport string,
	protocol string,
	ssl bool,
) (client *thrifttest.ThriftTestClient, trans thrift.TTransport, err error) {
	hostPort := fmt.Sprintf("%s:%d", host, port)
	cfg := &thrift.TConfiguration{
		TLSConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}

	var protocolFactory thrift.TProtocolFactory
	switch protocol {
	case "compact":
		protocolFactory = thrift.NewTCompactProtocolFactoryConf(cfg)
	case "simplejson":
		protocolFactory = thrift.NewTSimpleJSONProtocolFactoryConf(cfg)
	case "json":
		protocolFactory = thrift.NewTJSONProtocolFactory()
	case "binary":
		protocolFactory = thrift.NewTBinaryProtocolFactoryConf(cfg)
	case "header":
		protocolFactory = thrift.NewTHeaderProtocolFactoryConf(cfg)
	default:
		return nil, nil, fmt.Errorf("invalid protocol specified %s", protocol)
	}
	if debugClientProtocol {
		protocolFactory = thrift.NewTDebugProtocolFactoryWithLogger(protocolFactory, "client:", thrift.StdLogger(nil))
	}
	if ssl {
		trans = thrift.NewTSSLSocketConf(hostPort, cfg)
	} else {
		if domain_socket != "" {
			trans = thrift.NewTSocketConf(domain_socket, nil)
		} else {
			trans = thrift.NewTSocketConf(hostPort, nil)
		}
	}
	if err != nil {
		return nil, nil, err
	}
	switch transport {
	case "http":
		if ssl {
			tr := &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			}
			client := &http.Client{Transport: tr}
			trans, err = thrift.NewTHttpClientWithOptions(fmt.Sprintf("https://%s/", hostPort), thrift.THttpClientOptions{Client: client})
			fmt.Println(hostPort)
		} else {
			trans, err = thrift.NewTHttpClient(fmt.Sprintf("http://%s/", hostPort))
		}
	case "framed":
		trans = thrift.NewTFramedTransportConf(trans, cfg)
	case "buffered":
		trans = thrift.NewTBufferedTransport(trans, 8192)
	case "zlib":
		trans, err = thrift.NewTZlibTransport(trans, zlib.BestCompression)
	case "":
		// Do nothing
	default:
		return nil, nil, fmt.Errorf("invalid transport specified %s", transport)
	}
	if err != nil {
		return nil, nil, err
	}
	if err = trans.Open(); err != nil {
		return nil, nil, err
	}
	iprot := protocolFactory.GetProtocol(trans)
	oprot := protocolFactory.GetProtocol(trans)
	client = thrifttest.NewThriftTestClient(thrift.NewTStandardClient(iprot, oprot))
	return
}
thrift-0.16.0/test/go/src/common/clientserver_test.go000066400000000000000000000277611420101504100226350ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package common

import (
	"context"
	"errors"
	"reflect"
	"sync"
	"testing"

	"github.com/golang/mock/gomock"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/apache/thrift/test/go/src/gen/thrifttest"
)

type test_unit struct {
	host          string
	port          int64
	domain_socket string
	transport     string
	protocol      string
	ssl           bool
}

var units = []test_unit{
	{"127.0.0.1", 9095, "", "", "binary", false},
	{"127.0.0.1", 9091, "", "", "compact", false},
	{"127.0.0.1", 9092, "", "", "binary", true},
	{"127.0.0.1", 9093, "", "", "compact", true},
}

func TestAllConnection(t *testing.T) {
	wg := &sync.WaitGroup{}
	wg.Add(len(units))
	for _, unit := range units {
		go func(u test_unit) {
			defer wg.Done()
			doUnit(t, &u)
		}(unit)
	}
	wg.Wait()
}

func doUnit(t *testing.T, unit *test_unit) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	handler := NewMockThriftTest(ctrl)

	processor, serverTransport, transportFactory, protocolFactory, err := GetServerParams(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl, "../../../keys", handler)
	if err != nil {
		t.Errorf("GetServerParams failed: %v", err)
	}

	server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
	if err = server.Listen(); err != nil {
		t.Errorf("Unable to start server: %v", err)
		return
	}
	go server.AcceptLoop()
	defer server.Stop()
	client, trans, err := StartClient(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl)
	if err != nil {
		t.Errorf("Unable to start client: %v", err)
		return
	}
	defer trans.Close()
	callEverythingWithMock(t, client, handler)
}

var rmapmap = map[int32]map[int32]int32{
	-4: {-4: -4, -3: -3, -2: -2, -1: -1},
	4:  {4: 4, 3: 3, 2: 2, 1: 1},
}

var xxs = &thrifttest.Xtruct{
	StringThing: "Hello2",
	ByteThing:   42,
	I32Thing:    4242,
	I64Thing:    424242,
}

var xcept = &thrifttest.Xception{ErrorCode: 1001, Message: "some"}
var defaultCtx = context.Background()

func callEverythingWithMock(t *testing.T, client *thrifttest.ThriftTestClient, handler *MockThriftTest) {
	gomock.InOrder(
		handler.EXPECT().TestVoid(gomock.Any()),
		handler.EXPECT().TestString(gomock.Any(), "thing").Return("thing", nil),
		handler.EXPECT().TestBool(gomock.Any(), true).Return(true, nil),
		handler.EXPECT().TestBool(gomock.Any(), false).Return(false, nil),
		handler.EXPECT().TestByte(gomock.Any(), int8(42)).Return(int8(42), nil),
		handler.EXPECT().TestI32(gomock.Any(), int32(4242)).Return(int32(4242), nil),
		handler.EXPECT().TestI64(gomock.Any(), int64(424242)).Return(int64(424242), nil),
		// TODO: add TestBinary()
		handler.EXPECT().TestDouble(gomock.Any(), float64(42.42)).Return(float64(42.42), nil),
		handler.EXPECT().TestStruct(gomock.Any(), &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}).Return(&thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}, nil),
		handler.EXPECT().TestNest(gomock.Any(), &thrifttest.Xtruct2{StructThing: &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}}).Return(&thrifttest.Xtruct2{StructThing: &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}}, nil),
		handler.EXPECT().TestMap(gomock.Any(), map[int32]int32{1: 2, 3: 4, 5: 42}).Return(map[int32]int32{1: 2, 3: 4, 5: 42}, nil),
		handler.EXPECT().TestStringMap(gomock.Any(), map[string]string{"a": "2", "b": "blah", "some": "thing"}).Return(map[string]string{"a": "2", "b": "blah", "some": "thing"}, nil),
		handler.EXPECT().TestSet(gomock.Any(), []int32{1, 2, 42}).Return([]int32{1, 2, 42}, nil),
		handler.EXPECT().TestList(gomock.Any(), []int32{1, 2, 42}).Return([]int32{1, 2, 42}, nil),
		handler.EXPECT().TestEnum(gomock.Any(), thrifttest.Numberz_TWO).Return(thrifttest.Numberz_TWO, nil),
		handler.EXPECT().TestTypedef(gomock.Any(), thrifttest.UserId(42)).Return(thrifttest.UserId(42), nil),
		handler.EXPECT().TestMapMap(gomock.Any(), int32(42)).Return(rmapmap, nil),
		// TODO: not testing insanity
		handler.EXPECT().TestMulti(gomock.Any(), int8(42), int32(4242), int64(424242), map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24)).Return(xxs, nil),
		handler.EXPECT().TestException(gomock.Any(), "some").Return(xcept),
		handler.EXPECT().TestException(gomock.Any(), "TException").Return(errors.New("Just random exception")),
		handler.EXPECT().TestMultiException(gomock.Any(), "Xception", "ignoreme").Return(nil, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}),
		handler.EXPECT().TestMultiException(gomock.Any(), "Xception2", "ignoreme").Return(nil, &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}),
		handler.EXPECT().TestOneway(gomock.Any(), int32(2)).Return(nil),
		handler.EXPECT().TestVoid(gomock.Any()),
	)
	var err error
	if err = client.TestVoid(defaultCtx); err != nil {
		t.Errorf("Unexpected error in TestVoid() call: %s", err)
	}

	thing, err := client.TestString(defaultCtx, "thing")
	if err != nil {
		t.Errorf("Unexpected error in TestString() call: %s", err)
	}
	if thing != "thing" {
		t.Errorf("Unexpected TestString() result, expected 'thing' got '%s' ", thing)
	}

	bl, err := client.TestBool(defaultCtx, true)
	if err != nil {
		t.Errorf("Unexpected error in TestBool() call: %s", err)
	}
	if !bl {
		t.Errorf("Unexpected TestBool() result expected true, got %v ", bl)
	}
	bl, err = client.TestBool(defaultCtx, false)
	if err != nil {
		t.Errorf("Unexpected error in TestBool() call: %s", err)
	}
	if bl {
		t.Errorf("Unexpected TestBool() result expected false, got %v ", bl)
	}

	b, err := client.TestByte(defaultCtx, 42)
	if err != nil {
		t.Errorf("Unexpected error in TestByte() call: %s", err)
	}
	if b != 42 {
		t.Errorf("Unexpected TestByte() result expected 42, got %d ", b)
	}

	i32, err := client.TestI32(defaultCtx, 4242)
	if err != nil {
		t.Errorf("Unexpected error in TestI32() call: %s", err)
	}
	if i32 != 4242 {
		t.Errorf("Unexpected TestI32() result expected 4242, got %d ", i32)
	}

	i64, err := client.TestI64(defaultCtx, 424242)
	if err != nil {
		t.Errorf("Unexpected error in TestI64() call: %s", err)
	}
	if i64 != 424242 {
		t.Errorf("Unexpected TestI64() result expected 424242, got %d ", i64)
	}

	d, err := client.TestDouble(defaultCtx, 42.42)
	if err != nil {
		t.Errorf("Unexpected error in TestDouble() call: %s", err)
	}
	if d != 42.42 {
		t.Errorf("Unexpected TestDouble() result expected 42.42, got %f ", d)
	}

	// TODO: add TestBinary() call

	xs := thrifttest.NewXtruct()
	xs.StringThing = "thing"
	xs.ByteThing = 42
	xs.I32Thing = 4242
	xs.I64Thing = 424242
	xsret, err := client.TestStruct(defaultCtx, xs)
	if err != nil {
		t.Errorf("Unexpected error in TestStruct() call: %s", err)
	}
	if *xs != *xsret {
		t.Errorf("Unexpected TestStruct() result expected %#v, got %#v ", xs, xsret)
	}

	x2 := thrifttest.NewXtruct2()
	x2.StructThing = xs
	x2ret, err := client.TestNest(defaultCtx, x2)
	if err != nil {
		t.Errorf("Unexpected error in TestNest() call: %s", err)
	}
	if !reflect.DeepEqual(x2, x2ret) {
		t.Errorf("Unexpected TestNest() result expected %#v, got %#v ", x2, x2ret)
	}

	m := map[int32]int32{1: 2, 3: 4, 5: 42}
	mret, err := client.TestMap(defaultCtx, m)
	if err != nil {
		t.Errorf("Unexpected error in TestMap() call: %s", err)
	}
	if !reflect.DeepEqual(m, mret) {
		t.Errorf("Unexpected TestMap() result expected %#v, got %#v ", m, mret)
	}

	sm := map[string]string{"a": "2", "b": "blah", "some": "thing"}
	smret, err := client.TestStringMap(defaultCtx, sm)
	if err != nil {
		t.Errorf("Unexpected error in TestStringMap() call: %s", err)
	}
	if !reflect.DeepEqual(sm, smret) {
		t.Errorf("Unexpected TestStringMap() result expected %#v, got %#v ", sm, smret)
	}

	s := []int32{1, 2, 42}
	sret, err := client.TestSet(defaultCtx, s)
	if err != nil {
		t.Errorf("Unexpected error in TestSet() call: %s", err)
	}
	// Sets can be in any order, but Go slices are ordered, so reflect.DeepEqual won't work.
	stemp := map[int32]struct{}{}
	for _, val := range s {
		stemp[val] = struct{}{}
	}
	for _, val := range sret {
		if _, ok := stemp[val]; !ok {
			t.Fatalf("Unexpected TestSet() result expected %#v, got %#v ", s, sret)
		}
	}

	l := []int32{1, 2, 42}
	lret, err := client.TestList(defaultCtx, l)
	if err != nil {
		t.Errorf("Unexpected error in TestList() call: %s", err)
	}
	if !reflect.DeepEqual(l, lret) {
		t.Errorf("Unexpected TestList() result expected %#v, got %#v ", l, lret)
	}

	eret, err := client.TestEnum(defaultCtx, thrifttest.Numberz_TWO)
	if err != nil {
		t.Errorf("Unexpected error in TestEnum() call: %s", err)
	}
	if eret != thrifttest.Numberz_TWO {
		t.Errorf("Unexpected TestEnum() result expected %#v, got %#v ", thrifttest.Numberz_TWO, eret)
	}

	tret, err := client.TestTypedef(defaultCtx, thrifttest.UserId(42))
	if err != nil {
		t.Errorf("Unexpected error in TestTypedef() call: %s", err)
	}
	if tret != thrifttest.UserId(42) {
		t.Errorf("Unexpected TestTypedef() result expected %#v, got %#v ", thrifttest.UserId(42), tret)
	}

	mapmap, err := client.TestMapMap(defaultCtx, 42)
	if err != nil {
		t.Errorf("Unexpected error in TestMapmap() call: %s", err)
	}
	if !reflect.DeepEqual(mapmap, rmapmap) {
		t.Errorf("Unexpected TestMapmap() result expected %#v, got %#v ", rmapmap, mapmap)
	}

	xxsret, err := client.TestMulti(defaultCtx, 42, 4242, 424242, map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24))
	if err != nil {
		t.Errorf("Unexpected error in TestMulti() call: %s", err)
	}
	if !reflect.DeepEqual(xxs, xxsret) {
		t.Errorf("Unexpected TestMulti() result expected %#v, got %#v ", xxs, xxsret)
	}

	err = client.TestException(defaultCtx, "some")
	if err == nil {
		t.Errorf("Expecting exception in TestException() call")
	}
	if !reflect.DeepEqual(err, xcept) {
		t.Errorf("Unexpected TestException() result expected %#v, got %#v ", xcept, err)
	}

	// TODO: connection is being closed on this
	err = client.TestException(defaultCtx, "TException")
	if err == nil {
		t.Error("expected exception got nil")
	} else if tex, ok := err.(thrift.TApplicationException); !ok {
		t.Errorf("Unexpected TestException() result expected ApplicationError, got %T ", err)
	} else if tex.TypeId() != thrift.INTERNAL_ERROR {
		t.Errorf("expected internal_error got %v", tex.TypeId())
	}

	ign, err := client.TestMultiException(defaultCtx, "Xception", "ignoreme")
	if ign != nil || err == nil {
		t.Errorf("Expecting exception in TestMultiException() call")
	}
	if !reflect.DeepEqual(err, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}) {
		t.Errorf("Unexpected TestMultiException() %#v ", err)
	}

	ign, err = client.TestMultiException(defaultCtx, "Xception2", "ignoreme")
	if ign != nil || err == nil {
		t.Errorf("Expecting exception in TestMultiException() call")
	}
	expecting := &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}

	if !reflect.DeepEqual(err, expecting) {
		t.Errorf("Unexpected TestMultiException() %#v ", err)
	}

	err = client.TestOneway(defaultCtx, 2)
	if err != nil {
		t.Errorf("Unexpected error in TestOneway() call: %s", err)
	}

	//Make sure the connection still alive
	if err = client.TestVoid(defaultCtx); err != nil {
		t.Errorf("Unexpected error in TestVoid() call: %s", err)
	}
}
thrift-0.16.0/test/go/src/common/context_test.go000066400000000000000000000053161420101504100216040ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package common

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"syscall"
	"testing"
	"time"

	"github.com/apache/thrift/lib/go/thrift"
)

type slowHttpHandler struct{}

func (slowHttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	time.Sleep(1 * time.Second)
}

func TestHttpContextTimeout(t *testing.T) {
	unit := test_unit{"127.0.0.1", 9096, "", "http", "binary", false}

	server := &http.Server{Addr: unit.host + fmt.Sprintf(":%d", unit.port), Handler: slowHttpHandler{}}
	go server.ListenAndServe()

	client, trans, err := StartClient(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl)
	if err != nil {
		t.Errorf("Unable to start client: %v", err)
		return
	}
	defer trans.Close()

	unwrapErr := func(err error) error {
		for {
			//lint:ignore S1034 type switch is more appropriate here.
			switch err.(type) {
			case thrift.TTransportException:
				err = err.(thrift.TTransportException).Err()
			case *url.Error:
				err = err.(*url.Error).Err
			case *net.OpError:
				err = err.(*net.OpError).Err
			case *os.SyscallError:
				err = err.(*os.SyscallError).Err
			default:
				return err
			}
		}
	}

	serverStartupDeadline := time.Now().Add(5 * time.Second)
	for {
		ctx, _ := context.WithTimeout(context.Background(), 50*time.Millisecond)
		err = client.TestVoid(ctx)
		err = unwrapErr(err)
		if err != syscall.ECONNREFUSED || time.Now().After(serverStartupDeadline) {
			break
		}
		time.Sleep(time.Millisecond)
	}

	if err == nil {
		t.Errorf("Request completed (should have timed out)")
		return
	}

	// We've got to switch on `err.Error()` here since go1.7 doesn't properly return
	// `context.DeadlineExceeded` error and `http.errRequestCanceled` is not exported.
	// See https://github.com/golang/go/issues/17711
	switch err.Error() {
	case context.DeadlineExceeded.Error(), "net/http: request canceled":
		// Expected error
	default:
		t.Errorf("Unexpected error: %s", err)
	}
}
thrift-0.16.0/test/go/src/common/printing_handler.go000066400000000000000000000266111420101504100224110ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package common

import (
	"context"
	"encoding/hex"
	"errors"
	"fmt"
	"time"

	//lint:ignore ST1001 allow dot import here
	. "github.com/apache/thrift/test/go/src/gen/thrifttest"
)

var PrintingHandler = &printingHandler{}

type printingHandler struct{}

// Prints "testVoid()" and returns nothing.
func (p *printingHandler) TestVoid(ctx context.Context) (err error) {
	fmt.Println("testVoid()")
	return nil
}

// Prints 'testString("%s")' with thing as '%s'
// @param string thing - the string to print
// @return string - returns the string 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestString(ctx context.Context, thing string) (r string, err error) {
	fmt.Printf("testString(\"%s\")\n", thing)
	return thing, nil
}

// Prints 'testBool("%t")' with thing as 'true' or 'false'
// @param bool thing - the bool to print
// @return bool - returns the bool 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestBool(ctx context.Context, thing bool) (r bool, err error) {
	fmt.Printf("testBool(%t)\n", thing)
	return thing, nil
}

// Prints 'testByte("%d")' with thing as '%d'
// @param byte thing - the byte to print
// @return byte - returns the byte 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestByte(ctx context.Context, thing int8) (r int8, err error) {
	fmt.Printf("testByte(%d)\n", thing)
	return thing, nil
}

// Prints 'testI32("%d")' with thing as '%d'
// @param i32 thing - the i32 to print
// @return i32 - returns the i32 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestI32(ctx context.Context, thing int32) (r int32, err error) {
	fmt.Printf("testI32(%d)\n", thing)
	return thing, nil
}

// Prints 'testI64("%d")' with thing as '%d'
// @param i64 thing - the i64 to print
// @return i64 - returns the i64 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestI64(ctx context.Context, thing int64) (r int64, err error) {
	fmt.Printf("testI64(%d)\n", thing)
	return thing, nil
}

// Prints 'testDouble("%f")' with thing as '%f'
// @param double thing - the double to print
// @return double - returns the double 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestDouble(ctx context.Context, thing float64) (r float64, err error) {
	fmt.Printf("testDouble(%f)\n", thing)
	return thing, nil
}

// Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
// @param []byte thing - the binary to print
// @return []byte - returns the binary 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestBinary(ctx context.Context, thing []byte) (r []byte, err error) {
	fmt.Printf("testBinary(%s)\n", hex.EncodeToString(thing))
	return thing, nil
}

// Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
// @param Xtruct thing - the Xtruct to print
// @return Xtruct - returns the Xtruct 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestStruct(ctx context.Context, thing *Xtruct) (r *Xtruct, err error) {
	fmt.Printf("testStruct({\"%s\", %d, %d, %d})\n", thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing)
	return thing, err
}

// Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct
// @param Xtruct2 thing - the Xtruct2 to print
// @return Xtruct2 - returns the Xtruct2 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestNest(ctx context.Context, nest *Xtruct2) (r *Xtruct2, err error) {
	thing := nest.StructThing
	fmt.Printf("testNest({%d, {\"%s\", %d, %d, %d}, %d})\n", nest.ByteThing, thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing, nest.I32Thing)
	return nest, nil
}

// Prints 'testMap("{%s")' where thing has been formatted into a string of  'key => value' pairs
//  separated by commas and new lines
// @param map thing - the map to print
// @return map - returns the map 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestMap(ctx context.Context, thing map[int32]int32) (r map[int32]int32, err error) {
	fmt.Printf("testMap({")
	first := true
	for k, v := range thing {
		if first {
			first = false
		} else {
			fmt.Printf(", ")
		}
		fmt.Printf("%d => %d", k, v)
	}
	fmt.Printf("})\n")
	return thing, nil
}

// Prints 'testStringMap("{%s}")' where thing has been formatted into a string of  'key => value' pairs
//  separated by commas and new lines
// @param map thing - the map to print
// @return map - returns the map 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestStringMap(ctx context.Context, thing map[string]string) (r map[string]string, err error) {
	fmt.Printf("testStringMap({")
	first := true
	for k, v := range thing {
		if first {
			first = false
		} else {
			fmt.Printf(", ")
		}
		fmt.Printf("%s => %s", k, v)
	}
	fmt.Printf("})\n")
	return thing, nil
}

// Prints 'testSet("{%s}")' where thing has been formatted into a string of  values
//  separated by commas and new lines
// @param set thing - the set to print
// @return set - returns the set 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestSet(ctx context.Context, thing []int32) (r []int32, err error) {
	fmt.Printf("testSet({")
	first := true
	for k := range thing {
		if first {
			first = false
		} else {
			fmt.Printf(", ")
		}
		fmt.Printf("%d", k)
	}
	fmt.Printf("})\n")
	return thing, nil
}

// Prints 'testList("{%s}")' where thing has been formatted into a string of  values
//  separated by commas and new lines
// @param list thing - the list to print
// @return list - returns the list 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestList(ctx context.Context, thing []int32) (r []int32, err error) {
	fmt.Printf("testList({")
	for i, v := range thing {
		if i != 0 {
			fmt.Printf(", ")
		}
		fmt.Printf("%d", v)
	}
	fmt.Printf("})\n")
	return thing, nil
}

// Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
// @param Numberz thing - the Numberz to print
// @return Numberz - returns the Numberz 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestEnum(ctx context.Context, thing Numberz) (r Numberz, err error) {
	fmt.Printf("testEnum(%d)\n", thing)
	return thing, nil
}

// Prints 'testTypedef("%d")' with thing as '%d'
// @param UserId thing - the UserId to print
// @return UserId - returns the UserId 'thing'
//
// Parameters:
//  - Thing
func (p *printingHandler) TestTypedef(ctx context.Context, thing UserId) (r UserId, err error) {
	fmt.Printf("testTypedef(%d)\n", thing)
	return thing, nil
}

// Prints 'testMapMap("%d")' with hello as '%d'
// @param i32 hello - the i32 to print
// @return map> - returns a dictionary with these values:
//   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
//
// Parameters:
//  - Hello
func (p *printingHandler) TestMapMap(ctx context.Context, hello int32) (r map[int32]map[int32]int32, err error) {
	fmt.Printf("testMapMap(%d)\n", hello)

	r = map[int32]map[int32]int32{
		-4: {-4: -4, -3: -3, -2: -2, -1: -1},
		4:  {4: 4, 3: 3, 2: 2, 1: 1},
	}
	return
}

// So you think you've got this all worked, out eh?
//
// Creates a the returned map with these values and prints it out:
//   { 1 => { 2 => argument,
//            3 => argument,
//          },
//     2 => { 6 => , },
//   }
// @return map> - a map with the above values
//
// Parameters:
//  - Argument
func (p *printingHandler) TestInsanity(ctx context.Context, argument *Insanity) (r map[UserId]map[Numberz]*Insanity, err error) {
	fmt.Printf("testInsanity()\n")
	r = make(map[UserId]map[Numberz]*Insanity)
	r[1] = map[Numberz]*Insanity{
		2: argument,
		3: argument,
	}
	r[2] = map[Numberz]*Insanity{
		6: NewInsanity(),
	}
	return
}

// Prints 'testMulti()'
// @param byte arg0 -
// @param i32 arg1 -
// @param i64 arg2 -
// @param map arg3 -
// @param Numberz arg4 -
// @param UserId arg5 -
// @return Xtruct - returns an Xtruct with StringThing = "Hello2, ByteThing = arg0, I32Thing = arg1
//    and I64Thing = arg2
//
// Parameters:
//  - Arg0
//  - Arg1
//  - Arg2
//  - Arg3
//  - Arg4
//  - Arg5
func (p *printingHandler) TestMulti(ctx context.Context, arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 Numberz, arg5 UserId) (r *Xtruct, err error) {
	fmt.Printf("testMulti()\n")
	r = NewXtruct()

	r.StringThing = "Hello2"
	r.ByteThing = arg0
	r.I32Thing = arg1
	r.I64Thing = arg2
	return
}

// Print 'testException(%s)' with arg as '%s'
// @param string arg - a string indication what type of exception to throw
// if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
// elsen if arg == "TException" throw TException
// else do not throw anything
//
// Parameters:
//  - Arg
func (p *printingHandler) TestException(ctx context.Context, arg string) (err error) {
	fmt.Printf("testException(%s)\n", arg)
	switch arg {
	case "Xception":
		e := NewXception()
		e.ErrorCode = 1001
		e.Message = arg
		return e
	case "TException":
		//lint:ignore ST1005 To be consistent with other language libraries.
		return errors.New("Just TException")
	}
	return
}

// Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
// @param string arg - a string indication what type of exception to throw
// if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception"
// elsen if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
// else do not throw anything
// @return Xtruct - an Xtruct with StringThing = arg1
//
// Parameters:
//  - Arg0
//  - Arg1
func (p *printingHandler) TestMultiException(ctx context.Context, arg0 string, arg1 string) (r *Xtruct, err error) {
	fmt.Printf("testMultiException(%s, %s)\n", arg0, arg1)
	switch arg0 {

	case "Xception":
		e := NewXception()
		e.ErrorCode = 1001
		e.Message = "This is an Xception"
		return nil, e
	case "Xception2":
		e := NewXception2()
		e.ErrorCode = 2002
		e.StructThing = NewXtruct()
		e.StructThing.StringThing = "This is an Xception2"
		return nil, e
	default:
		r = NewXtruct()
		r.StringThing = arg1
		return
	}
}

// Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
// sleep 'secondsToSleep'
// Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
// @param i32 secondsToSleep - the number of seconds to sleep
//
// Parameters:
//  - SecondsToSleep
func (p *printingHandler) TestOneway(ctx context.Context, secondsToSleep int32) (err error) {
	fmt.Printf("testOneway(%d): Sleeping...\n", secondsToSleep)
	time.Sleep(time.Second * time.Duration(secondsToSleep))
	fmt.Printf("testOneway(%d): done sleeping!\n", secondsToSleep)
	return
}
thrift-0.16.0/test/go/src/common/server.go000066400000000000000000000067441420101504100203750ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package common

import (
	"compress/zlib"
	"crypto/tls"
	"flag"
	"fmt"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/apache/thrift/test/go/src/gen/thrifttest"
)

var (
	debugServerProtocol bool
)

func init() {
	flag.BoolVar(&debugServerProtocol, "debug_server_protocol", false, "turn server protocol trace on")
}

func GetServerParams(
	host string,
	port int64,
	domain_socket string,
	transport string,
	protocol string,
	ssl bool,
	certPath string,
	handler thrifttest.ThriftTest,
) (thrift.TProcessor, thrift.TServerTransport, thrift.TTransportFactory, thrift.TProtocolFactory, error) {

	var err error
	hostPort := fmt.Sprintf("%s:%d", host, port)
	var cfg *thrift.TConfiguration = nil

	var protocolFactory thrift.TProtocolFactory
	switch protocol {
	case "compact":
		protocolFactory = thrift.NewTCompactProtocolFactoryConf(cfg)
	case "simplejson":
		protocolFactory = thrift.NewTSimpleJSONProtocolFactoryConf(cfg)
	case "json":
		protocolFactory = thrift.NewTJSONProtocolFactory()
	case "binary":
		protocolFactory = thrift.NewTBinaryProtocolFactoryConf(nil)
	case "header":
		protocolFactory = thrift.NewTHeaderProtocolFactoryConf(nil)
	default:
		return nil, nil, nil, nil, fmt.Errorf("invalid protocol specified %s", protocol)
	}
	if debugServerProtocol {
		protocolFactory = thrift.NewTDebugProtocolFactoryWithLogger(protocolFactory, "server:", thrift.StdLogger(nil))
	}

	var serverTransport thrift.TServerTransport
	if ssl {
		cfg := new(tls.Config)
		if cert, err := tls.LoadX509KeyPair(certPath+"/server.crt", certPath+"/server.key"); err != nil {
			return nil, nil, nil, nil, err
		} else {
			cfg.Certificates = append(cfg.Certificates, cert)
		}
		serverTransport, err = thrift.NewTSSLServerSocket(hostPort, cfg)
	} else {
		if domain_socket != "" {
			serverTransport, err = thrift.NewTServerSocket(domain_socket)
		} else {
			serverTransport, err = thrift.NewTServerSocket(hostPort)
		}
	}
	if err != nil {
		return nil, nil, nil, nil, err
	}

	var transportFactory thrift.TTransportFactory

	switch transport {
	case "http":
		// there is no such factory, and we don't need any
		transportFactory = nil
	case "framed":
		transportFactory = thrift.NewTTransportFactory()
		transportFactory = thrift.NewTFramedTransportFactoryConf(transportFactory, nil)
	case "buffered":
		transportFactory = thrift.NewTBufferedTransportFactory(8192)
	case "zlib":
		transportFactory = thrift.NewTZlibTransportFactory(zlib.BestCompression)
	case "":
		transportFactory = thrift.NewTTransportFactory()
	default:
		return nil, nil, nil, nil, fmt.Errorf("invalid transport specified %s", transport)
	}
	processor := thrifttest.NewThriftTestProcessor(handler)

	return processor, serverTransport, transportFactory, protocolFactory, nil
}
thrift-0.16.0/test/go/src/common/simple_handler.go000066400000000000000000000077651420101504100220610ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package common

import (
	"errors"
	"time"

	//lint:ignore ST1001 allow dot import here
	. "github.com/apache/thrift/test/go/src/gen/thrifttest"
)

var SimpleHandler = &simpleHandler{}

type simpleHandler struct{}

func (p *simpleHandler) TestVoid() (err error) {
	return nil
}

func (p *simpleHandler) TestString(thing string) (r string, err error) {
	return thing, nil
}

func (p *simpleHandler) TestBool(thing []byte) (r []byte, err error) {
	return thing, nil
}

func (p *simpleHandler) TestByte(thing int8) (r int8, err error) {
	return thing, nil
}

func (p *simpleHandler) TestI32(thing int32) (r int32, err error) {
	return thing, nil
}

func (p *simpleHandler) TestI64(thing int64) (r int64, err error) {
	return thing, nil
}

func (p *simpleHandler) TestDouble(thing float64) (r float64, err error) {
	return thing, nil
}

func (p *simpleHandler) TestBinary(thing []byte) (r []byte, err error) {
	return thing, nil
}

func (p *simpleHandler) TestStruct(thing *Xtruct) (r *Xtruct, err error) {
	return r, err
}

func (p *simpleHandler) TestNest(nest *Xtruct2) (r *Xtruct2, err error) {
	return nest, nil
}

func (p *simpleHandler) TestMap(thing map[int32]int32) (r map[int32]int32, err error) {
	return thing, nil
}

func (p *simpleHandler) TestStringMap(thing map[string]string) (r map[string]string, err error) {
	return thing, nil
}

func (p *simpleHandler) TestSet(thing []int32) (r []int32, err error) {
	return thing, nil
}

func (p *simpleHandler) TestList(thing []int32) (r []int32, err error) {
	return thing, nil
}

func (p *simpleHandler) TestEnum(thing Numberz) (r Numberz, err error) {
	return thing, nil
}

func (p *simpleHandler) TestTypedef(thing UserId) (r UserId, err error) {
	return thing, nil
}

func (p *simpleHandler) TestMapMap(hello int32) (r map[int32]map[int32]int32, err error) {

	r = map[int32]map[int32]int32{
		-4: {-4: -4, -3: -3, -2: -2, -1: -1},
		4:  {4: 4, 3: 3, 2: 2, 1: 1},
	}
	return
}

func (p *simpleHandler) TestInsanity(argument *Insanity) (r map[UserId]map[Numberz]*Insanity, err error) {
	//lint:ignore ST1005 To be consistent with other language libraries.
	return nil, errors.New("No Insanity")
}

func (p *simpleHandler) TestMulti(arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 Numberz, arg5 UserId) (r *Xtruct, err error) {
	r = NewXtruct()

	r.StringThing = "Hello2"
	r.ByteThing = arg0
	r.I32Thing = arg1
	r.I64Thing = arg2
	return
}

func (p *simpleHandler) TestException(arg string) (err error) {
	switch arg {
	case "Xception":
		e := NewXception()
		e.ErrorCode = 1001
		e.Message = arg
		return e
	case "TException":
		//lint:ignore ST1005 To be consistent with other language libraries.
		return errors.New("Just TException")
	}
	return
}

func (p *simpleHandler) TestMultiException(arg0 string, arg1 string) (r *Xtruct, err error) {
	switch arg0 {

	case "Xception":
		e := NewXception()
		e.ErrorCode = 1001
		e.Message = "This is an Xception"
		return nil, e
	case "Xception2":
		e := NewXception2()
		e.ErrorCode = 2002
		e.StructThing.StringThing = "This is an Xception2"
		return nil, e
	default:
		r = NewXtruct()
		r.StringThing = arg1
		return
	}
}

func (p *simpleHandler) TestOneway(secondsToSleep int32) (err error) {
	time.Sleep(time.Second * time.Duration(secondsToSleep))
	return
}
thrift-0.16.0/test/haxe/000077500000000000000000000000001420101504100147665ustar00rootroot00000000000000thrift-0.16.0/test/haxe/Makefile.am000066400000000000000000000045351420101504100170310ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

THRIFTCMD = $(THRIFT) --gen haxe -r
THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift

BIN_CPP = bin/Main-debug
BIN_PHP = bin/php/Main-debug.php
BIN_PHP_WEB = bin/php-web-server/Main-debug.php

gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST)
	$(THRIFTCMD) $(THRIFTTEST)

all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB)

$(BIN_CPP): \
		src/*.hx \
		../../lib/haxe/src/org/apache/thrift/**/*.hx \
		gen-haxe/thrift/test/ThriftTest.hx
	$(HAXE) --cwd .  cpp.hxml
	
#	$(HAXE) --cwd .  csharp
#	$(HAXE) --cwd .  flash
#	$(HAXE) --cwd .  java
#	$(HAXE) --cwd .  javascript
#	$(HAXE) --cwd .  neko
#	$(HAXE) --cwd .  python

$(BIN_PHP): \
		src/*.hx \
		../../lib/haxe/src/org/apache/thrift/**/*.hx \
		gen-haxe/thrift/test/ThriftTest.hx
	$(HAXE) --cwd .  php.hxml

$(BIN_PHP_WEB): \
		src/*.hx \
		../../lib/haxe/src/org/apache/thrift/**/*.hx \
		gen-haxe/thrift/test/ThriftTest.hx
	$(HAXE) --cwd .  php-web-server.hxml



clean-local:
	$(RM) -r gen-haxe bin

.NOTPARALLEL:

check: check_cpp \
	check_php \
	check_php_web 

check_cpp: $(BIN_CPP) 
	timeout 20 $(BIN_CPP) server &
	sleep 1
	$(BIN_CPP) client
	sleep 10

check_php: $(BIN_PHP) 
	timeout 20 php -f $(BIN_PHP) server &
	sleep 1
	php -f $(BIN_PHP) client
	sleep 10

check_php_web: $(BIN_PHP_WEB) $(BIN_CPP)
	timeout 20 php -S 127.0.0.1:9090 router.php &
	sleep 1
	$(BIN_CPP) client --transport http
	sleep 10


EXTRA_DIST = \
	src \
	cpp.hxml \
	csharp.hxml \
	flash.hxml \
	java.hxml \
	javascript.hxml \
	neko.hxml \
	php.hxml \
	python.hxml \
	router.php \
	project.hide \
	php-web-server.hxml \
	TestClientServer.hxproj \
	make_all.bat \
	make_all.sh
thrift-0.16.0/test/haxe/TestClientServer.hxproj000066400000000000000000000037711420101504100214770ustar00rootroot00000000000000

  
  
    
    
    
    
    
    
    
    
    
    
  
  
  
    
    
    
  
  
  
    
  
  
    
  
  
  
    
  
  
  
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
  thrift -r -gen haxe  ../ThriftTest.thrift
  
  
  
  
    
  
  
thrift-0.16.0/test/haxe/cpp.hxml000066400000000000000000000023621420101504100164450ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#CPP target
-cpp bin

#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
#-D HXCPP_M64

#Add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce fullthrift-0.16.0/test/haxe/csharp.hxml000066400000000000000000000022371420101504100171440ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#CSHARP target
-cs bin/Tutorial.exe

#Add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce fullthrift-0.16.0/test/haxe/flash.hxml000066400000000000000000000023421420101504100167560ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#Flash target
-swf bin/Tutorial.swf

#Add debug information
-debug

# we need some goodies from sys.net
# --macro allowPackage("sys")

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce fullthrift-0.16.0/test/haxe/java.hxml000066400000000000000000000022401420101504100165770ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src 

#this class wil be used as entry point for your app.
-main Main

#Java target
-java bin/Tutorial.jar

#Add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce fullthrift-0.16.0/test/haxe/javascript.hxml000066400000000000000000000027061420101504100200330ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#JavaScript target
-js bin/Tutorial.js

#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx 
#files directly embedded into the map file, this way you only have to 
#upload it, and it will be always in sync with the compiled .js even if 
#you modify your .hx files.
-D source-map-content

#Generate source map and add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce fullthrift-0.16.0/test/haxe/make_all.bat000066400000000000000000000035461420101504100172330ustar00rootroot00000000000000@echo off
rem /*
rem  * Licensed to the Apache Software Foundation (ASF) under one
rem  * or more contributor license agreements. See the NOTICE file
rem  * distributed with this work for additional information
rem  * regarding copyright ownership. The ASF licenses this file
rem  * to you under the Apache License, Version 2.0 (the
rem  * "License"); you may not use this file except in compliance
rem  * with the License. You may obtain a copy of the License at
rem  *
rem  *   http://www.apache.org/licenses/LICENSE-2.0
rem  *
rem  * Unless required by applicable law or agreed to in writing,
rem  * software distributed under the License is distributed on an
rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
rem  * KIND, either express or implied. See the License for the
rem  * specific language governing permissions and limitations
rem  * under the License.
rem  */

setlocal
if "%HOMEDRIVE%"=="" goto MISSINGVARS
if "%HOMEPATH%"=="" goto MISSINGVARS
if "%HAXEPATH%"=="" goto NOTINSTALLED

set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path%

rem # invoke Thrift comnpiler
thrift -r -gen haxe   ..\ThriftTest.thrift
if errorlevel 1 goto STOP

rem # invoke Haxe compiler for all targets
rd .buildtemp /S /Q
for %%a in (*.hxml) do (
	echo --------------------------
	echo Building %%a ...
	echo --------------------------
	haxe  --cwd .  %%a
	if not exist ".buildtemp" mkdir ".buildtemp"
	move bin ".buildtemp\%%a"
	if errorlevel 1 pause
)

rd bin /S /Q
rename .buildtemp bin

echo.
echo done.
pause
goto eof

:NOTINSTALLED
echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set.
pause
goto eof

:MISSINGVARS
echo FATAL: Unable to locate home folder.
echo.
echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder.
echo The current values are:
echo HOMEDRIVE=%HOMEDRIVE%
echo HOMEPATH=%HOMEPATH%
pause
goto eof

:STOP
pause
goto eof

:eof
thrift-0.16.0/test/haxe/make_all.sh000077500000000000000000000022461420101504100170760ustar00rootroot00000000000000#!/bin/sh
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

# invoke Thrift comnpiler
../../compiler/cpp/thrift -r -gen haxe  ../ThriftTest.thrift

# output folder
if [ ! -d bin ]; then
  mkdir  bin
fi

# invoke Haxe compiler
for target in *.hxml; do 
  echo --------------------------
  echo Building ${target} ...
  echo --------------------------
  if [ ! -d bin/${target} ]; then
    mkdir  bin/${target}
  fi
  haxe  --cwd .  ${target} 
done


#eof
thrift-0.16.0/test/haxe/neko.hxml000066400000000000000000000022351420101504100166160ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#neko target
-neko bin/Tutorial.n

#Add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce fullthrift-0.16.0/test/haxe/php-web-server.hxml000066400000000000000000000023271420101504100205320ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#PHP target
-php bin/php-web-server
-D php-front=Main-debug.php

#defines
-D phpwebserver


#Add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce full
thrift-0.16.0/test/haxe/php.hxml000066400000000000000000000022621420101504100164510ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#PHP target
-php bin/php
-D php-front=Main-debug.php


#Add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce full
thrift-0.16.0/test/haxe/project.hide000066400000000000000000000036471420101504100173010ustar00rootroot00000000000000{
     "type" : 0
    ,"target" : 4
    ,"name" : "Apache Thrift cross-platform test client/server"
    ,"main" : null
    ,"projectPackage" : ""
    ,"company" : "Apache Software Foundation (ASF)"
    ,"license" : "Apache License, Version 2.0"
    ,"url" : "http://www.apache.org/licenses/LICENSE-2.0"
    ,"targetData" : [
         {
             "pathToHxml" : "flash.hxml"
            ,"runActionType" : 1
            ,"runActionText" : "bin/Tutorial.swf"
        }
        ,{
             "pathToHxml" : "javascript.hxml"
            ,"runActionType" : 1
            ,"runActionText" : "bin\\index.html"
        }
        ,{
             "pathToHxml" : "neko.hxml"
            ,"runActionType" : 2
            ,"runActionText" : "neko bin/Tutorial.n"
        }
        ,{
             "pathToHxml" : "php.hxml"
        }
        ,{
             "pathToHxml" : "cpp.hxml"
            ,"runActionType" : 2
            ,"runActionText" : "bin/Main-debug.exe  client --protocol json"
        }
        ,{
             "pathToHxml" : "java.hxml"
        }
        ,{
             "pathToHxml" : "csharp.hxml"
        }
        ,{
             "pathToHxml" : "python.hxml"
            ,"runActionType" : 2
            ,"runActionText" : "python bin/Tutorial.py"
        }
    ]
    ,"files" : [
         {
             "path" : "src\\TestClient.hx"
            ,"useTabs" : true
            ,"indentSize" : 4
            ,"foldedRegions" : [

            ]
            ,"activeLine" : 188
        }
        ,{
             "path" : "src\\TestServer.hx"
            ,"useTabs" : true
            ,"indentSize" : 4
            ,"foldedRegions" : [

            ]
            ,"activeLine" : 88
        }
    ]
    ,"activeFile" : "src\\TestClient.hx"
    ,"openFLTarget" : null
    ,"openFLBuildMode" : "Debug"
    ,"runActionType" : null
    ,"runActionText" : null
    ,"buildActionCommand" : null
    ,"hiddenItems" : [

    ]
    ,"showHiddenItems" : false
}thrift-0.16.0/test/haxe/python.hxml000066400000000000000000000022421420101504100172010ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
 
#integrate files to classpath
-cp src
-cp gen-haxe
-cp ../../lib/haxe/src

#this class wil be used as entry point for your app.
-main Main

#Python target
-python bin/Tutorial.py

#Add debug information
-debug

#dead code elimination : remove unused code
#"-dce no" : do not remove unused code
#"-dce std" : remove unused code in the std lib (default)
#"-dce full" : remove all unused code
-dce fullthrift-0.16.0/test/haxe/router.php000066400000000000000000000017141420101504100170220ustar00rootroot00000000000000 0) {
            arg = args.shift();

            if ( (arg == "-h") || (arg == "--help")) {
                // -h [ --help ]               produce help message
                Sys.println( GetHelp());
                printHelpOnly = true;
                return;
            }
            else if (arg == "--port") {
                // --port arg (=9090)          Port number to listen
                arg = args.shift();
                var tmp = Std.parseInt(arg);
                if( tmp != null) {
                    port = tmp;
                } else {
                    throw "Invalid port number "+arg;
                }
            }
            else if (arg == "--domain-socket") {
                //   --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
                throw "domain sockets not supported yet";
            }
            else if (arg == "--pipe") {
                //   --pipe arg                  Windows Named Pipe (e.g. MyThriftPipe)
                throw "named pipes not supported yet";
            }
            else if (arg == "--protocol") {
                // --protocol arg (=binary)    protocol: binary, compact, json
                arg = args.shift();
                if( arg == "binary") {
                    protocol = binary;
                } else if( arg == "compact") {
                    protocol = compact;
                } else if( arg == "json") {
                    protocol = json;
                } else {
                    InvalidArg(arg);
                }
            }
            else if (arg == "--ssl") {
                // --ssl                       Encrypted Transport using SSL
                throw "SSL not supported yet";
            }
            else {
                //Server only options:
                if( server) {
                    ParseServerArgument( arg, args);
                } else {
                    ParseClientArgument( arg, args);
                }
            }
        }
    }


    private function ParseServerArgument( arg : String, args : Array) : Void {
        if (arg == "--transport") {
            //  --transport arg (=sockets)  Transport: buffered, framed, http, anonpipe
            arg = args.shift();
            if( arg == "buffered") {
                buffered = true;
            } else if( arg == "framed") {
                framed = true;
            } else if( arg == "http") {
                transport = http;
            } else if( arg == "anonpipe") {
                throw "Anon pipes transport not supported yet";
            } else {
                InvalidArg(arg);
            }
        }
        else if (arg == "--processor-events") {
            throw "Processor events not supported yet";
        }
        else if (arg == "--server-type") {
            //  --server-type arg (=simple) type of server,
            // one of "simple", "thread-pool", "threaded", "nonblocking"
            arg = args.shift();
            if( arg == "simple") {
                servertype = simple;
            } else if( arg == "thread-pool") {
                throw arg+" server not supported yet";
            } else if( arg == "threaded") {
                throw arg+" server not supported yet";
            } else if( arg == "nonblocking") {
                throw arg+" server not supported yet";
            } else {
                InvalidArg(arg);
            }
        }
        else if ((arg == "-n") || (arg == "--workers")) {
            //  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for
            //                              thread-pool server type
            arg = args.shift();
            var tmp = Std.parseInt(arg);
            if( tmp != null) {
                numThreads = tmp;
            } else{
                throw "Invalid number "+arg;
            }
        }
        else {
            InvalidArg(arg);
        }
    }


    private function ParseClientArgument( arg : String, args : Array) : Void {
        if (arg == "--host") {
            //  --host arg (=localhost)     Host to connect
            host = args.shift();
        }
        else if (arg == "--transport") {
            //  --transport arg (=sockets)  Transport: buffered, framed, http, evhttp
            arg = args.shift();
            if( arg == "buffered") {
                buffered = true;
            } else if( arg == "framed") {
                framed = true;
            } else if( arg == "http") {
                transport = http;
            } else if( arg == "evhttp") {
                throw "evhttp transport not supported yet";
            } else {
                InvalidArg(arg);
            }
        }
        else if (arg == "--anon-pipes") {
            //  --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)
            throw "Anon pipes transport not supported yet";
        }
        else if ((arg == "-n") || (arg == "--testloops")) {
            //  -n [ --testloops ] arg (=1) Number of Tests
            arg = args.shift();
            var tmp = Std.parseInt(arg);
            if( tmp != null) {
                numIterations = tmp;
            } else {
                throw "Invalid number "+arg;
            }
        }
        else if ((arg == "-t") || (arg == "--threads")) {
            //  -t [ --threads ] arg (=1)   Number of Test threads
            arg = args.shift();
            var tmp = Std.parseInt(arg);
            if( tmp != null) {
                numThreads = tmp;
            } else {
                throw "Invalid number "+arg;
            }
        }
        else if (arg == "--skip-speed-test") {
            //  --skip-speed-test              Skip the speed test
            skipSpeedTest = true;
        }
        else {
            InvalidArg(arg);
        }
    }


    #end


    private function InvalidArg( arg : String) : Void {
        throw 'Invalid argument $arg';
    }
}
thrift-0.16.0/test/haxe/src/Main.hx000066400000000000000000000044501420101504100170050ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */


package;

import org.apache.thrift.*;
import org.apache.thrift.protocol.*;
import org.apache.thrift.transport.*;
import org.apache.thrift.server.*;
import org.apache.thrift.meta_data.*;

import thrift.test.*;  // generated code

class Main
{
    static function main() {
        #if phpwebserver
        initPhpWebServer();
        //check method
        if(php.Web.getMethod() != 'POST') {
          Sys.println('http endpoint for thrift test server');
          return;
        }
        #end

        try {
            var args = new Arguments();

            if( args.printHelpOnly)
                return;

            if (args.server)
                TestServer.Execute(args);
            else
                TestClient.Execute(args);

            trace("Completed.");
        } catch (e : String) {
            trace(e);
        }
    }

    #if phpwebserver
    private static function initPhpWebServer()
    {
        //remap trace to error log
        haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos)
        {
          // handle trace
          var newValue : Dynamic;
          if (infos != null && infos.customParams!=null) {
            var extra:String = "";
            for( v in infos.customParams )
              extra += "," + v;
            newValue = v + extra;
          }
          else {
            newValue = v;
          }
          var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : '';
          Sys.stderr().writeString('${msg}${newValue}\n');
        }
    }
    #end

}
thrift-0.16.0/test/haxe/src/TestClient.hx000066400000000000000000001002231420101504100201720ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package;

import haxe.Int32;
import haxe.Int64;
import haxe.io.Bytes;
import haxe.Timer;
import haxe.ds.IntMap;
import haxe.ds.StringMap;
import haxe.ds.ObjectMap;

import org.apache.thrift.*;
import org.apache.thrift.helper.*;
import org.apache.thrift.protocol.*;
import org.apache.thrift.transport.*;
import org.apache.thrift.server.*;
import org.apache.thrift.meta_data.*;

#if cpp
import sys.thread.Thread;
#else
// no thread support (yet)
#end

import thrift.test.*;  // generated code


using StringTools;

class TestResults {
    private var successCnt : Int = 0;
    private var errorCnt : Int = 0;
    private var failedTests : String = "";
    private var print_direct : Bool = false;

    public static var EXITCODE_SUCCESS            = 0x00;  // no errors bits set
    //
    public static var EXITCODE_FAILBIT_BASETYPES  = 0x01;
    public static var EXITCODE_FAILBIT_STRUCTS    = 0x02;
    public static var EXITCODE_FAILBIT_CONTAINERS = 0x04;
    public static var EXITCODE_FAILBIT_EXCEPTIONS = 0x08;
    //
    public static var EXITCODE_ALL_FAILBITS       = 0x0F;
    //
    private var testsExecuted : Int = 0;
    private var testsFailed : Int = 0;
    private var currentTest : Int = 0;


    public function new(direct : Bool) {
        print_direct = direct;
    }

    public function StartTestGroup( groupBit : Int) : Void {
        currentTest = groupBit;
        testsExecuted |= groupBit;
    }

    public function Expect( expr : Bool, msg : String) : Void {
        if ( expr) {
            ++successCnt;
        } else {
            ++errorCnt;
            testsFailed |= currentTest;
            failedTests += "\n  " + msg;
            if( print_direct) {
                trace('FAIL: $msg');
            }
        }
    }

    public function CalculateExitCode() : Int {
        var notExecuted : Int = EXITCODE_ALL_FAILBITS & (~testsExecuted);
        return testsFailed | notExecuted;
    }

    public function PrintSummary() : Void {
        var total = successCnt + errorCnt;
        var sp = Math.round((1000 * successCnt) / total) / 10;
        var ep = Math.round((1000 * errorCnt) / total) / 10;

        trace('===========================');
        trace('Tests executed    $total');
        trace('Tests succeeded   $successCnt ($sp%)');
        trace('Tests failed      $errorCnt ($ep%)');
        if ( errorCnt > 0)
        {
            trace('===========================');
            trace('FAILED TESTS: $failedTests');
        }
        trace('===========================');
    }
}


class TestClient {

    public static function Execute(args : Arguments) :  Void
    {
        var exitCode = 0xFF;
        try
        {
            var difft = Timer.stamp();

            if ( args.numThreads > 1) {
                #if cpp
                exitCode = MultiThreadClient(args);
                #else
                trace('Threads not supported/implemented for this platform.');
                exitCode = SingleThreadClient(args);
                #end
            } else {
                exitCode = SingleThreadClient(args);
            }

            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
            trace('total test time: $difft seconds');
        }
        catch (e : TException)
        {
            trace('TException: $e');
            exitCode = 0xFF;
        }
        catch (e : Dynamic)
        {
            trace('Exception: $e');
            exitCode = 0xFF;
        }

        #if sys
        Sys.exit( exitCode);
        #end
    }


    public static function SingleThreadClient(args : Arguments) :  Int
    {
        var rslt = new TestResults(true);
        RunClient(args,rslt);
        rslt.PrintSummary();
        return rslt.CalculateExitCode();
    }


    #if cpp
    public static function MultiThreadClient(args : Arguments) :  Int
    {
        var threads = new List();
        for( test in 0 ... args.numThreads) {
            threads.add( StartThread( args));
        }
        var exitCode : Int = 0;
        for( thread in threads) {
            exitCode |= Thread.readMessage(true);
        }
        return exitCode;
    }
    #end

    #if cpp
    private static function StartThread(args : Arguments) : Thread {
        var thread = Thread.create(
            function() : Void {
                var rslt = new TestResults(false);
                var main : Thread = Thread.readMessage(true);
                try
                {
                    RunClient(args,rslt);
                }
                catch (e : TException)
                {
                    rslt.Expect( false, '$e');
                    trace('$e');
                }
                catch (e : Dynamic)
                {
                    rslt.Expect( false, '$e');
                    trace('$e');
                }
                main.sendMessage( rslt.CalculateExitCode());
            });

        thread.sendMessage(Thread.current());
        return thread;
    }
    #end


    public static function RunClient(args : Arguments, rslt : TestResults)
    {
        var transport : TTransport = null;
        switch (args.transport)
        {
            case socket:
                transport = new TSocket(args.host, args.port);
            case http:
                var uri = 'http://${args.host}:${args.port}';
                trace('- http client : ${uri}');
                transport = new THttpClient(uri);
            default:
                throw "Unhandled transport";
        }

        // optional: layered transport
        if ( args.framed) {
            trace("- framed transport");
            transport = new TFramedTransport(transport);
        }
        if ( args.buffered) {
            trace("- buffered transport");
            transport = new TBufferedTransport(transport);
        }

        // protocol
        var protocol : TProtocol = null;
        switch( args.protocol)
        {
        case binary:
            trace("- binary protocol");
            protocol = new TBinaryProtocol(transport);
        case json:
            trace("- json protocol");
            protocol = new TJSONProtocol(transport);
        case compact:
            trace("- compact protocol");
            protocol = new TCompactProtocol(transport);
        }

        // some quick and basic unit tests
        HaxeBasicsTest( args, rslt);
        ModuleUnitTests( args, rslt);

        // now run the test code
        trace('- ${args.numIterations} iterations');
        for( i in 0 ... args.numIterations) {
            ClientTest( transport, protocol, args, rslt);
        }
    }


    public static function HaxeBasicsTest( args : Arguments, rslt : TestResults) : Void
    {
        // We need to test a few basic things used in the ClientTest
        // Anything else beyond this scope should go into /lib/haxe/ instead
        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);

        var map32 = new IntMap();
        var map64 = new Int64Map();

        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #1");
        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #2");
        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #3");
        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #4");

        map32.set( 42, 815);
        map64.set( Int64.make(0,42), 815);
        map32.set( -517, 23);
        map64.set( Int64.neg(Int64.make(0,517)), 23);
        map32.set( 0, -123);
        map64.set( Int64.make(0,0), -123);

        //trace('map32 = $map32');
        //trace('map64 = $map64');

        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #10");
        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #11");
        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map Test #12");
        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #13");
        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #14");
        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #15");
        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map Test #16");
        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #Int64.make(-5,17)");
        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map Test #18");
        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #19");
        rslt.Expect( map32.remove( -517) == map64.remove( Int64.neg(Int64.make(0,517))), "Int64Map Test #20");
        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #21");
        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map Test #22");
        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #23");
        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #24");
        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #25");
        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map Test #26");
        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #27");
        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map Test #28");

        map32.set( 42, 1);
        map64.set( Int64.make(0,42), 1);
        map32.set( -517, -2);
        map64.set( Int64.neg(Int64.make(0,517)), -2);
        map32.set( 0, 3);
        map64.set( Int64.make(0,0), 3);

        var c32 = 0;
        var ksum32 = 0;
        for (key in map32.keys()) {
            ++c32;
            ksum32 += key;
        }
        var c64 = 0;
        var ksum64 = Int64.make(0,0);
        for (key in map64.keys()) {
            ++c64;
            ksum64 = Int64.add( ksum64, key);
        }
        rslt.Expect( c32 == c64, "Int64Map Test #30");
        rslt.Expect( '$ksum64' == '$ksum32', '$ksum64 == $ksum32   Test #31');

        //compare without spaces because differ in php and cpp
        var s32 = map32.toString().replace(' ', '');
        var s64 = map64.toString().replace(' ', '');
        rslt.Expect( s32 == s64, "Int64Map.toString(): " + ' ("$s32" == "$s64") Test #32');

        map32.remove( 42);
        map64.remove( Int64.make(0,42));
        map32.remove( -517);
        map64.remove( Int64.neg(Int64.make(0,517)));
        map32.remove( 0);
        map64.remove( Int64.make(0,0));

        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #90");
        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #91");
        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map Test #92");
        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #93");
        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #94");
        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #95");
        rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #96");
        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #97");
        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0, 0)), "Int64Map Test #98");
    }


    // core module unit tests
    public static function ModuleUnitTests( args : Arguments, rslt : TestResults) : Void {
        #if debug

        try {
            BitConverter.UnitTest();
            rslt.Expect( true, 'BitConverter.UnitTest  Test #100');
        }
        catch( e : Dynamic) {
            rslt.Expect( false, 'BitConverter.UnitTest: $e  Test #100');
        }

        try {
            ZigZag.UnitTest();
            rslt.Expect( true, 'ZigZag.UnitTest  Test #101');
        }
        catch( e : Dynamic) {
            rslt.Expect( false, 'ZigZag.UnitTest: $e  Test #101');
        }

        #end
    }


    public static function BytesToHex(data : Bytes) : String {
        var hex = "";
        for ( i in 0 ... data.length) {
            hex += StringTools.hex( data.get(i), 2);
        }
        return hex;
    }

    public static function PrepareTestData(randomDist : Bool) : Bytes    {
        var retval = Bytes.alloc(0x100);
        var initLen : Int = (retval.length > 0x100 ? 0x100 : retval.length);

        // linear distribution, unless random is requested
        if (!randomDist) {
            for (i in 0 ... initLen) {
                retval.set(i, i % 0x100);
            }
            return retval;
        }

        // random distribution
        for (i in 0 ... initLen) {
            retval.set(i, 0);
        }
        for (i in 1 ... initLen) {
            while( true) {
                var nextPos = Std.random(initLen);
                if (retval.get(nextPos) == 0) {
                    retval.set( nextPos, i % 0x100);
                    break;
                }
            }
        }
        return retval;
    }


    public static function ClientTest( transport : TTransport, protocol : TProtocol,
                                       args : Arguments, rslt : TestResults) : Void
    {
        var client = new ThriftTestImpl(protocol,protocol);
        try
        {
            if (!transport.isOpen())
            {
                transport.open();
            }
        }
        catch (e : TException)
        {
            rslt.Expect( false, 'unable to open transport: $e');
            return;
        }
        catch (e : Dynamic)
        {
            rslt.Expect( false, 'unable to open transport: $e');
            return;
        }

        var start = Date.now();

        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_EXCEPTIONS);

        // if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
        trace('testException("Xception")');
        try {
            client.testException("Xception");
            rslt.Expect( false, 'testException("Xception") should throw');
        }
        catch (e : Xception)
        {
            rslt.Expect( e.message == "Xception", 'testException("Xception")  -  e.message == "Xception"');
            rslt.Expect( e.errorCode == 1001, 'testException("Xception")  -  e.errorCode == 1001');
        }
        catch (e : TException)
        {
            rslt.Expect( false, 'testException("Xception")  -  ${e} : ${e.errorMsg}');
        }
        catch (e : Dynamic)
        {
            rslt.Expect( false, 'testException("Xception")  -  $e');
        }

        // if arg == "TException" throw TException
        trace('testException("TException")');
        try {
            client.testException("TException");
            rslt.Expect( false, 'testException("TException") should throw');
        }
        catch (e : TException)
        {
            rslt.Expect( true, 'testException("TException")  -  $e : ${e.errorMsg}');
        }
        catch (e : Dynamic)
        {
            rslt.Expect( false, 'testException("TException")  -  $e');
        }

        // reopen the transport, just in case the server closed his end
        if (transport.isOpen())
            transport.close();
        transport.open();

        // else do not throw anything
        trace('testException("bla")');
        try {
            client.testException("bla");
            rslt.Expect( true, 'testException("bla") should not throw');
        }
        catch (e : TException)
        {
            rslt.Expect( false, 'testException("bla")  -  ${e} : ${e.errorMsg}');
        }
        catch (e : Dynamic)
        {
            rslt.Expect( false, 'testException("bla")  -  $e');
        }

        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);

        trace('testVoid()');
        client.testVoid();
        trace(' = void');
        rslt.Expect(true,"testVoid()");  // bump counter

        trace('testBool(${true})');
        var b = client.testBool(true);
        trace(' = $b');
        rslt.Expect(b, '$b == "${true}"');
        trace('testBool(${false})');
        b = client.testBool(false);
        trace(' = $b');
        rslt.Expect( ! b, '$b == "${false}"');

        trace('testString("Test")');
        var s = client.testString("Test");
        trace(' = "$s"');
        rslt.Expect(s == "Test", '$s == "Test"');

        trace('testByte(1)');
        var i8 = client.testByte(1);
        trace(' = $i8');
        rslt.Expect(i8 == 1, '$i8 == 1');

        trace('testI32(-1)');
        var i32 = client.testI32(-1);
        trace(' = $i32');
        rslt.Expect(i32 == -1, '$i32 == -1');

        trace('testI64(-34359738368)');
        var i64 = client.testI64( Int64.make( 0xFFFFFFF8, 0x00000000)); // -34359738368
        trace(' = $i64');
        rslt.Expect( Int64.compare( i64, Int64.make( 0xFFFFFFF8, 0x00000000)) == 0,
                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0xFFFFFFF8, 0x00000000)));

        // edge case: the largest negative Int64 has no positive Int64 equivalent
        trace('testI64(-9223372036854775808)');
        i64 = client.testI64( Int64.make( 0x80000000, 0x00000000)); // -9223372036854775808
        trace(' = $i64');
        rslt.Expect( Int64.compare( i64, Int64.make( 0x80000000, 0x00000000)) == 0,
                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0x80000000, 0x00000000)));

        trace('testDouble(5.325098235)');
        var dub = client.testDouble(5.325098235);
        trace(' = $dub');
        rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');

        var binOut = PrepareTestData(true);
        trace('testBinary('+BytesToHex(binOut)+')');
        try {
            var binIn = client.testBinary(binOut);
            trace('testBinary() = '+BytesToHex(binIn));
            rslt.Expect( binIn.length == binOut.length, '${binIn.length} == ${binOut.length}');
            var len = ((binIn.length < binOut.length)  ?  binIn.length  : binOut.length);
            for (ofs in 0 ... len) {
                if (binIn.get(ofs) != binOut.get(ofs)) {
                    rslt.Expect( false, 'testBinary('+BytesToHex(binOut)+'): content mismatch at offset $ofs');
                }
            }
        }
        catch (e : TApplicationException) {
            trace('testBinary('+BytesToHex(binOut)+'): '+e.errorMsg);  // may not be supported by the server
        }


        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);

        trace('testStruct({"Zero", 1, -3, -5})');
        var o = new Xtruct();
        o.string_thing = "Zero";
        o.byte_thing = 1;
        o.i32_thing = -3;
        o.i64_thing = Int64.make(0,-5);
        var i = client.testStruct(o);
        trace(' = {"' + i.string_thing + '", ' + i.byte_thing +', '
                      + i.i32_thing +', '+ Int64.toStr(i.i64_thing) + '}');
        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");

        trace('testNest({1, {\"Zero\", 1, -3, -5}, 5})');
        var o2 = new Xtruct2();
        o2.byte_thing = 1;
        o2.struct_thing = o;
        o2.i32_thing = 5;
        var i2 = client.testNest(o2);
        i = i2.struct_thing;
        trace(" = {" + i2.byte_thing + ", {\"" + i.string_thing + "\", "
              + i.byte_thing + ", " + i.i32_thing + ", " + Int64.toStr(i.i64_thing) + "}, "
              + i2.i32_thing + "}");
        rslt.Expect( i2.byte_thing == o2.byte_thing, "i2.byte_thing == o2.byte_thing");
        rslt.Expect( i2.i32_thing == o2.i32_thing, "i2.i32_thing == o2.i32_thing");
        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
        rslt.Expect( i.i32_thing == o.i32_thing, "i.i32_thing == o.i32_thing");
        rslt.Expect( Int64.compare( i.i64_thing, o.i64_thing) == 0, "i.i64_thing == o.i64_thing");


        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);

        var mapout = new IntMap< haxe.Int32>();
        for ( j in 0 ... 5)
        {
            mapout.set(j, j - 10);
        }
        trace("testMap({");
        var first : Bool = true;
        for( key in mapout.keys())
        {
            if (first)
            {
                first = false;
            }
            else
            {
                trace(", ");
            }
            trace(key + " => " + mapout.get(key));
        }
        trace("})");

        var mapin = client.testMap(mapout);

        trace(" = {");
        first = true;
        for( key in mapin.keys())
        {
            if (first)
            {
                first = false;
            }
            else
            {
                trace(", ");
            }
            trace(key + " => " + mapin.get(key));
            rslt.Expect( mapin.get(key) == mapout.get(key), ' mapin.get($key) == mapout.get($key)');
        }
        trace("}");
        for( key in mapout.keys())
        {
            rslt.Expect(mapin.exists(key), 'mapin.exists($key)');
        }

        var listout = new List();
        for (j in -2 ... 3)
        {
            listout.add(j);
        }
        trace("testList({");
        first = true;
        for( j in listout)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                trace(", ");
            }
            trace(j);
        }
        trace("})");

        var listin = client.testList(listout);

        trace(" = {");
        first = true;
        for( j in listin)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                trace(", ");
            }
            trace(j);
        }
        trace("}");

        rslt.Expect(listin.length == listout.length, "listin.length == listout.length");
        var literout = listout.iterator();
        var literin = listin.iterator();
        while( literin.hasNext()) {
            rslt.Expect(literin.next() == literout.next(), "literin[i] == literout[i]");
        }

        //set
        var setout = new IntSet();
        for (j in -2 ... 3)
        {
            setout.add(j);
        }
        trace("testSet({");
        first = true;
        for( j in setout)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                trace(", ");
            }
            trace(j);
        }
        trace("})");

        var setin = client.testSet(setout);

        trace(" = {");
        first = true;
        for( j in setin)
        {
            if (first)
            {
                first = false;
            }
            else
            {
                trace(", ");
            }
            trace(j);
            rslt.Expect(setout.contains(j), 'setout.contains($j)');
        }
        trace("}");
        rslt.Expect(setin.size == setout.size, "setin.length == setout.length");


        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);

        trace("testEnum(ONE)");
        var ret = client.testEnum(Numberz.ONE);
        trace(" = " + ret);
        rslt.Expect(ret == Numberz.ONE, '$ret == Numberz.ONE');

        trace("testEnum(TWO)");
        ret = client.testEnum(Numberz.TWO);
        trace(" = " + ret);
        rslt.Expect(ret == Numberz.TWO, '$ret == Numberz.TWO');

        trace("testEnum(THREE)");
        ret = client.testEnum(Numberz.THREE);
        trace(" = " + ret);
        rslt.Expect(ret == Numberz.THREE, '$ret == Numberz.THREE');

        trace("testEnum(FIVE)");
        ret = client.testEnum(Numberz.FIVE);
        trace(" = " + ret);
        rslt.Expect(ret == Numberz.FIVE, '$ret == Numberz.FIVE');

        trace("testEnum(EIGHT)");
        ret = client.testEnum(Numberz.EIGHT);
        trace(" = " + ret);
        rslt.Expect(ret == Numberz.EIGHT, '$ret == Numberz.EIGHT');

        trace("testTypedef(309858235082523)");
        var uid = client.testTypedef( Int64.make( 0x119D0, 0x7E08671B));  // 309858235082523
        trace(" = " + uid);
        rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0,
                     Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B)));


        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);

        trace("testMapMap(1)");
        var mm = client.testMapMap(1);
        trace(" = {");
        for( key in mm.keys())
        {
            trace(key + " => {");
            var m2 = mm.get(key);
            for( k2 in m2.keys())
            {
                trace(k2 + " => " + m2.get(k2) + ", ");
            }
            trace("}, ");
        }
        trace("}");

        var pos = mm.get(4);
        var neg = mm.get(-4);
        rslt.Expect( (pos != null) && (neg != null), "(pos != null) && (neg != null)");
        for (i in 1 ... 5) {
            rslt.Expect( pos.get(i) == i, 'pos.get($i) == $i');
            rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i');
        }
        rslt.Expect( ! pos.exists(0), '!pos.exists(0)');
        rslt.Expect( ! neg.exists(-0), '!neg.exists(-0)');
        rslt.Expect( ! pos.exists(42), '!pos.exists(42)');
        rslt.Expect( ! neg.exists(-42), '!neg.exists(-42)');


        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);

        var insane = new Insanity();
        insane.userMap = new IntMap< Int64>();
        insane.userMap.set( Numberz.FIVE, Int64.make(0,5000));
        var truck = new Xtruct();
        truck.string_thing = "Truck";
        truck.byte_thing = 8;
        truck.i32_thing = 8;
        truck.i64_thing = Int64.make(0,8);
        insane.xtructs = new List();
        insane.xtructs.add(truck);
        trace("testInsanity()");
        var whoa = client.testInsanity(insane);
        trace(" = {");
        for( key in whoa.keys())
        {
            var val = whoa.get(key);
            trace(key + " => {");

            for( k2 in val.keys())
            {
                var v2 = val.get(k2);

                trace(k2 + " => {");
                var userMap = v2.userMap;

                trace("{");
                if (userMap != null)
                {
                    for( k3 in userMap.keys())
                    {
                        trace(k3 + " => " + userMap.get(k3) + ", ");
                    }
                }
                else
                {
                    trace("null");
                }
                trace("}, ");

                var xtructs = v2.xtructs;

                trace("{");
                if (xtructs != null)
                {
                    for( x in xtructs)
                    {
                        trace("{\"" + x.string_thing + "\", "
                              + x.byte_thing + ", " + x.i32_thing + ", "
                              + x.i32_thing + "}, ");
                    }
                }
                else
                {
                    trace("null");
                }
                trace("}");

                trace("}, ");
            }
            trace("}, ");
        }
        trace("}");


		/**
		* So you think you've got this all worked, out eh?
		*
		* Creates a the returned map with these values and prints it out:
		*   { 1 => { 2 => argument,
		*            3 => argument,
		*          },
		*     2 => { 6 => , },
		*   }
		* @return map> - a map with the above values
		*/
		
        var first_map = whoa.get(Int64.make(0,1));
        var second_map = whoa.get(Int64.make(0,2));
        rslt.Expect( (first_map != null) && (second_map != null), "(first_map != null) && (second_map != null)");
        if ((first_map != null) && (second_map != null))
        {
            var crazy2 = first_map.get(Numberz.TWO);
            var crazy3 = first_map.get(Numberz.THREE);
            var looney = second_map.get(Numberz.SIX);
            rslt.Expect( (crazy2 != null) && (crazy3 != null) && (looney != null),
                        "(crazy2 != null) && (crazy3 != null) && (looney != null)");

            var crz2iter = crazy2.xtructs.iterator();
            var crz3iter = crazy3.xtructs.iterator();
            rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
            var goodbye2 = crz2iter.next();
            var goodbye3 = crz3iter.next();
            rslt.Expect( ! (crz2iter.hasNext() || crz3iter.hasNext()), "! (crz2iter.hasNext() || crz3iter.hasNext())");

			rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy2.userMap[5] == insane.userMap[5]");
			rslt.Expect( truck.string_thing == goodbye2.string_thing, "truck.string_thing == goodbye2.string_thing");
			rslt.Expect( truck.byte_thing  == goodbye2.byte_thing, "truck.byte_thing  == goodbye2.byte_thing");
			rslt.Expect( truck.i32_thing  == goodbye2.i32_thing, "truck.i32_thing  == goodbye2.i32_thing");
			rslt.Expect( Int64.compare( truck.i64_thing, goodbye2.i64_thing) == 0, "truck.i64_thing  == goodbye2.i64_thing");

			rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy3.userMap[5] == insane.userMap[5]");
			rslt.Expect( truck.string_thing == goodbye3.string_thing, "truck.string_thing == goodbye3.string_thing");
			rslt.Expect( truck.byte_thing  == goodbye3.byte_thing, "truck.byte_thing  == goodbye3.byte_thing");
			rslt.Expect( truck.i32_thing  == goodbye3.i32_thing, "truck.i32_thing  == goodbye3.i32_thing");
			rslt.Expect( Int64.compare( truck.i64_thing, goodbye3.i64_thing) == 0, "truck.i64_thing  == goodbye3.i64_thing");
			
			rslt.Expect( ! looney.isSet(1), "! looney.isSet(1)");
			rslt.Expect( ! looney.isSet(2), "! looney.isSet(2)");
        }

        var arg0 = 1;
        var arg1 = 2;
        var arg2 = Int64.make( 0x7FFFFFFF,0xFFFFFFFF);
        var multiDict = new IntMap< String>();
        multiDict.set(1, "one");
        var arg4 = Numberz.FIVE;
        var arg5 = Int64.make(0,5000000);
        trace("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
        var multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
        trace(" = Xtruct(byte_thing:" + multiResponse.byte_thing + ",string_thing:" + multiResponse.string_thing
                    + ",i32_thing:" + multiResponse.i32_thing
                    + ",i64_thing:" + Int64.toStr(multiResponse.i64_thing) + ")");

        rslt.Expect( multiResponse.string_thing == "Hello2", 'multiResponse.String_thing == "Hello2"');
        rslt.Expect( multiResponse.byte_thing == arg0, 'multiResponse.Byte_thing == arg0');
        rslt.Expect( multiResponse.i32_thing == arg1, 'multiResponse.I32_thing == arg1');
        rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2');


        rslt.StartTestGroup( 0);

        trace("Test Oneway(1)");
        client.testOneway(1);

        if( ! args.skipSpeedTest) {
            trace("Test Calltime()");
            var difft = Timer.stamp();
            for ( k in 0 ... 1000) {
                client.testVoid();
            }
            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
            trace('$difft ms per testVoid() call');
        }
    }
}
thrift-0.16.0/test/haxe/src/TestMacro.hx000066400000000000000000000025661420101504100200300ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package ;

import haxe.macro.Context;
import haxe.macro.Expr;

/****
 * If you call the Thrift compiler this way (e.g. by changing the prebuild command)
 *
 *     thrift -r -gen haxe:buildmacro=TestMacro.handle()   ../ThriftTest.thrift
 *
 * the TestMacro.handle() function implemented below is called for each generated class
 * and interface. Use "thrift --help" to get more info about other available options.
 */
class TestMacro
{
  public static function handle( ) : Array< Field> {
    trace('TestMacro called for ' + Context.getLocalType());
    return Context.getBuildFields();
  }

}
thrift-0.16.0/test/haxe/src/TestServer.hx000066400000000000000000000101041420101504100202200ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package;

import org.apache.thrift.*;
import org.apache.thrift.protocol.*;
import org.apache.thrift.transport.*;
import org.apache.thrift.server.*;
import org.apache.thrift.meta_data.*;

import thrift.test.*;  // generated code


class TestServer
{
    public static function Execute(args : Arguments) :  Void
    {
        try
        {
            // Transport
            var transport : TServerTransport = null;
            switch( args.transport) {
            case socket:
                trace("- socket port "+args.port);
				#if (flash || html5 || js)
				throw "Transport not supported on this platform";
                #else
                transport = new TServerSocket( args.port);
				#end
            case http:
                trace("- http");
                #if phpwebserver
                transport = new TWrappingServerTransport( 
					new TStreamTransport(
						new TFileStream("php://input", Read),
						new TFileStream("php://output", Append),
						null
					)
				);
                #else
				throw "Transport not supported on this platform";
                //transport = new THttpServer( targetHost);
                #end
            default:
                throw "Unhandled transport";
            }

            // optional: layered transport
            var transfactory : TTransportFactory = null;
            if ( args.framed) {
                trace("- framed transport");
                transfactory = new TFramedTransportFactory();
            }
            if ( args.buffered) {
                trace("- buffered transport");
                transfactory = new TBufferedTransportFactory();
            }

            // protocol
            var protfactory : TProtocolFactory = null;
            switch( args.protocol)
            {
            case binary:
                trace("- binary protocol");
                protfactory = new TBinaryProtocolFactory();
            case json:
                trace("- json protocol");
                protfactory = new TJSONProtocolFactory();
            case compact:
                trace("- compact protocol");
                protfactory = new TCompactProtocolFactory();
            }


            // Processor
            var handler : ThriftTest_service = new TestServerHandler();
            var processor = new ThriftTestProcessor(handler);

            // Simple Server
            var server : TServer = null;
            switch( args.servertype)
            {
            case simple:
                var simpleServer = new TSimpleServer( processor, transport, transfactory, protfactory);
                #if phpwebserver
                simpleServer.runOnce = true;
                #end
                server = simpleServer;

            default:
                throw "Unhandled server type";
            }


            /*
            // Server event handler
            if( args.serverEvents) {
                var events = new TestServerEventHandler();
                server.setEventHandler(serverEvents);
                handler.server = serverEngine;
            }
            */

            // Run it
            server.Serve();
            trace("done.");

        }
        catch (x : TException)
        {
            trace('$x ${x.errorID} ${x.errorMsg}');
        }
        catch (x : Dynamic)
        {
            trace('$x');
        }
    }
}
thrift-0.16.0/test/haxe/src/TestServerEventHandler.hx000066400000000000000000000031171420101504100225260ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package;

import org.apache.thrift.*;
import org.apache.thrift.protocol.*;
import org.apache.thrift.transport.*;
import org.apache.thrift.server.*;
import org.apache.thrift.meta_data.*;

import thrift.test.*;  // generated code


class TestServerEventHandler : TServerEventHandler
{
    public int callCount = 0;
    public void preServe()
    {
        callCount++;
    }
    public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
    {
        callCount++;
        return null;
    }
    public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
    {
        callCount++;
    }
    public void processContext(Object serverContext, Thrift.Transport.TTransport transport)
    {
        callCount++;
    }
}

    thrift-0.16.0/test/haxe/src/TestServerHandler.hx000066400000000000000000000327041420101504100215300ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package;

import org.apache.thrift.*;
import org.apache.thrift.protocol.*;
import org.apache.thrift.transport.*;
import org.apache.thrift.server.*;
import org.apache.thrift.meta_data.*;
import org.apache.thrift.helper.*;

import haxe.Int32;
import haxe.Int64;
import haxe.io.Bytes;
import haxe.ds.IntMap;
import haxe.ds.StringMap;
import haxe.ds.ObjectMap;

import thrift.test.*;  // generated code


class TestServerHandler implements ThriftTest_service {

    public var server:TServer;

    public function new() {
    }

    /**
    * Prints "testVoid()" and returns nothing.
    */
    public function testVoid():Void
    {
        trace("testVoid()");
    }

    /**
    * Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false'
    * @param bool  thing - the bool data to print
    * @return bool  - returns the bool 'thing'
    *
    * @param thing
    */
    public function testBool(thing : Bool) : Bool
    {
        trace('testBool($thing)');
        return thing;
    }

    /**
    * Prints 'testString("%s")' with thing as '%s'
    * @param string thing - the string to print
    * @return string - returns the string 'thing'
    *
    * @param thing
    */
    public function testString(thing:String):String
    {
        trace("teststring(\"" + thing + "\")");
        return thing;
    }

    /**
    * Prints 'testByte("%d")' with thing as '%d'
    * @param byte thing - the byte to print
    * @return byte - returns the byte 'thing'
    *
    * @param thing
    */
    public function testByte(thing:haxe.Int32):haxe.Int32
    {
        trace("testByte(" + thing + ")");
        return thing;
    }

    /**
    * Prints 'testI32("%d")' with thing as '%d'
    * @param i32 thing - the i32 to print
    * @return i32 - returns the i32 'thing'
    *
    * @param thing
    */
    public function testI32(thing:haxe.Int32):haxe.Int32
    {
        trace("testI32(" + thing + ")");
        return thing;
    }

    /**
    * Prints 'testI64("%d")' with thing as '%d'
    * @param i64 thing - the i64 to print
    * @return i64 - returns the i64 'thing'
    *
    * @param thing
    */
    public function testI64(thing:haxe.Int64):haxe.Int64
    {
        trace("testI64(" + thing + ")");
        return thing;
    }

    /**
    * Prints 'testDouble("%f")' with thing as '%f'
    * @param double thing - the double to print
    * @return double - returns the double 'thing'
    *
    * @param thing
    */
    public function testDouble(thing:Float):Float
    {
        trace("testDouble(" + thing + ")");
        return thing;
    }

    /**
     * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
     * @param binary  thing - the binary data to print
     * @return binary  - returns the binary 'thing'
     *
     * @param thing
     */
    public function testBinary(thing : haxe.io.Bytes) : haxe.io.Bytes
    {
        var hex = "";
        for ( i in 0 ... thing.length) {
            hex += StringTools.hex( thing.get(i), 2);
        }
        trace('testBinary($hex)');
        return thing;
    }

    /**
    * Prints 'testStruct("{%s}")' where thing has been formatted
    *  into a string of comma separated values
    * @param Xtruct thing - the Xtruct to print
    * @return Xtruct - returns the Xtruct 'thing'
    *
    * @param thing
    */
    public function testStruct(thing:Xtruct):Xtruct
    {
        trace("testStruct({" +
                          "\"" + thing.string_thing + "\", " +
                          thing.byte_thing + ", " +
                          thing.i32_thing + ", " +
                          Int64.toStr(thing.i64_thing) + "})");
        return thing;
    }

    /**
    * Prints 'testNest("{%s}")' where thing has been formatted
    *  into a string of the nested struct
    * @param Xtruct2 thing - the Xtruct2 to print
    * @return Xtruct2 - returns the Xtruct2 'thing'
    *
    * @param thing
    */
    public function testNest(nest:Xtruct2):Xtruct2
    {
        var thing:Xtruct = nest.struct_thing;
        trace("testNest({" +
                          nest.byte_thing + ", {" +
                          "\"" + thing.string_thing + "\", " +
                          thing.byte_thing + ", " +
                          thing.i32_thing + ", " +
                          Int64.toStr(thing.i64_thing) + "}, " +
                          nest.i32_thing + "})");
        return nest;
    }

    /**
    * Prints 'testMap("{%s")' where thing has been formatted
    *  into a string of  'key => value' pairs
    *  separated by commas and new lines
    * @param map thing - the map to print
    * @return map - returns the map 'thing'
    *
    * @param thing
    */
    public function testMap(thing:IntMap):IntMap
    {
        trace("testMap({");
        var first:Bool = true;
        for (key in thing.keys()) {
            if (first) {
                first = false;
            } else {
                trace(", ");
            };
            trace(key + " => " + thing.get(key));
        };
        trace("})");
        return thing;
    }

    /**
    * Prints 'testStringMap("{%s}")' where thing has been formatted
    *  into a string of  'key => value' pairs
    *  separated by commas and new lines
    * @param map thing - the map to print
    * @return map - returns the map 'thing'
    *
    * @param thing
    */
    public function testStringMap(thing:StringMap):StringMap
    {
        trace("testStringMap({");
        var first:Bool = true;
        for (key in thing.keys()) {
            if (first) {
                first = false;
            } else {
                trace(", ");
            };
            trace(key + " => " + thing.get(key));
        };
        trace("})");
        return thing;
    }

    /**
    * Prints 'testSet("{%s}")' where thing has been formatted
    *  into a string of  values
    *  separated by commas and new lines
    * @param set thing - the set to print
    * @return set - returns the set 'thing'
    *
    * @param thing
    */
    public function testSet(thing:IntSet):IntSet
    {
        trace("testSet({");
        var first:Bool = true;
        for (elem in thing) {
            if (first) {
                first = false;
            } else {
                trace(", ");
            };
            trace(elem);
        };
        trace("})");
        return thing;
    }

    /**
    * Prints 'testList("{%s}")' where thing has been formatted
    *  into a string of  values
    *  separated by commas and new lines
    * @param list thing - the list to print
    * @return list - returns the list 'thing'
    *
    * @param thing
    */
    public function testList(thing:List):List
    {
        trace("testList({");
        var first:Bool = true;
        for (elem in thing) {
            if (first) {
                first = false;
            } else {
                trace(", ");
            };
            trace(elem);
        };
        trace("})");
        return thing;
    }

    /**
    * Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
    * @param Numberz thing - the Numberz to print
    * @return Numberz - returns the Numberz 'thing'
    *
    * @param thing
    */
    public function testEnum(thing:Int):Int
    {
        trace("testEnum(" + thing + ")");
        return thing;
    }

    /**
    * Prints 'testTypedef("%d")' with thing as '%d'
    * @param UserId thing - the UserId to print
    * @return UserId - returns the UserId 'thing'
    *
    * @param thing
    */
    public function testTypedef(thing:haxe.Int64):haxe.Int64
    {
        trace("testTypedef(" + thing + ")");
        return thing;
    }

    /**
    * Prints 'testMapMap("%d")' with hello as '%d'
    * @param i32 hello - the i32 to print
    * @return map> - returns a dictionary with these values:
    *   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, },
    *     4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
    *
    * @param hello
    */
    public function testMapMap(hello:haxe.Int32):IntMap>
    {
        trace("testMapMap(" + hello + ")");
        var mapmap = new IntMap>();
        var pos = new IntMap();
        var neg = new IntMap();
        for (i in 1 ... 5) {
            pos.set(i, i);
            neg.set(-i, -i);
        };
        mapmap.set(4, pos);
        mapmap.set(-4, neg);
        return mapmap;
    }

    /**
    * So you think you've got this all worked, out eh?
    *
    * Creates a the returned map with these values and prints it out:
    *   { 1 => { 2 => argument,
    *            3 => argument,
    *          },
    *     2 => { 6 => , },
    *   }
    * @return map> - a map with the above values
    *
    * @param argument
    */
    public function testInsanity(argument : Insanity) : Int64Map< IntMap< Insanity>>
    {
        trace("testInsanity()");

        var first_map = new IntMap< Insanity>();
        first_map.set(Numberz.TWO, argument);
        first_map.set(Numberz.THREE, argument);

        var second_map = new IntMap< Insanity>();
        var looney = new Insanity();
        second_map.set(Numberz.SIX, looney);

        var insane = new Int64Map< IntMap< Insanity>>();
        insane.set( Int64.make(0,1), first_map);
        insane.set( Int64.make(0,2), second_map);

        return insane;
    }

    /**
    * Prints 'testMulti()'
    * @param byte arg0 -
    * @param i32 arg1 -
    * @param i64 arg2 -
    * @param map arg3 -
    * @param Numberz arg4 -
    * @param UserId arg5 -
    * @return Xtruct - returns an Xtruct
    *    with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1
    *    and i64_thing = arg2
    *
    * @param arg0
    * @param arg1
    * @param arg2
    * @param arg3
    * @param arg4
    * @param arg5
    */
    public function testMulti(arg0:haxe.Int32, arg1:haxe.Int32, arg2:haxe.Int64,
        arg3:IntMap, arg4:Int, arg5:haxe.Int64):Xtruct
    {
        trace("testMulti()");
        var hello = new Xtruct();
        hello.string_thing = "Hello2";
        hello.byte_thing = arg0;
        hello.i32_thing = arg1;
        hello.i64_thing = arg2;
        return hello;
    }

    /**
    * Print 'testException(%s)' with arg as '%s'
    * @param string arg - a string indication what type of exception to throw
    * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
    * elsen if arg == "TException" throw TException
    * else do not throw anything
    *
    * @param arg
    */
    public function testException(arg:String):Void
    {
        trace("testException(" + arg + ")");
        if (arg == "Xception") {
            var x = new Xception();
            x.errorCode = 1001;
            x.message = arg;
            throw x;
        };
        if (arg == "TException") {
            throw new TException();
        };
        return;
    }

    /**
    * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
    * @param string arg - a string indication what type of exception to throw
    * if arg0 == "Xception"
    * throw Xception with errorCode = 1001 and message = "This is an Xception"
    * else if arg0 == "Xception2"
    * throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
    * else do not throw anything
    * @return Xtruct - an Xtruct with string_thing = arg1
    *
    * @param arg0
    * @param arg1
    */
    public function testMultiException(arg0:String, arg1:String):Xtruct
    {
        trace("testMultiException(" + arg0 + ", " + arg1 + ")");
        if (arg0 == "Xception") {
            var x = new Xception();
            x.errorCode = 1001;
            x.message = "This is an Xception";
            throw x;
        } else if (arg0 == "Xception2") {
            var x = new Xception2();
            x.errorCode = 2002;
            x.struct_thing = new Xtruct();
            x.struct_thing.string_thing = "This is an Xception2";
            throw x;
        };
        var result = new Xtruct();
        result.string_thing = arg1;
        return result;
    }

    /**
    * Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
    * sleep 'secondsToSleep'
    * Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
    * @param i32 secondsToSleep - the number of seconds to sleep
    *
    * @param secondsToSleep
    */
    public function testOneway(secondsToSleep:haxe.Int32):Void
    {
		#if sys
        trace("testOneway(" + secondsToSleep + "), sleeping...");
        Sys.sleep(secondsToSleep);
		#end
        trace("testOneway finished");
    }

    public function testStop():Void
    {
        if (server != null) {
            server.Stop();
        };
    }
}
thrift-0.16.0/test/index.html000066400000000000000000000032551420101504100160430ustar00rootroot00000000000000




Apache Thrift - integration test suite






Apache Thrift - integration test suite: Results

Server Client Protocol Transport Result (log) Expected

Test Information



browse raw log



thrift-0.16.0/test/keys/000077500000000000000000000000001420101504100150145ustar00rootroot00000000000000thrift-0.16.0/test/keys/CA.pem000066400000000000000000000111771420101504100160110ustar00rootroot00000000000000Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 16582080088954381212 (0xe61f61fc3b34239c)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, ST=Maryland, L=Forest Hill, O=The Apache Software Foundation, OU=Apache Thrift, CN=localhost/emailAddress=dev@thrift.apache.org
        Validity
            Not Before: Apr  7 18:58:00 2014 GMT
            Not After : Jun 24 18:58:00 2022 GMT
        Subject: C=US, ST=Maryland, L=Forest Hill, O=The Apache Software Foundation, OU=Apache Thrift, CN=localhost/emailAddress=dev@thrift.apache.org
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:aa:13:d4:c4:f7:01:17:a7:92:d1:b4:b4:15:0d:
                    21:90:19:5e:fc:fb:b6:6d:3f:f2:3f:65:a2:7a:43:
                    a6:46:95:fc:43:16:f6:63:14:5e:f7:b1:e3:61:02:
                    f9:4a:95:89:bf:8d:f9:48:1d:82:e7:34:e0:b2:48:
                    df:08:d9:7c:3a:2f:d3:1b:0b:e8:ef:c2:41:0a:7d:
                    0a:38:78:3a:31:66:73:99:8c:d1:79:27:5f:e5:66:
                    d0:5e:3a:8c:0c:92:18:73:04:c1:f5:45:db:37:e7:
                    5f:c7:8c:a3:60:e9:92:a0:d8:29:5d:77:48:fb:1d:
                    b0:ed:12:2c:4e:2e:02:db:3d:1a:41:71:a6:2b:2e:
                    b3:4c:6a:c7:f7:1d:a9:7e:c7:cf:db:f2:e7:b6:f3:
                    1f:77:1d:24:01:1a:66:66:30:85:30:02:29:c4:bb:
                    f7:cd:3f:89:4b:1a:5f:f4:91:96:fb:e9:39:f2:46:
                    96:12:3d:8a:23:b5:2e:82:9e:41:fe:40:b6:27:b1:
                    14:44:5c:96:30:0f:55:e4:bb:ad:8b:8a:99:17:c0:
                    29:11:4e:76:79:9d:4b:03:31:7e:85:3c:a8:23:40:
                    54:02:58:35:c6:fc:dd:3d:eb:e3:d1:51:00:02:86:
                    1a:d7:b0:9f:a0:17:73:6a:5a:d0:e6:b6:b8:55:40:
                    5e:27
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                28:F2:FD:30:CD:03:F1:DC:41:1E:C4:93:C6:97:13:CA:D4:FA:60:2A
            X509v3 Authority Key Identifier: 
                keyid:28:F2:FD:30:CD:03:F1:DC:41:1E:C4:93:C6:97:13:CA:D4:FA:60:2A

            X509v3 Basic Constraints: 
                CA:TRUE
    Signature Algorithm: sha1WithRSAEncryption
         46:15:18:89:b2:57:17:d1:a2:64:c1:9a:73:4f:04:94:76:07:
         1f:29:ba:6f:34:46:c2:36:d5:68:85:f4:15:4c:8e:1a:fe:83:
         79:53:ec:aa:0d:92:60:de:f3:9a:3a:e8:80:66:ac:87:70:89:
         59:f2:ac:9e:b0:28:11:37:7d:78:4e:5e:3f:25:0f:be:09:6f:
         26:2a:3d:66:79:38:28:e5:81:71:71:96:26:4f:db:ec:23:70:
         be:37:39:fc:e0:32:0d:80:8f:66:c7:ac:a4:b4:8b:77:40:e2:
         99:44:3a:73:c8:f9:14:cf:1b:32:27:c2:78:db:b0:da:8a:60:
         eb:8d:34:7e:7d:3c:03:d4:38:74:f7:17:9e:32:74:9a:e7:37:
         95:d4:71:03:c8:94:ea:09:7b:ad:2d:eb:70:43:f2:32:7e:63:
         01:84:8c:7e:9e:f0:79:7f:ae:e9:cf:f9:be:0e:fe:95:d2:bd:
         c8:a7:81:c2:71:d9:c3:50:31:89:6d:fa:ad:a2:ab:00:01:34:
         10:58:ef:96:5a:eb:30:07:a9:8e:84:36:ef:3d:3c:61:46:96:
         6a:e8:09:20:5a:ab:f8:4b:eb:b7:33:61:8e:af:9a:7d:16:b0:
         60:6a:f0:30:e5:b2:8e:e7:80:b4:a1:02:a9:37:fe:5f:b5:ae:
         65:e9:6b:34
-----BEGIN CERTIFICATE-----
MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
-----END CERTIFICATE-----
thrift-0.16.0/test/keys/README.md000077500000000000000000000060301420101504100162750ustar00rootroot00000000000000# Test Keys and Certificates
This folder is dedicated to test keys and certificates provided in multiple formats.
Primary use are unit test suites and cross language tests.

    test/keys

**The files in this directory must never be used on production systems.**

## SSL Keys and Certificates


## create certificates

we use the following parameters for test key and certificate creation

    C=US,
    ST=Maryland,
    L=Forest Hill,
    O=The Apache Software Foundation,
    OU=Apache Thrift,
    CN=localhost/emailAddress=dev@thrift.apache.org

### create self-signed server key and certificate

    openssl req -new -x509 -nodes  -days 3000 -out server.crt -keyout server.key
    openssl x509 -in server.crt -text > CA.pem
    cat server.crt server.key > server.pem

Export password is "thrift" without the quotes

    openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12

### create client key and certificate

    openssl genrsa -out client.key

create a signing request:

    openssl req -new -key client.key -out client.csr

sign the client certificate with the server.key

    openssl x509 -req -days 3000 -in client.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client.crt

export certificate in PKCS12 format (Export password is "thrift" without the quotes)

    openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

export certificate in PEM format for OpenSSL usage

    openssl pkcs12 -in client.p12 -out client.pem -clcerts

### create client key and certificate with altnames

copy openssl.cnf from your system e.g. /etc/ssl/openssl.cnf and append following to the end of [ v3_req ]

    subjectAltName=@alternate_names

    [ alternate_names ]
    IP.1=127.0.0.1
    IP.2=::1
    IP.3=::ffff:127.0.0.1

create a signing request:

    openssl req -new -key client_v3.key -out client_v3.csr -config openssl.cnf \
        -subj "/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost" -extensions v3_req

sign the client certificate with the server.key

    openssl x509 -req -days 3000 -in client_v3.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client_v3.crt -extensions v3_req -extfile openssl.cnf

## Java key and certificate import
Java Test Environment uses key and trust store password "thrift" without the quotes

list keystore entries

    keytool -list -storepass thrift -keystore ../../lib/java/test/.keystore

list truststore entries

    keytool -list -storepass thrift -keystore ../../lib/java/test/.truststore


delete an entry

    keytool -delete -storepass thrift -keystore ../../lib/java/test/.truststore -alias ssltest


import certificate into truststore

    keytool -importcert -storepass thrift -keystore ../../lib/java/test/.truststore -alias localhost --file server.crt

import key into keystore

    keytool -importkeystore -storepass thrift -keystore ../../lib/java/test/.keystore -srcstoretype pkcs12 -srckeystore server.p12

# Test SSL server and clients

    openssl s_client -connect localhost:9090
    openssl s_server -accept 9090 -www

thrift-0.16.0/test/keys/client.crt000066400000000000000000000025631420101504100170120ustar00rootroot00000000000000-----BEGIN CERTIFICATE-----
MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD
VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo
ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo
cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy
aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB
sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl
c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u
MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi
BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH
dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug
eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3
PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE
mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG
sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR
J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk
XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS
UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve
21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U
VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg==
-----END CERTIFICATE-----
thrift-0.16.0/test/keys/client.key000066400000000000000000000032131420101504100170030ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuX9smGDXs+7W3vzkki7CWHt7YTnV6hYW+7ExZ8d2xQBWoNo7
P307my/ymBYpeuQ8G20T3xP4zH8/DPkkezhByt7cDlp2bpx1pvQAq6B5UbU+8etb
NXhqF6DgpR9VKIzPwEbYrdDVUa9mSAxFr9DjT0UqNTpngP28Ebg9qzc83kXGcAvo
/vTJYISvZW7+1YmUI36qtEN9JoTaGqZPWKvFqg9rrUa+5FWwZDdN6gSYZ8Q228Wo
LqpBa5IJsblojjtG/rqmqhZbGqStyiU1zv6+HHqtb7B0U7ciWohPwgax1BWn5jiK
v90anZ6POoZkKt6Y8nW4QqMsyki6R2DbnKYcLQIDAQABAoIBAFotbCmXysUaczLs
VmIKgUhqn0xgxXGLU5kARzhga4jR5UtFTFBNHVEQOitdesTXd7ENkf98whMIOSqh
Y+7TJojtVqVTrQeQ4FFNhZXp6ZCjP/pzpF+WLl1WRF+Bn/Cao9ShnGzDfTC8yEh2
Ttpt/lNnGGHQBslakLc8jh5SODEFfbugX8SdTCwZYsesKNrXm1pS/5IEunPqaRi0
II0EcnqHEsgqSo+CljpW7uNxSryA2vSAVdlPej6+9FZjdIHLP5AEKYvk7e9D2CMV
1+grNe/QkQppShizPirbb93tHm86v5bkDFCM9yWrhcMcjvILMXETxIppMGPmacRu
jqtYcAECgYEA8VDzylTz4kS3+D3n3hTgb41XVYa7feUsh99GWRO1wXIFpHjCIRjA
9r/BXW9+Rx3puVPhS8hwLQ4BLdA7lFpV1C8ag0e3+vn6zVirnz1jtI+uHMvStzhO
d6i0nf+w4HYXo7mN6o9ZdHEfC8SFNbymhCoVKh2DILDwb4EX9RXNpy0CgYEAxMj4
+vrklJ/ilH+Ry1zst4zQYIwmm3QWjarDrypGucHgd4jg5v9A/CJIKUi8x0MjrcuN
wVb7R8XJyYzFQRXIUXR6GnLeeSnfpxzt4YlifCvXxnOi8w4fv7KeGBV5np1Egpo8
nWNyZFxdvQDuCopr3SUoS9JI8JPwVgA7T+7DaQECgYAGoavhbo45NJw9pS3fC4HT
bvXscsRqREcCAN/FCOagx0piZ7MmB7Ed1s0wjSTSPX8zyZtSYtK6Wj0sDiHlBMqB
Bz5aRzlGG2KKDBrDSIOZ7aziO7Oxt0lovmkgQmuQ743cwPemb4QM0CMDRsZGYMXO
sf1c5+y3lEU3Ozv2T0AUjQKBgBlnzOUyMQKTJcCAO8ViiNkln91nGrDlKug9TKg3
sAvZYO5tyINqHuyuTFywHFcpbtjIN9PnM+fPPD7+IpVFh6gkfoMdo2VHJ62+iWOd
xg475s6jLT1t7GFmYQzA8QOuUCMAYKT9Ks6UMjHthc3skwJpAqvPSUVuBBBGVWH7
dFUBAoGBAL67ARLujiAEVNHt5rajixB6ncl7/R+Z2uawI1JfmdnCZonAKVZYHuXU
/4j2+o4QhJIPLtWIoaxAkMigQtAkesqirn3Kk/c7kZRIoN549HTJuwZqYqNp7CB/
kVi5R335+M9z49i6qA0RZsJGSoSBk7PufG4RmLimcRbGwrY93sPD
-----END RSA PRIVATE KEY-----
thrift-0.16.0/test/keys/client.p12000066400000000000000000000050351420101504100166210ustar00rootroot000000000000000
0		*H
		0	0	*H
p0l0e	*H
0
*H
0)b8Xk쫷ݬiCd~kߡJ4#wl!1rs>jvUl's
du۞hYiC2su
Q,$a"gFqdLfWLw $8eU>틉
K\ـi>XTZ$L#^U7덄Ö37lAvz슌8#1,f6__=v83@Tڸx`ki4Pj\e[!͐^R@HњGea>ZP'~M 秝b'䩧l}MPxbͦAyBr秫cFm6q}R_L4Bp
198r$?4x%QWqέMAQ~a|bModѻa	%GEhV3GnhLQu2ߏ=Ê		/xz(qln>r{S1D0c,b
nil<`Hɧ=x'䃉.is1[fn9+j6C笳nmB;Ik04J6Du]½<'9 l!*	E~%S4ӵ7nDYP7ƵO-UueZ熵v%{х-OFBwa\%"n񬧆ua "V/y]+ɓLLvx[8/LA.c'ߗxϰ9g#E"spkS]Oh<Ap=E^$|P~hJDTC*pt"(ĉF&{Tk@A_p@(*-`#Uz
eOI&eGOdLEMwICe`"9>WbAu*ql8
`pJ~ͨQ.I!D@؜b|HYv|{h!"Lcuݓ.L^.܂399\am{Ąe xn0A	*H
2.0*0&*H

00
*H
0׮$7>ȅHX%bc[#P"fPA愱6v=>EԷף ÷e:@HYƱ}&mr7Ӌ#TiIp YJ~he:sն_6s_v*9Aó40+OI5õ)C-&//㝀R"<C
Ia׻)z h^_*tQxb6'jךPEApYXS~Y9tA"29Sr=l>&T?+Da<A;b"(G7yclw'F%W1MH	yc
(V?Wpf[kpq=$|BZ^<ƘOgȆ9.AZR?0k-P`,E{\(r
yiĵS-p-Zk;C+p3h])gA~',|p1%0#	*H
	19=[(	zbhD010!0	+s4w8D4E4thrift-0.16.0/test/keys/client.pem000066400000000000000000000072101420101504100167750ustar00rootroot00000000000000Bag Attributes
    localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD 
subject=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org
issuer=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org
-----BEGIN CERTIFICATE-----
MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD
VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo
ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo
cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy
aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB
sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl
c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u
MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi
BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH
dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug
eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3
PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE
mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG
sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR
J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk
XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS
UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve
21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U
VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg==
-----END CERTIFICATE-----
Bag Attributes
    localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD 
Key Attributes: 
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIRKol42bAS3ACAggA
MBQGCCqGSIb3DQMHBAjOulcyHMaWsQSCBMgbeXQ8pIYTENKm08UPeqxkCR2nLxSO
gtRmBxDYjqYv35y4K8KhybBvSBlIPgE5jEWxUCcc1Qvy5ydUQ/X9pmkU8dnmAmDC
o0zwd3lt2eNPy+4WliqFDVmHrLfYQFOoIrHjuzC0lI4C2iPOjxhfa1zFumedgwGS
Gx10X5uEVH5N64fW6B3BvzQM0rn2qr0ONuSRmteRtI8NsznfkgeJ9a4CIAF7E5Z2
JTGI12edNzzUJ1JhX47ZW4miQwCU5Lcy01UZqTFuUpmK7FUQegtLy3e5eDKq+bIg
ZYq6Hx7lu8hjT5kWZGKy71aYmHKEjI0f727cAbqDTG5uZBHBjwK/3p/znQVQXxBb
1+E9CiKeFdXj2ElptsnDyoTvrSwJ/Jqu1wkXBcH5Embg7aJMod1IOs6OQB1rPDvd
FFa84zbqRNWHSxxxYZxcB8YZinL6/dQJnisKu9LMQd3BBGsGWqH8Zz5tEvXjS5Kv
3g9JRa7QDkSF005x6U+q/678G2MG+W+NWqje3NZx9Psh/Ptm+h+q9n2GSvnibiK5
mEj9FIwGquGpbZUTK5aXHcKN657dKiICsEJeNar1iZznRmzrMbZJ+DxqJnTw+GAv
7Yb63/CNAtqSxiyNHGZ6NM2ZA9vAKY1HXn0RVC0y1+9FmNpSRwv3u/+ydSCnJonR
GEKjzOqM9Dn7qxd+h4UnnA7hXWxITageB6G6KmfiXRxhiWyqtOICdCneCwpq8UZ4
e0fm05NRW6M2mqGQHsMNSvTWddwz5b8wgw4eVsb+xQytxVdj9lpBuB9KyjQjxUgU
3oZx4KyWLoEWjkztPAiK3uv5GfotNIMdznRfON1+xm1M5swtn3y3Ru1f6STZC7Sp
qvbG7jPmpB5gLEUri+chw+aKUYbJ0b820Od4FLQYnwLWr46VelYmV44xuR06wgqP
1HchMSsHtS+ZlIiQQU9jhdyTrl86EQHH33dh+Sua8AhfewPRy2VFp3Zk34AUsWcX
EfIYGemhqUD3drG0SMVbFFNOaFGp9e0tQouYOC6/qFBv/SNgQz3mAEkciJYbUuUZ
V4YQPvtdvSrISV0e7bjFgdSEjG7P7F6CFrWTrjUlHZuWj6/rJ3+/1PHeJViyhsrJ
ZYFe14W/48PDxBRl4IEAmxcN1Eb2Ez9eCqv0HW77HviG6zIgnkPrhWHjFGUpxKk4
jLfuB2Tfq9F7ozv4L2QAn+F/yKt1Rm2Hh5J61eUJtAT60pajg+gJtjmpu5Pr4HDn
b6p3xmYwaL5Let1zCAbbMfdlDK14YjdOdM/BEKpXb9y4EIubX5AMY4ljXeG9gx+T
B1TuQVdJ0P5wIK/D10TQzAWDKam0kv3RXidlzRxpZ3snRnN/L3EVd58Rntj1Oc0y
FiIiSKRszDbPzKDxQE2sNgQcdO24JNLSa/sZYtq2gRgspl/YqIDo4ZYqi9x8F5OS
rdPU5D/H8LWR4vpJLL8DYrHh5qFG3BX2OJIhPRS+48pDYtrRjp7S/1ZU64OJAytk
99hDqSrn1j2a6yFE8L2Ptz+4UCF2OQXEc9Rqqeb8QEUuMSkNH4oQ+A2F6uzLpZi0
XH64R2niNC56LxV2i+3T5KREFLahyk8epLZlv8YdxYR4Sb7J/5yiooK3g9hmYVKO
zLc=
-----END ENCRYPTED PRIVATE KEY-----
thrift-0.16.0/test/keys/client_v3.crt000066400000000000000000000026641420101504100174240ustar00rootroot00000000000000-----BEGIN CERTIFICATE-----
MIIECDCCAvCgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVVMx
ETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jlc3QgSGlsbDEnMCUGA1UE
CgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMRYwFAYDVQQLDA1BcGFj
aGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAiBgkqhkiG9w0BCQEWFWRl
dkB0aHJpZnQuYXBhY2hlLm9yZzAeFw0xNjAyMjIxMTU4NDFaFw0yNDA1MTAxMTU4
NDFaMIGLMQswCQYDVQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcM
C0ZvcmVzdCBIaWxsMScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5k
YXRpb24xFjAUBgNVBAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9z
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALZ0wiQnXg5QMZZWugd/
O3woatyHuczJuFSmYiRGWLr3PugB+xtvjy0rTcE2MNx/bdsVxrapCKA+tMFORbEl
sF6jk0H+B7BzGoIwHr6N8GP1VOoA2esrhsNEz22aJI00VaFTFE8G/qgFcihyaVWH
ZsLa3MakOzFUmOBaV2tLBjCjaznqXw3eo3XwUI0BkgS9b9vqXjScmfWXDw5+1is4
bCgumG2zj9EpLypc9qCGNKFBO2YIg0XsIIJ8RprlianjL6P4MfC6GPOyW4NbZaLd
ESv/bumpVyuV/C/xqkPahvOwBuPE1loxZZPx6Qv368qn7SVNVZOLyX722spooA5G
6csCAwEAAaNPME0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwMwYDVR0RBCwwKocE
fwAAAYcQAAAAAAAAAAAAAAAAAAAAAYcQAAAAAAAAAAAAAP//fwAAATANBgkqhkiG
9w0BAQsFAAOCAQEABUEmeQkG/PS935jMHDrg/5zm4X2xrnFtmTwb0jdxfau6z/7h
AbxD5ioyY7FUTNCzI6SyMo9vJJtYCTCuEGr84JjT2R7232z60k4c1z/av01W3Orv
ExHfAZ8llhkfu0209T5TaIYCB7hDFj5KDbta8c6fEcwtmlHQWj3M31lSNsr4ZtWW
wObhK3sqTsOluHbhKNwlNEat48lbOQUC19I1Wi3dAS6n8lr0lEhfGKvqxu0ViASS
N1nLfdkREGp39bYpKg0n6EFw5bYyV4qE3cnIedFJp7NIOM/6xndJMh/c5l6N2uyZ
upArRQpw/3j+HkL1x9bs+900QK0GI6AxgjbopA==
-----END CERTIFICATE-----
thrift-0.16.0/test/keys/client_v3.key000066400000000000000000000032171420101504100174170ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAtnTCJCdeDlAxlla6B387fChq3Ie5zMm4VKZiJEZYuvc+6AH7
G2+PLStNwTYw3H9t2xXGtqkIoD60wU5FsSWwXqOTQf4HsHMagjAevo3wY/VU6gDZ
6yuGw0TPbZokjTRVoVMUTwb+qAVyKHJpVYdmwtrcxqQ7MVSY4FpXa0sGMKNrOepf
Dd6jdfBQjQGSBL1v2+peNJyZ9ZcPDn7WKzhsKC6YbbOP0SkvKlz2oIY0oUE7ZgiD
RewggnxGmuWJqeMvo/gx8LoY87Jbg1tlot0RK/9u6alXK5X8L/GqQ9qG87AG48TW
WjFlk/HpC/fryqftJU1Vk4vJfvbaymigDkbpywIDAQABAoIBAQCJpyUhaaIIYnBG
4D+RkGgsj8Gvh6ah3j53ft/kRj6DMC4BlB0C4fO/PEB5WI0cjfcvpwo4nOapHyX4
ATmLIMgjXn2m+CSM9wo01mEbmrKWd20M7n96cWhGwg9MvVJ+RdGk2K0lwj02PoWW
Blt576GTuNN/+j++Q/jiqsXxaLTO0/Wj+4b2gQh3n8I0u6bkolDLoERKIdrLGHH+
FU3sk8bpUhHmeiUTfwwci+juhtOY9e30AEst6xakCHbq1lRRyEYPtWL7oLds6yv0
UAKP7wS9Yl6dcekXSF1RZpB+fovTW+qPYn8aEuksaMz0wK96FCOjVNGYxMp+Xnvl
sKx63UZBAoGBAOCbCbJtO0HsgIauvCvGZ50aZ1vDvQReCwri4ioutEg4JCAXHEsX
+axz2J5j3UEQhGKr0EX9BG6YbxGW0Mmjf3QxeRB+0WLpMMY2SFt93oC2R1AX9l0I
h50O6tYv5SXm96pKxwRz01d84mCJgwn/G+cZ/EJj4rfZsNbQst6JQFvzAoGBAM/1
gLVQt5l+IK+6s68EnADI66i7cKe6sj3rFRTahZJxL2vY28J9EB2mF/XEgARSNJQV
X/H9zDrwKm9MX87/eCH2nEbc+5qSGpDPQm482C9DqsMitxCKD8bble1BlpjFb8hr
R0Q3v5q8u5uomLBds5eUBeRKMtu9tOMA9KRSDGjJAoGAF44K2Ux9T2+XFwjSMSEQ
krhHKKeBdijKrayXnWbif0Rr/XWPAQ0VoRFRIWNFu+IYkCSGpiBfy51u4IBZixv7
bNsXYDR8jwv3koH02qt7nzH+jpbEvoL7fewnkqjZNj1fsds/vebLvjwZnZguRukb
KwRdoTTKfQ92bUDb0VzBhCMCgYB7H+3ObDXoCQctRCsyilYbGNp+EkxG4oC5rD/V
EvRWmfDrt3+VjRpHk5lIB8mLxWgf7O/bhNqwYpWdQ+jN0++6nBo20oudHrff2PaJ
8jhE85lc42bjwfpJUKVZzaVuWicu0GVnfGJTKT8ikBWnBjNYoWlDmrK164H3jQ9L
YtC6EQKBgQCabFXXHx5cIJ2XOm4K/nTOG7ClvD80xapqyGroQd9E/cJUHHPp/wQ4
c1dMO5EViM7JRsKfxkl9vM5o9IM7swlYh4EMFSLJNjzgOY9XVkvQh0uGbiJOBO4f
inUuWn1YWUj/HFtrT+0No+cYvZVcMKrFAy3K/AwpTbfKCk6roullNA==
-----END RSA PRIVATE KEY-----
thrift-0.16.0/test/keys/server.crt000066400000000000000000000027611420101504100170420ustar00rootroot00000000000000-----BEGIN CERTIFICATE-----
MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
-----END CERTIFICATE-----
thrift-0.16.0/test/keys/server.key000066400000000000000000000032501420101504100170340ustar00rootroot00000000000000-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
rdPUV9/uQkdx8VrShxlD8A==
-----END PRIVATE KEY-----
thrift-0.16.0/test/keys/server.p12000066400000000000000000000051751420101504100166560ustar00rootroot000000000000000
y0
?	*H

0
,0
(0	*H
00	*H
0
*H
0}@SWP_磂Aq'ug#l)ؗ&jvZV+՗WW@D2\aK^N>Z_
6ˌЅn\v>!`'taʋ &IL%PF~lyp4kKKD4YnRs&ڌbV?7+&q7%Əh&lG)0ڔ*@;6Ҟ#HUfLsJ./8BtϩlqVWkLJyK]nUnA|+&XCHk+:'
06K~"KT#$n;|V&:TVr-~X9EgI?(͆QԡkR:z;=YXRam2xx7!~}ۆ]VGL̛;z<ҵ-/g.&@5vi,21F@b-_x2DbK!{CKHCك{#fQҍpw1Ԫ6A1VOGyȊɛ<4gm-%VP(ݡoΊ¥O'7ųUtWVwh!{gp.*6MN2XL) kA57!k}0g/0xOlT|'It0A	*H
2.0*0&*H

00
*H
0UW"
BA藒Dp.e^J|sObMPi\
0`hjwnBnHab3oEb5Ǟe,a6Es֣ɰ=12jH-_|NP3=o'_5FC~6Z~} ;zZ$Վ/Ų<ӛҁ90TZЃH2.0(ph#TDE)R}J0f&f{
'\v}nI1r߀ҧb.-{#hrj3SLE7
w)3R3:j͉ՕϾ$H.v{9)3>
.8H\`t 5[Cu"BiQ7b$Wo%=ʻͿu%5!-',II|9AxuI
1?*9AouʠXxliG{2
$CȹT3&y'._B6D߄i+&%_K0P_/Hobԛlb28˔fm'	$w5P߄PܤIOKZf)ȒB-3.QHY1%0#	*H
	1CO4O|[m010!0	+i$Ю,k:G ~
thrift-0.16.0/test/keys/server.pem000066400000000000000000000062311420101504100170270ustar00rootroot00000000000000-----BEGIN CERTIFICATE-----
MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
rdPUV9/uQkdx8VrShxlD8A==
-----END PRIVATE KEY-----
thrift-0.16.0/test/known_failures_Linux.json000066400000000000000000001223521420101504100211460ustar00rootroot00000000000000[
  "cl-c_glib_binary_buffered-ip",
  "cl-c_glib_binary_framed-ip",
  "cl-c_glib_multi-binary_buffered-ip",
  "cl-c_glib_multi-binary_framed-ip",
  "cl-c_glib_multi_buffered-ip",
  "cl-c_glib_multi_framed-ip",
  "cl-go_binary_buffered-ip",
  "cl-go_binary_framed-ip",
  "cl-netstd_binary_buffered-ip",
  "cl-netstd_binary_framed-ip",
  "cl-rb_binary-accel_buffered-ip",
  "cl-rb_binary-accel_framed-ip",
  "cl-rb_binary_buffered-ip",
  "cl-rb_binary_framed-ip",
  "cl-rs_binary_buffered-ip",
  "cl-rs_binary_framed-ip",
  "cl-rs_multi-binary_buffered-ip",
  "cl-rs_multi-binary_framed-ip",
  "cl-rs_multi_buffered-ip",
  "cl-rs_multi_framed-ip",
  "cpp-cpp_binary_websocket-domain",
  "cpp-cpp_binary_websocket-ip",
  "cpp-cpp_binary_websocket-ip-ssl",
  "cpp-cpp_compact_websocket-domain",
  "cpp-cpp_compact_websocket-ip",
  "cpp-cpp_compact_websocket-ip-ssl",
  "cpp-cpp_header_websocket-domain",
  "cpp-cpp_header_websocket-ip",
  "cpp-cpp_header_websocket-ip-ssl",
  "cpp-cpp_json_websocket-domain",
  "cpp-cpp_json_websocket-ip",
  "cpp-cpp_json_websocket-ip-ssl",
  "cpp-cpp_multi-binary_websocket-domain",
  "cpp-cpp_multi-binary_websocket-ip",
  "cpp-cpp_multi-binary_websocket-ip-ssl",
  "cpp-cpp_multic-compact_websocket-domain",
  "cpp-cpp_multic-compact_websocket-ip",
  "cpp-cpp_multic-compact_websocket-ip-ssl",
  "cpp-cpp_multic_websocket-domain",
  "cpp-cpp_multic_websocket-ip",
  "cpp-cpp_multic_websocket-ip-ssl",
  "cpp-cpp_multih-header_websocket-domain",
  "cpp-cpp_multih-header_websocket-ip",
  "cpp-cpp_multih-header_websocket-ip-ssl",
  "cpp-cpp_multih_websocket-domain",
  "cpp-cpp_multih_websocket-ip",
  "cpp-cpp_multih_websocket-ip-ssl",
  "cpp-cpp_multij-json_websocket-domain",
  "cpp-cpp_multij-json_websocket-ip",
  "cpp-cpp_multij-json_websocket-ip-ssl",
  "cpp-cpp_multij_websocket-domain",
  "cpp-cpp_multij_websocket-ip",
  "cpp-cpp_multij_websocket-ip-ssl",
  "cpp-cpp_multi_websocket-domain",
  "cpp-cpp_multi_websocket-ip",
  "cpp-cpp_multi_websocket-ip-ssl",
  "cpp-dart_binary_http-ip",
  "cpp-dart_compact_http-ip",
  "cpp-dart_json_http-ip",
  "cpp-dart_multi-binary_http-ip",
  "cpp-dart_multic-compact_http-ip",
  "cpp-dart_multij-json_http-ip",
  "cpp-go_binary_http-ip",
  "cpp-go_binary_http-ip-ssl",
  "cpp-go_compact_http-ip",
  "cpp-go_compact_http-ip-ssl",
  "cpp-go_header_http-ip",
  "cpp-go_header_http-ip-ssl",
  "cpp-go_json_http-ip",
  "cpp-go_json_http-ip-ssl",
  "cpp-go_multi-binary_http-ip",
  "cpp-go_multi-binary_http-ip-ssl",
  "cpp-go_multic-compact_http-ip",
  "cpp-go_multic-compact_http-ip-ssl",
  "cpp-go_multih-header_http-ip",
  "cpp-go_multih-header_http-ip-ssl",
  "cpp-go_multij-json_http-ip",
  "cpp-go_multij-json_http-ip-ssl",
  "cpp-java_binary_http-ip",
  "cpp-java_binary_http-ip-ssl",
  "cpp-java_compact_http-ip",
  "cpp-java_compact_http-ip-ssl",
  "cpp-java_json_http-ip",
  "cpp-java_json_http-ip-ssl",
  "cpp-java_multi-binary_http-ip",
  "cpp-java_multi-binary_http-ip-ssl",
  "cpp-java_multic-compact_http-ip",
  "cpp-java_multic-compact_http-ip-ssl",
  "cpp-java_multic_http-ip",
  "cpp-java_multic_http-ip-ssl",
  "cpp-java_multij-json_http-ip",
  "cpp-java_multij-json_http-ip-ssl",
  "cpp-java_multij_http-ip",
  "cpp-java_multij_http-ip-ssl",
  "cpp-java_multi_http-ip",
  "cpp-java_multi_http-ip-ssl",
  "cpp-netstd_binary_buffered-ip",
  "cpp-netstd_binary_buffered-ip-ssl",
  "cpp-netstd_binary_framed-ip",
  "cpp-netstd_binary_framed-ip-ssl",
  "cpp-netstd_compact_buffered-ip",
  "cpp-netstd_compact_buffered-ip-ssl",
  "cpp-netstd_compact_framed-ip",
  "cpp-netstd_compact_framed-ip-ssl",
  "cpp-netstd_json_buffered-ip",
  "cpp-netstd_json_buffered-ip-ssl",
  "cpp-netstd_json_framed-ip",
  "cpp-netstd_json_framed-ip-ssl",
  "cpp-netstd_multi-binary_buffered-ip",
  "cpp-netstd_multi-binary_buffered-ip-ssl",
  "cpp-netstd_multi-binary_framed-ip",
  "cpp-netstd_multi-binary_framed-ip-ssl",
  "cpp-netstd_multic-compact_buffered-ip",
  "cpp-netstd_multic-compact_buffered-ip-ssl",
  "cpp-netstd_multic-compact_framed-ip",
  "cpp-netstd_multic-compact_framed-ip-ssl",
  "cpp-netstd_multij-json_buffered-ip",
  "cpp-netstd_multij-json_buffered-ip-ssl",
  "cpp-netstd_multij-json_framed-ip",
  "cpp-netstd_multij-json_framed-ip-ssl",
  "cpp-nodejs_binary_http-domain",
  "cpp-nodejs_binary_http-ip",
  "cpp-nodejs_binary_http-ip-ssl",
  "cpp-nodejs_binary_websocket-domain",
  "cpp-nodejs_compact_http-domain",
  "cpp-nodejs_compact_http-ip",
  "cpp-nodejs_compact_http-ip-ssl",
  "cpp-nodejs_compact_websocket-domain",
  "cpp-nodejs_header_http-domain",
  "cpp-nodejs_header_http-ip",
  "cpp-nodejs_header_http-ip-ssl",
  "cpp-nodejs_header_websocket-domain",
  "cpp-nodejs_header_websocket-ip",
  "cpp-nodejs_header_websocket-ip-ssl",
  "cpp-nodejs_json_http-domain",
  "cpp-nodejs_json_http-ip",
  "cpp-nodejs_json_http-ip-ssl",
  "cpp-nodejs_json_websocket-domain",
  "cpp-nodejs_multi-binary_http-domain",
  "cpp-nodejs_multi-binary_http-ip",
  "cpp-nodejs_multi-binary_http-ip-ssl",
  "cpp-nodejs_multi-binary_websocket-domain",
  "cpp-nodejs_multic-compact_http-domain",
  "cpp-nodejs_multic-compact_http-ip",
  "cpp-nodejs_multic-compact_http-ip-ssl",
  "cpp-nodejs_multic-compact_websocket-domain",
  "cpp-nodejs_multih-header_http-domain",
  "cpp-nodejs_multih-header_http-ip",
  "cpp-nodejs_multih-header_http-ip-ssl",
  "cpp-nodejs_multih-header_websocket-domain",
  "cpp-nodejs_multih-header_websocket-ip",
  "cpp-nodejs_multih-header_websocket-ip-ssl",
  "cpp-nodejs_multij-json_http-domain",
  "cpp-nodejs_multij-json_http-ip",
  "cpp-nodejs_multij-json_http-ip-ssl",
  "cpp-nodejs_multij-json_websocket-domain",
  "cpp-php_binary-accel_buffered-ip",
  "cpp-php_binary-accel_framed-ip",
  "cpp-php_json_buffered-ip",
  "cpp-php_json_framed-ip",
  "cpp-php_multi-accel_buffered-ip",
  "cpp-php_multi-accel_framed-ip",
  "cpp-php_multij-json_buffered-ip",
  "cpp-php_multij-json_framed-ip",
  "cpp-py3_binary-accel_http-domain",
  "cpp-py3_binary-accel_http-ip",
  "cpp-py3_binary-accel_http-ip-ssl",
  "cpp-py3_binary_http-domain",
  "cpp-py3_binary_http-ip",
  "cpp-py3_binary_http-ip-ssl",
  "cpp-py3_compact-accelc_http-domain",
  "cpp-py3_compact-accelc_http-ip",
  "cpp-py3_compact-accelc_http-ip-ssl",
  "cpp-py3_compact_http-domain",
  "cpp-py3_compact_http-ip",
  "cpp-py3_compact_http-ip-ssl",
  "cpp-py3_header_http-domain",
  "cpp-py3_header_http-ip",
  "cpp-py3_header_http-ip-ssl",
  "cpp-py3_json_http-domain",
  "cpp-py3_json_http-ip",
  "cpp-py3_json_http-ip-ssl",
  "cpp-py3_multi-accel_http-domain",
  "cpp-py3_multi-accel_http-ip",
  "cpp-py3_multi-accel_http-ip-ssl",
  "cpp-py3_multi-binary_http-domain",
  "cpp-py3_multi-binary_http-ip",
  "cpp-py3_multi-binary_http-ip-ssl",
  "cpp-py3_multi-multia_http-domain",
  "cpp-py3_multi-multia_http-ip",
  "cpp-py3_multi-multia_http-ip-ssl",
  "cpp-py3_multic-accelc_http-domain",
  "cpp-py3_multic-accelc_http-ip",
  "cpp-py3_multic-accelc_http-ip-ssl",
  "cpp-py3_multic-compact_http-domain",
  "cpp-py3_multic-compact_http-ip",
  "cpp-py3_multic-compact_http-ip-ssl",
  "cpp-py3_multic-multiac_http-domain",
  "cpp-py3_multic-multiac_http-ip",
  "cpp-py3_multic-multiac_http-ip-ssl",
  "cpp-py3_multic_http-domain",
  "cpp-py3_multic_http-ip",
  "cpp-py3_multic_http-ip-ssl",
  "cpp-py3_multih-header_http-domain",
  "cpp-py3_multih-header_http-ip",
  "cpp-py3_multih-header_http-ip-ssl",
  "cpp-py3_multih_http-domain",
  "cpp-py3_multih_http-ip",
  "cpp-py3_multih_http-ip-ssl",
  "cpp-py3_multij-json_http-domain",
  "cpp-py3_multij-json_http-ip",
  "cpp-py3_multij-json_http-ip-ssl",
  "cpp-py3_multij_http-domain",
  "cpp-py3_multij_http-ip",
  "cpp-py3_multij_http-ip-ssl",
  "cpp-py3_multi_http-domain",
  "cpp-py3_multi_http-ip",
  "cpp-py3_multi_http-ip-ssl",
  "cpp-py_binary-accel_http-domain",
  "cpp-py_binary-accel_http-ip",
  "cpp-py_binary-accel_http-ip-ssl",
  "cpp-py_binary_http-domain",
  "cpp-py_binary_http-ip",
  "cpp-py_binary_http-ip-ssl",
  "cpp-py_compact-accelc_http-domain",
  "cpp-py_compact-accelc_http-ip",
  "cpp-py_compact-accelc_http-ip-ssl",
  "cpp-py_compact_http-domain",
  "cpp-py_compact_http-ip",
  "cpp-py_compact_http-ip-ssl",
  "cpp-py_header_http-domain",
  "cpp-py_header_http-ip",
  "cpp-py_header_http-ip-ssl",
  "cpp-py_json_http-domain",
  "cpp-py_json_http-ip",
  "cpp-py_json_http-ip-ssl",
  "cpp-py_multi-accel_http-domain",
  "cpp-py_multi-accel_http-ip",
  "cpp-py_multi-accel_http-ip-ssl",
  "cpp-py_multi-binary_http-domain",
  "cpp-py_multi-binary_http-ip",
  "cpp-py_multi-binary_http-ip-ssl",
  "cpp-py_multi-multia_http-domain",
  "cpp-py_multi-multia_http-ip",
  "cpp-py_multi-multia_http-ip-ssl",
  "cpp-py_multic-accelc_http-domain",
  "cpp-py_multic-accelc_http-ip",
  "cpp-py_multic-accelc_http-ip-ssl",
  "cpp-py_multic-compact_http-domain",
  "cpp-py_multic-compact_http-ip",
  "cpp-py_multic-compact_http-ip-ssl",
  "cpp-py_multic-multiac_http-domain",
  "cpp-py_multic-multiac_http-ip",
  "cpp-py_multic-multiac_http-ip-ssl",
  "cpp-py_multic_http-domain",
  "cpp-py_multic_http-ip",
  "cpp-py_multic_http-ip-ssl",
  "cpp-py_multih-header_http-domain",
  "cpp-py_multih-header_http-ip",
  "cpp-py_multih-header_http-ip-ssl",
  "cpp-py_multih_http-domain",
  "cpp-py_multih_http-ip",
  "cpp-py_multih_http-ip-ssl",
  "cpp-py_multij-json_http-domain",
  "cpp-py_multij-json_http-ip",
  "cpp-py_multij-json_http-ip-ssl",
  "cpp-py_multij_http-domain",
  "cpp-py_multij_http-ip",
  "cpp-py_multij_http-ip-ssl",
  "cpp-py_multi_http-domain",
  "cpp-py_multi_http-ip",
  "cpp-py_multi_http-ip-ssl",
  "c_glib-netstd_binary_buffered-ip",
  "c_glib-netstd_binary_framed-ip",
  "c_glib-netstd_compact_buffered-ip",
  "c_glib-netstd_compact_framed-ip",
  "c_glib-netstd_multi-binary_buffered-ip",
  "c_glib-netstd_multi-binary_framed-ip",
  "c_glib-netstd_multic-compact_buffered-ip",
  "c_glib-netstd_multic-compact_framed-ip",
  "d-cl_binary_buffered-ip",
  "d-cl_binary_framed-ip",
  "d-cpp_binary_buffered-ip",
  "d-cpp_binary_buffered-ip-ssl",
  "d-cpp_binary_framed-ip",
  "d-cpp_binary_framed-ip-ssl",
  "d-cpp_binary_http-ip",
  "d-cpp_binary_http-ip-ssl",
  "d-cpp_binary_zlib-ip",
  "d-cpp_binary_zlib-ip-ssl",
  "d-cpp_compact_buffered-ip",
  "d-cpp_compact_buffered-ip-ssl",
  "d-cpp_compact_framed-ip",
  "d-cpp_compact_framed-ip-ssl",
  "d-cpp_compact_http-ip",
  "d-cpp_compact_http-ip-ssl",
  "d-cpp_compact_zlib-ip",
  "d-cpp_compact_zlib-ip-ssl",
  "d-cpp_json_buffered-ip",
  "d-cpp_json_buffered-ip-ssl",
  "d-cpp_json_framed-ip",
  "d-cpp_json_framed-ip-ssl",
  "d-cpp_json_http-ip",
  "d-cpp_json_http-ip-ssl",
  "d-cpp_json_zlib-ip",
  "d-cpp_json_zlib-ip-ssl",
  "d-dart_binary_http-ip",
  "d-dart_compact_http-ip",
  "d-dart_json_http-ip",
  "d-d_binary_http-ip",
  "d-d_compact_http-ip",
  "d-d_json_http-ip",
  "d-go_binary_http-ip",
  "d-go_binary_http-ip-ssl",
  "d-go_compact_http-ip",
  "d-go_compact_http-ip-ssl",
  "d-go_json_http-ip",
  "d-go_json_http-ip-ssl",
  "d-java_binary_http-ip",
  "d-java_binary_http-ip-ssl",
  "d-java_compact_http-ip",
  "d-java_compact_http-ip-ssl",
  "d-java_json_http-ip",
  "d-java_json_http-ip-ssl",
  "d-js_json_http-ip",
  "d-netstd_binary_buffered-ip",
  "d-netstd_binary_buffered-ip-ssl",
  "d-netstd_binary_framed-ip",
  "d-netstd_binary_framed-ip-ssl",
  "d-netstd_compact_buffered-ip",
  "d-netstd_compact_buffered-ip-ssl",
  "d-netstd_compact_framed-ip",
  "d-netstd_compact_framed-ip-ssl",
  "d-netstd_json_buffered-ip",
  "d-netstd_json_buffered-ip-ssl",
  "d-netstd_json_framed-ip",
  "d-netstd_json_framed-ip-ssl",
  "d-nodejs_binary_buffered-ip",
  "d-nodejs_binary_buffered-ip-ssl",
  "d-nodejs_binary_framed-ip",
  "d-nodejs_binary_framed-ip-ssl",
  "d-nodejs_binary_http-ip",
  "d-nodejs_binary_http-ip-ssl",
  "d-nodejs_compact_buffered-ip",
  "d-nodejs_compact_buffered-ip-ssl",
  "d-nodejs_compact_framed-ip",
  "d-nodejs_compact_framed-ip-ssl",
  "d-nodejs_compact_http-ip",
  "d-nodejs_compact_http-ip-ssl",
  "d-nodejs_json_buffered-ip",
  "d-nodejs_json_buffered-ip-ssl",
  "d-nodejs_json_framed-ip",
  "d-nodejs_json_framed-ip-ssl",
  "d-nodejs_json_http-ip",
  "d-nodejs_json_http-ip-ssl",
  "d-nodets_binary_buffered-ip",
  "d-py3_binary-accel_buffered-ip",
  "d-py3_binary-accel_buffered-ip-ssl",
  "d-py3_binary-accel_framed-ip",
  "d-py3_binary-accel_framed-ip-ssl",
  "d-py3_binary-accel_http-ip",
  "d-py3_binary-accel_http-ip-ssl",
  "d-py3_binary-accel_zlib-ip",
  "d-py3_binary-accel_zlib-ip-ssl",
  "d-py3_binary_buffered-ip",
  "d-py3_binary_buffered-ip-ssl",
  "d-py3_binary_framed-ip",
  "d-py3_binary_framed-ip-ssl",
  "d-py3_binary_http-ip",
  "d-py3_binary_http-ip-ssl",
  "d-py3_binary_zlib-ip",
  "d-py3_binary_zlib-ip-ssl",
  "d-py3_compact-accelc_buffered-ip",
  "d-py3_compact-accelc_buffered-ip-ssl",
  "d-py3_compact-accelc_framed-ip",
  "d-py3_compact-accelc_framed-ip-ssl",
  "d-py3_compact-accelc_http-ip",
  "d-py3_compact-accelc_http-ip-ssl",
  "d-py3_compact-accelc_zlib-ip",
  "d-py3_compact-accelc_zlib-ip-ssl",
  "d-py3_compact_buffered-ip",
  "d-py3_compact_buffered-ip-ssl",
  "d-py3_compact_framed-ip",
  "d-py3_compact_framed-ip-ssl",
  "d-py3_compact_http-ip",
  "d-py3_compact_http-ip-ssl",
  "d-py3_compact_zlib-ip",
  "d-py3_compact_zlib-ip-ssl",
  "d-py3_json_buffered-ip",
  "d-py3_json_buffered-ip-ssl",
  "d-py3_json_framed-ip",
  "d-py3_json_framed-ip-ssl",
  "d-py3_json_http-ip",
  "d-py3_json_http-ip-ssl",
  "d-py3_json_zlib-ip",
  "d-py3_json_zlib-ip-ssl",
  "d-py_binary-accel_buffered-ip",
  "d-py_binary-accel_buffered-ip-ssl",
  "d-py_binary-accel_framed-ip",
  "d-py_binary-accel_framed-ip-ssl",
  "d-py_binary-accel_http-ip",
  "d-py_binary-accel_http-ip-ssl",
  "d-py_binary-accel_zlib-ip",
  "d-py_binary-accel_zlib-ip-ssl",
  "d-py_binary_buffered-ip",
  "d-py_binary_buffered-ip-ssl",
  "d-py_binary_framed-ip",
  "d-py_binary_framed-ip-ssl",
  "d-py_binary_http-ip",
  "d-py_binary_http-ip-ssl",
  "d-py_binary_zlib-ip",
  "d-py_binary_zlib-ip-ssl",
  "d-py_compact-accelc_buffered-ip",
  "d-py_compact-accelc_buffered-ip-ssl",
  "d-py_compact-accelc_framed-ip",
  "d-py_compact-accelc_framed-ip-ssl",
  "d-py_compact-accelc_http-ip",
  "d-py_compact-accelc_http-ip-ssl",
  "d-py_compact-accelc_zlib-ip",
  "d-py_compact-accelc_zlib-ip-ssl",
  "d-py_compact_buffered-ip",
  "d-py_compact_buffered-ip-ssl",
  "d-py_compact_framed-ip",
  "d-py_compact_framed-ip-ssl",
  "d-py_compact_http-ip",
  "d-py_compact_http-ip-ssl",
  "d-py_compact_zlib-ip",
  "d-py_compact_zlib-ip-ssl",
  "d-py_json_buffered-ip",
  "d-py_json_buffered-ip-ssl",
  "d-py_json_framed-ip",
  "d-py_json_framed-ip-ssl",
  "d-py_json_http-ip",
  "d-py_json_http-ip-ssl",
  "d-py_json_zlib-ip",
  "d-py_json_zlib-ip-ssl",
  "erl-cpp_binary_buffered-ip",
  "erl-cpp_compact_buffered-ip",
  "erl-netstd_binary_buffered-ip",
  "erl-netstd_binary_buffered-ip-ssl",
  "erl-netstd_binary_framed-ip",
  "erl-netstd_binary_framed-ip-ssl",
  "erl-netstd_compact_buffered-ip",
  "erl-netstd_compact_buffered-ip-ssl",
  "erl-netstd_compact_framed-ip",
  "erl-netstd_compact_framed-ip-ssl",
  "erl-nodejs_binary_buffered-ip",
  "erl-nodejs_compact_buffered-ip",
  "erl-nodets_binary_buffered-ip",
  "erl-rb_binary-accel_buffered-ip",
  "erl-rb_binary-accel_buffered-ip-ssl",
  "erl-rb_binary-accel_framed-ip",
  "erl-rb_binary-accel_framed-ip-ssl",
  "erl-rb_binary_buffered-ip",
  "erl-rb_binary_buffered-ip-ssl",
  "erl-rb_binary_framed-ip",
  "erl-rb_binary_framed-ip-ssl",
  "erl-rb_compact_buffered-ip",
  "erl-rb_compact_buffered-ip-ssl",
  "erl-rb_compact_framed-ip",
  "erl-rb_compact_framed-ip-ssl",
  "go-cpp_binary_http-ip",
  "go-cpp_binary_http-ip-ssl",
  "go-cpp_compact_http-ip",
  "go-cpp_compact_http-ip-ssl",
  "go-cpp_header_http-ip",
  "go-cpp_header_http-ip-ssl",
  "go-cpp_json_http-ip",
  "go-cpp_json_http-ip-ssl",
  "go-dart_binary_http-ip",
  "go-dart_compact_http-ip",
  "go-dart_json_http-ip",
  "go-d_binary_http-ip",
  "go-d_binary_http-ip-ssl",
  "go-d_compact_http-ip",
  "go-d_compact_http-ip-ssl",
  "go-d_json_http-ip",
  "go-d_json_http-ip-ssl",
  "go-java_binary_http-ip",
  "go-java_binary_http-ip-ssl",
  "go-java_compact_http-ip",
  "go-java_compact_http-ip-ssl",
  "go-java_json_http-ip",
  "go-java_json_http-ip-ssl",
  "go-netstd_binary_buffered-ip",
  "go-netstd_binary_buffered-ip-ssl",
  "go-netstd_binary_framed-ip",
  "go-netstd_binary_framed-ip-ssl",
  "go-netstd_compact_buffered-ip",
  "go-netstd_compact_buffered-ip-ssl",
  "go-netstd_compact_framed-ip",
  "go-netstd_compact_framed-ip-ssl",
  "go-netstd_json_buffered-ip",
  "go-netstd_json_buffered-ip-ssl",
  "go-netstd_json_framed-ip",
  "go-netstd_json_framed-ip-ssl",
  "go-py3_binary-accel_zlib-ip-ssl",
  "go-py3_compact-accelc_zlib-ip-ssl",
  "go-py_binary-accel_zlib-ip-ssl",
  "go-py_compact-accelc_zlib-ip-ssl",
  "hs-netstd_binary_buffered-ip",
  "hs-netstd_binary_framed-ip",
  "hs-netstd_compact_buffered-ip",
  "hs-netstd_compact_framed-ip",
  "hs-netstd_json_buffered-ip",
  "hs-netstd_json_framed-ip",
  "hs-php_binary-accel_buffered-ip",
  "hs-php_binary-accel_framed-ip",
  "hs-php_json_buffered-ip",
  "hs-php_json_framed-ip",
  "java-erl_binary_buffered-ip-ssl",
  "java-erl_binary_fastframed-framed-ip-ssl",
  "java-erl_binary_framed-ip-ssl",
  "java-erl_compact_buffered-ip-ssl",
  "java-erl_compact_fastframed-framed-ip-ssl",
  "java-erl_compact_framed-ip-ssl",
  "java-erl_multi-binary_buffered-ip-ssl",
  "java-erl_multi-binary_fastframed-framed-ip-ssl",
  "java-erl_multi-binary_framed-ip-ssl",
  "java-erl_multic-compact_buffered-ip-ssl",
  "java-erl_multic-compact_fastframed-framed-ip-ssl",
  "java-erl_multic-compact_framed-ip-ssl",
  "java-netstd_binary_buffered-ip",
  "java-netstd_binary_buffered-ip-ssl",
  "java-netstd_binary_fastframed-framed-ip",
  "java-netstd_binary_fastframed-framed-ip-ssl",
  "java-netstd_binary_framed-ip",
  "java-netstd_binary_framed-ip-ssl",
  "java-netstd_compact_buffered-ip",
  "java-netstd_compact_buffered-ip-ssl",
  "java-netstd_compact_fastframed-framed-ip",
  "java-netstd_compact_fastframed-framed-ip-ssl",
  "java-netstd_compact_framed-ip",
  "java-netstd_compact_framed-ip-ssl",
  "java-netstd_json_buffered-ip",
  "java-netstd_json_buffered-ip-ssl",
  "java-netstd_json_fastframed-framed-ip",
  "java-netstd_json_fastframed-framed-ip-ssl",
  "java-netstd_json_framed-ip",
  "java-netstd_json_framed-ip-ssl",
  "java-netstd_multi-binary_buffered-ip",
  "java-netstd_multi-binary_buffered-ip-ssl",
  "java-netstd_multi-binary_fastframed-framed-ip",
  "java-netstd_multi-binary_fastframed-framed-ip-ssl",
  "java-netstd_multi-binary_framed-ip",
  "java-netstd_multi-binary_framed-ip-ssl",
  "java-netstd_multic-compact_buffered-ip",
  "java-netstd_multic-compact_buffered-ip-ssl",
  "java-netstd_multic-compact_fastframed-framed-ip",
  "java-netstd_multic-compact_fastframed-framed-ip-ssl",
  "java-netstd_multic-compact_framed-ip",
  "java-netstd_multic-compact_framed-ip-ssl",
  "java-netstd_multij-json_buffered-ip",
  "java-netstd_multij-json_buffered-ip-ssl",
  "java-netstd_multij-json_fastframed-framed-ip",
  "java-netstd_multij-json_fastframed-framed-ip-ssl",
  "java-netstd_multij-json_framed-ip",
  "java-netstd_multij-json_framed-ip-ssl",
  "java-php_binary-accel_buffered-ip",
  "java-php_binary-accel_fastframed-framed-ip",
  "java-php_binary-accel_framed-ip",
  "java-php_json_buffered-ip",
  "java-php_json_fastframed-framed-ip",
  "java-php_json_framed-ip",
  "java-php_multi-accel_buffered-ip",
  "java-php_multi-accel_fastframed-framed-ip",
  "java-php_multi-accel_framed-ip",
  "java-php_multij-json_buffered-ip",
  "java-php_multij-json_fastframed-framed-ip",
  "java-php_multij-json_framed-ip",
  "netstd-cl_binary_buffered-ip",
  "netstd-cl_binary_framed-ip",
  "netstd-cpp_binary_buffered-ip",
  "netstd-cpp_binary_buffered-ip-ssl",
  "netstd-cpp_binary_framed-ip",
  "netstd-cpp_binary_framed-ip-ssl",
  "netstd-cpp_compact_buffered-ip",
  "netstd-cpp_compact_buffered-ip-ssl",
  "netstd-cpp_compact_framed-ip",
  "netstd-cpp_compact_framed-ip-ssl",
  "netstd-cpp_json_buffered-ip",
  "netstd-cpp_json_buffered-ip-ssl",
  "netstd-cpp_json_framed-ip",
  "netstd-cpp_json_framed-ip-ssl",
  "netstd-c_glib_binary_buffered-ip",
  "netstd-c_glib_binary_buffered-ip-ssl",
  "netstd-c_glib_binary_framed-ip",
  "netstd-c_glib_binary_framed-ip-ssl",
  "netstd-c_glib_compact_buffered-ip",
  "netstd-c_glib_compact_buffered-ip-ssl",
  "netstd-c_glib_compact_framed-ip",
  "netstd-c_glib_compact_framed-ip-ssl",
  "netstd-dart_binary_buffered-ip",
  "netstd-dart_binary_framed-ip",
  "netstd-dart_compact_buffered-ip",
  "netstd-dart_compact_framed-ip",
  "netstd-dart_json_buffered-ip",
  "netstd-dart_json_framed-ip",
  "netstd-d_binary_buffered-ip",
  "netstd-d_binary_buffered-ip-ssl",
  "netstd-d_binary_framed-ip",
  "netstd-d_binary_framed-ip-ssl",
  "netstd-d_compact_buffered-ip",
  "netstd-d_compact_buffered-ip-ssl",
  "netstd-d_compact_framed-ip",
  "netstd-d_compact_framed-ip-ssl",
  "netstd-d_json_buffered-ip",
  "netstd-d_json_buffered-ip-ssl",
  "netstd-d_json_framed-ip",
  "netstd-d_json_framed-ip-ssl",
  "netstd-erl_binary_buffered-ip",
  "netstd-erl_binary_buffered-ip-ssl",
  "netstd-erl_binary_framed-ip",
  "netstd-erl_binary_framed-ip-ssl",
  "netstd-erl_compact_buffered-ip",
  "netstd-erl_compact_buffered-ip-ssl",
  "netstd-erl_compact_framed-ip",
  "netstd-erl_compact_framed-ip-ssl",
  "netstd-go_binary_buffered-ip",
  "netstd-go_binary_buffered-ip-ssl",
  "netstd-go_binary_framed-ip",
  "netstd-go_binary_framed-ip-ssl",
  "netstd-go_compact_buffered-ip",
  "netstd-go_compact_buffered-ip-ssl",
  "netstd-go_compact_framed-ip",
  "netstd-go_compact_framed-ip-ssl",
  "netstd-go_json_buffered-ip",
  "netstd-go_json_buffered-ip-ssl",
  "netstd-go_json_framed-ip",
  "netstd-go_json_framed-ip-ssl",
  "netstd-hs_binary_buffered-ip",
  "netstd-hs_binary_framed-ip",
  "netstd-hs_compact_buffered-ip",
  "netstd-hs_compact_framed-ip",
  "netstd-hs_json_buffered-ip",
  "netstd-hs_json_framed-ip",
  "netstd-java_binary_buffered-ip",
  "netstd-java_binary_buffered-ip-ssl",
  "netstd-java_binary_framed-fastframed-ip",
  "netstd-java_binary_framed-fastframed-ip-ssl",
  "netstd-java_binary_framed-ip",
  "netstd-java_binary_framed-ip-ssl",
  "netstd-java_compact_buffered-ip",
  "netstd-java_compact_buffered-ip-ssl",
  "netstd-java_compact_framed-fastframed-ip",
  "netstd-java_compact_framed-fastframed-ip-ssl",
  "netstd-java_compact_framed-ip",
  "netstd-java_compact_framed-ip-ssl",
  "netstd-java_json_buffered-ip",
  "netstd-java_json_buffered-ip-ssl",
  "netstd-java_json_framed-fastframed-ip",
  "netstd-java_json_framed-fastframed-ip-ssl",
  "netstd-java_json_framed-ip",
  "netstd-java_json_framed-ip-ssl",
  "netstd-lua_binary_buffered-ip",
  "netstd-lua_binary_framed-ip",
  "netstd-lua_compact_buffered-ip",
  "netstd-lua_compact_framed-ip",
  "netstd-lua_json_buffered-ip",
  "netstd-lua_json_framed-ip",
  "netstd-netstd_binary_buffered-ip",
  "netstd-netstd_binary_buffered-ip-ssl",
  "netstd-netstd_binary_framed-ip",
  "netstd-netstd_binary_framed-ip-ssl",
  "netstd-netstd_compact_buffered-ip",
  "netstd-netstd_compact_buffered-ip-ssl",
  "netstd-netstd_compact_framed-ip",
  "netstd-netstd_compact_framed-ip-ssl",
  "netstd-netstd_json_buffered-ip",
  "netstd-netstd_json_buffered-ip-ssl",
  "netstd-netstd_json_framed-ip",
  "netstd-netstd_json_framed-ip-ssl",
  "netstd-nodejs_binary_buffered-ip",
  "netstd-nodejs_binary_buffered-ip-ssl",
  "netstd-nodejs_binary_framed-ip",
  "netstd-nodejs_binary_framed-ip-ssl",
  "netstd-nodejs_compact_buffered-ip",
  "netstd-nodejs_compact_buffered-ip-ssl",
  "netstd-nodejs_compact_framed-ip",
  "netstd-nodejs_compact_framed-ip-ssl",
  "netstd-nodejs_json_buffered-ip",
  "netstd-nodejs_json_buffered-ip-ssl",
  "netstd-nodejs_json_framed-ip",
  "netstd-nodejs_json_framed-ip-ssl",
  "netstd-nodets_binary_buffered-ip",
  "netstd-perl_binary_buffered-ip",
  "netstd-perl_binary_buffered-ip-ssl",
  "netstd-perl_binary_framed-ip",
  "netstd-perl_binary_framed-ip-ssl",
  "netstd-php_binary-accel_buffered-ip",
  "netstd-php_binary-accel_framed-ip",
  "netstd-php_binary_buffered-ip",
  "netstd-php_binary_framed-ip",
  "netstd-php_compact_buffered-ip",
  "netstd-php_compact_framed-ip",
  "netstd-php_json_buffered-ip",
  "netstd-php_json_framed-ip",
  "netstd-py3_binary-accel_buffered-ip",
  "netstd-py3_binary-accel_buffered-ip-ssl",
  "netstd-py3_binary-accel_framed-ip",
  "netstd-py3_binary-accel_framed-ip-ssl",
  "netstd-py3_binary_buffered-ip",
  "netstd-py3_binary_buffered-ip-ssl",
  "netstd-py3_binary_framed-ip",
  "netstd-py3_binary_framed-ip-ssl",
  "netstd-py3_compact-accelc_buffered-ip",
  "netstd-py3_compact-accelc_buffered-ip-ssl",
  "netstd-py3_compact-accelc_framed-ip",
  "netstd-py3_compact-accelc_framed-ip-ssl",
  "netstd-py3_compact_buffered-ip",
  "netstd-py3_compact_buffered-ip-ssl",
  "netstd-py3_compact_framed-ip",
  "netstd-py3_compact_framed-ip-ssl",
  "netstd-py3_json_buffered-ip",
  "netstd-py3_json_buffered-ip-ssl",
  "netstd-py3_json_framed-ip",
  "netstd-py3_json_framed-ip-ssl",
  "netstd-py_binary-accel_buffered-ip",
  "netstd-py_binary-accel_buffered-ip-ssl",
  "netstd-py_binary-accel_framed-ip",
  "netstd-py_binary-accel_framed-ip-ssl",
  "netstd-py_binary_buffered-ip",
  "netstd-py_binary_buffered-ip-ssl",
  "netstd-py_binary_framed-ip",
  "netstd-py_binary_framed-ip-ssl",
  "netstd-py_compact-accelc_buffered-ip",
  "netstd-py_compact-accelc_buffered-ip-ssl",
  "netstd-py_compact-accelc_framed-ip",
  "netstd-py_compact-accelc_framed-ip-ssl",
  "netstd-py_compact_buffered-ip",
  "netstd-py_compact_buffered-ip-ssl",
  "netstd-py_compact_framed-ip",
  "netstd-py_compact_framed-ip-ssl",
  "netstd-py_json_buffered-ip",
  "netstd-py_json_buffered-ip-ssl",
  "netstd-py_json_framed-ip",
  "netstd-py_json_framed-ip-ssl",
  "netstd-rb_binary-accel_buffered-ip",
  "netstd-rb_binary-accel_buffered-ip-ssl",
  "netstd-rb_binary-accel_framed-ip",
  "netstd-rb_binary-accel_framed-ip-ssl",
  "netstd-rb_binary_buffered-ip",
  "netstd-rb_binary_buffered-ip-ssl",
  "netstd-rb_binary_framed-ip",
  "netstd-rb_binary_framed-ip-ssl",
  "netstd-rb_compact_buffered-ip",
  "netstd-rb_compact_buffered-ip-ssl",
  "netstd-rb_compact_framed-ip",
  "netstd-rb_compact_framed-ip-ssl",
  "netstd-rb_json_buffered-ip",
  "netstd-rb_json_buffered-ip-ssl",
  "netstd-rb_json_framed-ip",
  "netstd-rb_json_framed-ip-ssl",
  "netstd-rs_binary_buffered-ip",
  "netstd-rs_binary_framed-ip",
  "netstd-rs_compact_buffered-ip",
  "netstd-rs_compact_framed-ip",
  "nodejs-cpp_binary_http-domain",
  "nodejs-cpp_binary_http-ip",
  "nodejs-cpp_binary_http-ip-ssl",
  "nodejs-cpp_binary_websocket-domain",
  "nodejs-cpp_binary_websocket-ip",
  "nodejs-cpp_binary_websocket-ip-ssl",
  "nodejs-cpp_compact_http-domain",
  "nodejs-cpp_compact_http-ip",
  "nodejs-cpp_compact_http-ip-ssl",
  "nodejs-cpp_compact_websocket-domain",
  "nodejs-cpp_compact_websocket-ip",
  "nodejs-cpp_compact_websocket-ip-ssl",
  "nodejs-cpp_header_http-domain",
  "nodejs-cpp_header_http-ip",
  "nodejs-cpp_header_http-ip-ssl",
  "nodejs-cpp_header_websocket-domain",
  "nodejs-cpp_header_websocket-ip",
  "nodejs-cpp_header_websocket-ip-ssl",
  "nodejs-cpp_json_buffered-ip-ssl",
  "nodejs-cpp_json_http-domain",
  "nodejs-cpp_json_http-ip",
  "nodejs-cpp_json_http-ip-ssl",
  "nodejs-cpp_json_websocket-domain",
  "nodejs-cpp_json_websocket-ip",
  "nodejs-cpp_json_websocket-ip-ssl",
  "nodejs-dart_binary_http-ip",
  "nodejs-dart_compact_http-ip",
  "nodejs-dart_json_http-ip",
  "nodejs-d_binary_http-ip",
  "nodejs-d_binary_http-ip-ssl",
  "nodejs-d_compact_http-ip",
  "nodejs-d_compact_http-ip-ssl",
  "nodejs-d_json_http-ip",
  "nodejs-d_json_http-ip-ssl",
  "nodejs-go_binary_http-ip",
  "nodejs-go_binary_http-ip-ssl",
  "nodejs-go_compact_http-ip",
  "nodejs-go_compact_http-ip-ssl",
  "nodejs-go_header_http-ip",
  "nodejs-go_header_http-ip-ssl",
  "nodejs-go_json_http-ip",
  "nodejs-go_json_http-ip-ssl",
  "nodejs-hs_binary_http-ip",
  "nodejs-hs_compact_http-ip",
  "nodejs-hs_header_http-ip",
  "nodejs-hs_json_http-ip",
  "nodejs-java_binary_http-ip",
  "nodejs-java_binary_http-ip-ssl",
  "nodejs-java_compact_http-ip",
  "nodejs-java_compact_http-ip-ssl",
  "nodejs-java_json_http-ip",
  "nodejs-java_json_http-ip-ssl",
  "nodejs-js_json_http-ip",
  "nodejs-lua_binary_http-ip",
  "nodejs-lua_compact_http-ip",
  "nodejs-lua_json_http-ip",
  "nodejs-netstd_binary_buffered-ip",
  "nodejs-netstd_binary_buffered-ip-ssl",
  "nodejs-netstd_binary_framed-ip",
  "nodejs-netstd_binary_framed-ip-ssl",
  "nodejs-netstd_compact_buffered-ip",
  "nodejs-netstd_compact_buffered-ip-ssl",
  "nodejs-netstd_compact_framed-ip",
  "nodejs-netstd_compact_framed-ip-ssl",
  "nodejs-netstd_json_buffered-ip",
  "nodejs-netstd_json_buffered-ip-ssl",
  "nodejs-netstd_json_framed-ip",
  "nodejs-netstd_json_framed-ip-ssl",
  "nodejs-nodejs_binary_websocket-domain",
  "nodejs-nodejs_compact_websocket-domain",
  "nodejs-nodejs_header_websocket-domain",
  "nodejs-nodejs_json_websocket-domain",
  "nodejs-php_binary-accel_buffered-ip",
  "nodejs-php_binary-accel_framed-ip",
  "nodejs-php_json_buffered-ip",
  "nodejs-php_json_framed-ip",
  "nodejs-py3_binary-accel_http-domain",
  "nodejs-py3_binary-accel_http-ip",
  "nodejs-py3_binary-accel_http-ip-ssl",
  "nodejs-py3_binary_http-domain",
  "nodejs-py3_binary_http-ip",
  "nodejs-py3_binary_http-ip-ssl",
  "nodejs-py3_compact-accelc_http-domain",
  "nodejs-py3_compact-accelc_http-ip",
  "nodejs-py3_compact-accelc_http-ip-ssl",
  "nodejs-py3_compact_http-domain",
  "nodejs-py3_compact_http-ip",
  "nodejs-py3_compact_http-ip-ssl",
  "nodejs-py3_header_http-domain",
  "nodejs-py3_header_http-ip",
  "nodejs-py3_header_http-ip-ssl",
  "nodejs-py3_json_http-domain",
  "nodejs-py3_json_http-ip",
  "nodejs-py3_json_http-ip-ssl",
  "nodejs-py_binary-accel_http-domain",
  "nodejs-py_binary-accel_http-ip",
  "nodejs-py_binary-accel_http-ip-ssl",
  "nodejs-py_binary_http-domain",
  "nodejs-py_binary_http-ip",
  "nodejs-py_binary_http-ip-ssl",
  "nodejs-py_compact-accelc_http-domain",
  "nodejs-py_compact-accelc_http-ip",
  "nodejs-py_compact-accelc_http-ip-ssl",
  "nodejs-py_compact_http-domain",
  "nodejs-py_compact_http-ip",
  "nodejs-py_compact_http-ip-ssl",
  "nodejs-py_header_http-domain",
  "nodejs-py_header_http-ip",
  "nodejs-py_header_http-ip-ssl",
  "nodejs-py_json_http-domain",
  "nodejs-py_json_http-ip",
  "nodejs-py_json_http-ip-ssl",
  "nodets-netstd_binary_buffered-ip",
  "nodets-php_binary-accel_buffered-ip",
  "perl-netstd_binary_buffered-ip",
  "perl-netstd_binary_buffered-ip-ssl",
  "perl-netstd_binary_framed-ip",
  "perl-netstd_binary_framed-ip-ssl",
  "perl-netstd_multi-binary_buffered-ip",
  "perl-netstd_multi-binary_buffered-ip-ssl",
  "perl-netstd_multi-binary_framed-ip",
  "perl-netstd_multi-binary_framed-ip-ssl",
  "py-cpp_accel-binary_http-domain",
  "py-cpp_accel-binary_http-ip",
  "py-cpp_accel-binary_http-ip-ssl",
  "py-cpp_accel-binary_zlib-domain",
  "py-cpp_accel-binary_zlib-ip",
  "py-cpp_accel-binary_zlib-ip-ssl",
  "py-cpp_accelc-compact_http-domain",
  "py-cpp_accelc-compact_http-ip",
  "py-cpp_accelc-compact_http-ip-ssl",
  "py-cpp_accelc-compact_zlib-domain",
  "py-cpp_accelc-compact_zlib-ip",
  "py-cpp_accelc-compact_zlib-ip-ssl",
  "py-cpp_binary_http-domain",
  "py-cpp_binary_http-ip",
  "py-cpp_binary_http-ip-ssl",
  "py-cpp_compact_http-domain",
  "py-cpp_compact_http-ip",
  "py-cpp_compact_http-ip-ssl",
  "py-cpp_header_http-domain",
  "py-cpp_header_http-ip",
  "py-cpp_header_http-ip-ssl",
  "py-cpp_json_http-domain",
  "py-cpp_json_http-ip",
  "py-cpp_json_http-ip-ssl",
  "py-cpp_multi-binary_http-domain",
  "py-cpp_multi-binary_http-ip",
  "py-cpp_multi-binary_http-ip-ssl",
  "py-cpp_multia-binary_http-domain",
  "py-cpp_multia-binary_http-ip",
  "py-cpp_multia-binary_http-ip-ssl",
  "py-cpp_multia-binary_zlib-domain",
  "py-cpp_multia-binary_zlib-ip",
  "py-cpp_multia-binary_zlib-ip-ssl",
  "py-cpp_multia-multi_http-domain",
  "py-cpp_multia-multi_http-ip",
  "py-cpp_multia-multi_http-ip-ssl",
  "py-cpp_multia-multi_zlib-domain",
  "py-cpp_multia-multi_zlib-ip",
  "py-cpp_multia-multi_zlib-ip-ssl",
  "py-cpp_multiac-compact_http-domain",
  "py-cpp_multiac-compact_http-ip",
  "py-cpp_multiac-compact_http-ip-ssl",
  "py-cpp_multiac-compact_zlib-domain",
  "py-cpp_multiac-compact_zlib-ip",
  "py-cpp_multiac-compact_zlib-ip-ssl",
  "py-cpp_multiac-multic_http-domain",
  "py-cpp_multiac-multic_http-ip",
  "py-cpp_multiac-multic_http-ip-ssl",
  "py-cpp_multiac-multic_zlib-domain",
  "py-cpp_multiac-multic_zlib-ip",
  "py-cpp_multiac-multic_zlib-ip-ssl",
  "py-cpp_multic-compact_http-domain",
  "py-cpp_multic-compact_http-ip",
  "py-cpp_multic-compact_http-ip-ssl",
  "py-cpp_multic_http-domain",
  "py-cpp_multic_http-ip",
  "py-cpp_multic_http-ip-ssl",
  "py-cpp_multih-header_http-domain",
  "py-cpp_multih-header_http-ip",
  "py-cpp_multih-header_http-ip-ssl",
  "py-cpp_multih_http-domain",
  "py-cpp_multih_http-ip",
  "py-cpp_multih_http-ip-ssl",
  "py-cpp_multij-json_http-domain",
  "py-cpp_multij-json_http-ip",
  "py-cpp_multij-json_http-ip-ssl",
  "py-cpp_multij_http-domain",
  "py-cpp_multij_http-ip",
  "py-cpp_multij_http-ip-ssl",
  "py-cpp_multi_http-domain",
  "py-cpp_multi_http-ip",
  "py-cpp_multi_http-ip-ssl",
  "py-dart_accel-binary_http-ip",
  "py-dart_accelc-compact_http-ip",
  "py-dart_binary_http-ip",
  "py-dart_compact_http-ip",
  "py-dart_json_http-ip",
  "py-d_accel-binary_http-ip",
  "py-d_accel-binary_http-ip-ssl",
  "py-d_accelc-compact_http-ip",
  "py-d_accelc-compact_http-ip-ssl",
  "py-d_binary_http-ip",
  "py-d_binary_http-ip-ssl",
  "py-d_compact_http-ip",
  "py-d_compact_http-ip-ssl",
  "py-d_json_http-ip",
  "py-d_json_http-ip-ssl",
  "py-hs_accel-binary_http-ip",
  "py-hs_accelc-compact_http-ip",
  "py-hs_binary_http-ip",
  "py-hs_compact_http-ip",
  "py-hs_header_http-ip",
  "py-hs_json_http-ip",
  "py-java_accel-binary_http-ip-ssl",
  "py-java_accelc-compact_http-ip-ssl",
  "py-java_binary_http-ip-ssl",
  "py-java_compact_http-ip-ssl",
  "py-java_json_http-ip-ssl",
  "py-java_multi-binary_http-ip-ssl",
  "py-java_multia-binary_http-ip-ssl",
  "py-java_multia-multi_http-ip-ssl",
  "py-java_multiac-compact_http-ip-ssl",
  "py-java_multiac-multic_http-ip-ssl",
  "py-java_multic-compact_http-ip-ssl",
  "py-java_multic_http-ip-ssl",
  "py-java_multij-json_http-ip-ssl",
  "py-java_multij_http-ip-ssl",
  "py-java_multi_http-ip-ssl",
  "py-lua_accel-binary_http-ip",
  "py-lua_accelc-compact_http-ip",
  "py-lua_binary_http-ip",
  "py-lua_compact_http-ip",
  "py-lua_json_http-ip",
  "py-netstd_accel-binary_buffered-ip",
  "py-netstd_accel-binary_buffered-ip-ssl",
  "py-netstd_accel-binary_framed-ip",
  "py-netstd_accel-binary_framed-ip-ssl",
  "py-netstd_accelc-compact_buffered-ip",
  "py-netstd_accelc-compact_buffered-ip-ssl",
  "py-netstd_accelc-compact_framed-ip",
  "py-netstd_accelc-compact_framed-ip-ssl",
  "py-netstd_binary_buffered-ip",
  "py-netstd_binary_buffered-ip-ssl",
  "py-netstd_binary_framed-ip",
  "py-netstd_binary_framed-ip-ssl",
  "py-netstd_compact_buffered-ip",
  "py-netstd_compact_buffered-ip-ssl",
  "py-netstd_compact_framed-ip",
  "py-netstd_compact_framed-ip-ssl",
  "py-netstd_json_buffered-ip",
  "py-netstd_json_buffered-ip-ssl",
  "py-netstd_json_framed-ip",
  "py-netstd_json_framed-ip-ssl",
  "py-nodejs_accel-binary_http-domain",
  "py-nodejs_accelc-compact_http-domain",
  "py-nodejs_binary_http-domain",
  "py-nodejs_compact_http-domain",
  "py-nodejs_header_http-domain",
  "py-nodejs_json_http-domain",
  "py-php_accel_buffered-ip",
  "py-php_accel_framed-ip",
  "py-php_binary-accel_buffered-ip",
  "py-php_binary-accel_framed-ip",
  "py-php_json_buffered-ip",
  "py-php_json_framed-ip",
  "py-rs_multia-multi_buffered-ip",
  "py-rs_multia-multi_framed-ip",
  "py-rs_multiac-multic_buffered-ip",
  "py-rs_multiac-multic_framed-ip",
  "py-rs_multic_buffered-ip",
  "py-rs_multic_framed-ip",
  "py-rs_multi_buffered-ip",
  "py-rs_multi_framed-ip",
  "py3-cpp_accel-binary_http-domain",
  "py3-cpp_accel-binary_http-ip",
  "py3-cpp_accel-binary_http-ip-ssl",
  "py3-cpp_accel-binary_zlib-domain",
  "py3-cpp_accel-binary_zlib-ip",
  "py3-cpp_accel-binary_zlib-ip-ssl",
  "py3-cpp_accelc-compact_http-domain",
  "py3-cpp_accelc-compact_http-ip",
  "py3-cpp_accelc-compact_http-ip-ssl",
  "py3-cpp_accelc-compact_zlib-domain",
  "py3-cpp_accelc-compact_zlib-ip",
  "py3-cpp_accelc-compact_zlib-ip-ssl",
  "py3-cpp_binary_http-domain",
  "py3-cpp_binary_http-ip",
  "py3-cpp_binary_http-ip-ssl",
  "py3-cpp_compact_http-domain",
  "py3-cpp_compact_http-ip",
  "py3-cpp_compact_http-ip-ssl",
  "py3-cpp_header_http-domain",
  "py3-cpp_header_http-ip",
  "py3-cpp_header_http-ip-ssl",
  "py3-cpp_json_http-domain",
  "py3-cpp_json_http-ip",
  "py3-cpp_json_http-ip-ssl",
  "py3-cpp_multi-binary_http-domain",
  "py3-cpp_multi-binary_http-ip",
  "py3-cpp_multi-binary_http-ip-ssl",
  "py3-cpp_multia-binary_http-domain",
  "py3-cpp_multia-binary_http-ip",
  "py3-cpp_multia-binary_http-ip-ssl",
  "py3-cpp_multia-binary_zlib-domain",
  "py3-cpp_multia-binary_zlib-ip",
  "py3-cpp_multia-binary_zlib-ip-ssl",
  "py3-cpp_multia-multi_http-domain",
  "py3-cpp_multia-multi_http-ip",
  "py3-cpp_multia-multi_http-ip-ssl",
  "py3-cpp_multia-multi_zlib-domain",
  "py3-cpp_multia-multi_zlib-ip",
  "py3-cpp_multia-multi_zlib-ip-ssl",
  "py3-cpp_multiac-compact_http-domain",
  "py3-cpp_multiac-compact_http-ip",
  "py3-cpp_multiac-compact_http-ip-ssl",
  "py3-cpp_multiac-compact_zlib-domain",
  "py3-cpp_multiac-compact_zlib-ip",
  "py3-cpp_multiac-compact_zlib-ip-ssl",
  "py3-cpp_multiac-multic_http-domain",
  "py3-cpp_multiac-multic_http-ip",
  "py3-cpp_multiac-multic_http-ip-ssl",
  "py3-cpp_multiac-multic_zlib-domain",
  "py3-cpp_multiac-multic_zlib-ip",
  "py3-cpp_multiac-multic_zlib-ip-ssl",
  "py3-cpp_multic-compact_http-domain",
  "py3-cpp_multic-compact_http-ip",
  "py3-cpp_multic-compact_http-ip-ssl",
  "py3-cpp_multic_http-domain",
  "py3-cpp_multic_http-ip",
  "py3-cpp_multic_http-ip-ssl",
  "py3-cpp_multih-header_http-domain",
  "py3-cpp_multih-header_http-ip",
  "py3-cpp_multih-header_http-ip-ssl",
  "py3-cpp_multih_http-domain",
  "py3-cpp_multih_http-ip",
  "py3-cpp_multih_http-ip-ssl",
  "py3-cpp_multij-json_http-domain",
  "py3-cpp_multij-json_http-ip",
  "py3-cpp_multij-json_http-ip-ssl",
  "py3-cpp_multij_http-domain",
  "py3-cpp_multij_http-ip",
  "py3-cpp_multij_http-ip-ssl",
  "py3-cpp_multi_http-domain",
  "py3-cpp_multi_http-ip",
  "py3-cpp_multi_http-ip-ssl",
  "py3-dart_accel-binary_http-ip",
  "py3-dart_accelc-compact_http-ip",
  "py3-dart_binary_http-ip",
  "py3-dart_compact_http-ip",
  "py3-dart_json_http-ip",
  "py3-d_accel-binary_http-ip",
  "py3-d_accel-binary_http-ip-ssl",
  "py3-d_accelc-compact_http-ip",
  "py3-d_accelc-compact_http-ip-ssl",
  "py3-d_binary_http-ip",
  "py3-d_binary_http-ip-ssl",
  "py3-d_compact_http-ip",
  "py3-d_compact_http-ip-ssl",
  "py3-d_json_http-ip",
  "py3-d_json_http-ip-ssl",
  "py3-hs_accel-binary_http-ip",
  "py3-hs_accelc-compact_http-ip",
  "py3-hs_binary_http-ip",
  "py3-hs_compact_http-ip",
  "py3-hs_header_http-ip",
  "py3-hs_json_http-ip",
  "py3-java_accel-binary_http-ip-ssl",
  "py3-java_accelc-compact_http-ip-ssl",
  "py3-java_binary_http-ip-ssl",
  "py3-java_compact_http-ip-ssl",
  "py3-java_json_http-ip-ssl",
  "py3-java_multi-binary_http-ip-ssl",
  "py3-java_multia-binary_http-ip-ssl",
  "py3-java_multia-multi_http-ip-ssl",
  "py3-java_multiac-compact_http-ip-ssl",
  "py3-java_multiac-multic_http-ip-ssl",
  "py3-java_multic-compact_http-ip-ssl",
  "py3-java_multic_http-ip-ssl",
  "py3-java_multij-json_http-ip-ssl",
  "py3-java_multij_http-ip-ssl",
  "py3-java_multi_http-ip-ssl",
  "py3-lua_accel-binary_http-ip",
  "py3-lua_accelc-compact_http-ip",
  "py3-lua_binary_http-ip",
  "py3-lua_compact_http-ip",
  "py3-lua_json_http-ip",
  "py3-netstd_accel-binary_buffered-ip",
  "py3-netstd_accel-binary_buffered-ip-ssl",
  "py3-netstd_accel-binary_framed-ip",
  "py3-netstd_accel-binary_framed-ip-ssl",
  "py3-netstd_accelc-compact_buffered-ip",
  "py3-netstd_accelc-compact_buffered-ip-ssl",
  "py3-netstd_accelc-compact_framed-ip",
  "py3-netstd_accelc-compact_framed-ip-ssl",
  "py3-netstd_binary_buffered-ip",
  "py3-netstd_binary_buffered-ip-ssl",
  "py3-netstd_binary_framed-ip",
  "py3-netstd_binary_framed-ip-ssl",
  "py3-netstd_compact_buffered-ip",
  "py3-netstd_compact_buffered-ip-ssl",
  "py3-netstd_compact_framed-ip",
  "py3-netstd_compact_framed-ip-ssl",
  "py3-netstd_json_buffered-ip",
  "py3-netstd_json_buffered-ip-ssl",
  "py3-netstd_json_framed-ip",
  "py3-netstd_json_framed-ip-ssl",
  "py3-nodejs_accel-binary_http-domain",
  "py3-nodejs_accelc-compact_http-domain",
  "py3-nodejs_binary_http-domain",
  "py3-nodejs_compact_http-domain",
  "py3-nodejs_header_http-domain",
  "py3-nodejs_json_http-domain",
  "py3-php_accel_buffered-ip",
  "py3-php_accel_framed-ip",
  "py3-php_binary-accel_buffered-ip",
  "py3-php_binary-accel_framed-ip",
  "py3-php_json_buffered-ip",
  "py3-php_json_framed-ip",
  "rb-cpp_json_buffered-domain",
  "rb-cpp_json_buffered-ip",
  "rb-cpp_json_buffered-ip-ssl",
  "rb-cpp_json_framed-domain",
  "rb-cpp_json_framed-ip",
  "rb-cpp_json_framed-ip-ssl",
  "rb-netstd_accel-binary_buffered-ip",
  "rb-netstd_accel-binary_buffered-ip-ssl",
  "rb-netstd_accel-binary_framed-ip",
  "rb-netstd_accel-binary_framed-ip-ssl",
  "rb-netstd_binary_buffered-ip",
  "rb-netstd_binary_buffered-ip-ssl",
  "rb-netstd_binary_framed-ip",
  "rb-netstd_binary_framed-ip-ssl",
  "rb-netstd_compact_buffered-ip",
  "rb-netstd_compact_buffered-ip-ssl",
  "rb-netstd_compact_framed-ip",
  "rb-netstd_compact_framed-ip-ssl",
  "rb-netstd_json_buffered-ip",
  "rb-netstd_json_buffered-ip-ssl",
  "rb-netstd_json_framed-ip",
  "rb-netstd_json_framed-ip-ssl",
  "rs-netstd_binary_buffered-ip",
  "rs-netstd_binary_framed-ip",
  "rs-netstd_compact_buffered-ip",
  "rs-netstd_compact_buffered-ip",
  "rs-netstd_compact_framed-ip",
  "rs-netstd_multi-binary_buffered-ip",
  "rs-netstd_multi-binary_framed-ip",
  "rs-netstd_multic-compact_buffered-ip",
  "rs-netstd_multic-compact_framed-ip"
]
thrift-0.16.0/test/lua/000077500000000000000000000000001420101504100146225ustar00rootroot00000000000000thrift-0.16.0/test/lua/Makefile.am000066400000000000000000000021721420101504100166600ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

THRIFT = $(top_builddir)/compiler/cpp/thrift

# Remove "MapType =" line to ignore some map bug for now
stubs: ../ThriftTest.thrift $(THRIFT)
	$(THRIFT) --gen lua $<
	$(SED) -i.bak 's/MapType =//g' gen-lua/ThriftTest_ttypes.lua
	$(RM) gen-lua/ThriftTest_ttypes.lua.bak

precross: stubs

clean-local:
	$(RM) -r gen-lua/

dist-hook:
	$(RM) -r $(distdir)/gen-lua/
thrift-0.16.0/test/lua/test_basic_client.lua000066400000000000000000000135121420101504100210050ustar00rootroot00000000000000-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at

--   http://www.apache.org/licenses/LICENSE-2.0

-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.


require('TSocket')
require('TBufferedTransport')
require('TFramedTransport')
require('THttpTransport')
require('TCompactProtocol')
require('TJsonProtocol')
require('TBinaryProtocol')
require('ThriftTest_ThriftTest')
require('liblualongnumber')

local client

function teardown()
  if client then
    -- close the connection
    client:close()
  end
end

function parseArgs(rawArgs)
  local opt = {
    protocol='binary',
    transport='buffered',
    port='9090',
  }
  for i, str in pairs(rawArgs) do
    if i > 0 then
      k, v = string.match(str, '--(%w+)=(%w+)')
      assert(opt[k] ~= nil, 'Unknown argument')
      opt[k] = v
    end
  end
  return opt
end

function assertEqual(val1, val2, msg)
  assert(val1 == val2, msg)
end

function testBasicClient(rawArgs)
  local opt = parseArgs(rawArgs)
  local socket = TSocket:new{
    port = tonumber(opt.port)
  }
  assert(socket, 'Failed to create client socket')
  socket:setTimeout(5000)

  local transports = {
    buffered = TBufferedTransport,
    framed = TFramedTransport,
    http = THttpTransport,
  }
  assert(transports[opt.transport] ~= nil)
  local transport = transports[opt.transport]:new{
    trans = socket,
    isServer = false
  }

  local protocols = {
    binary = TBinaryProtocol,
    compact = TCompactProtocol,
    json = TJSONProtocol,
  }
  assert(protocols[opt.protocol] ~= nil)
  local protocol = protocols[opt.protocol]:new{
    trans = transport
  }
  assert(protocol, 'Failed to create binary protocol')

  client = ThriftTestClient:new{
    protocol = protocol
  }
  assert(client, 'Failed to create client')

  -- Open the transport
  local status, _ = pcall(transport.open, transport)
  assert(status, 'Failed to connect to server')

  -- String
  assertEqual(client:testString('lala'),  'lala',  'Failed testString')
  assertEqual(client:testString('wahoo'), 'wahoo', 'Failed testString')

  -- Bool
  assertEqual(client:testBool(true), true, 'Failed testBool true')
  assertEqual(client:testBool(false), false, 'Failed testBool false')

  -- Byte
  assertEqual(client:testByte(0x01), 1,    'Failed testByte 1')
  assertEqual(client:testByte(0x40), 64,   'Failed testByte 2')
  assertEqual(client:testByte(0x7f), 127,  'Failed testByte 3')
  assertEqual(client:testByte(0x80), -128, 'Failed testByte 4')
  assertEqual(client:testByte(0xbf), -65,  'Failed testByte 5')
  assertEqual(client:testByte(0xff), -1,   'Failed testByte 6')
  assertEqual(client:testByte(128), -128,  'Failed testByte 7')
  assertEqual(client:testByte(255), -1,    'Failed testByte 8')

  -- I32
  assertEqual(client:testI32(0x00000001), 1,           'Failed testI32 1')
  assertEqual(client:testI32(0x40000000), 1073741824,  'Failed testI32 2')
  assertEqual(client:testI32(0x7fffffff), 2147483647,  'Failed testI32 3')
  assertEqual(client:testI32(0x80000000), -2147483648, 'Failed testI32 4')
  assertEqual(client:testI32(0xbfffffff), -1073741825, 'Failed testI32 5')
  assertEqual(client:testI32(0xffffffff), -1,          'Failed testI32 6')
  assertEqual(client:testI32(2147483648), -2147483648, 'Failed testI32 7')
  assertEqual(client:testI32(4294967295), -1,          'Failed testI32 8')

  -- I64 (lua only supports 16 decimal precision so larger numbers are
  -- initialized by their string value)
  local long = liblualongnumber.new
  assertEqual(client:testI64(long(0x0000000000000001)),
                   long(1),
                   'Failed testI64 1')
  assertEqual(client:testI64(long(0x4000000000000000)),
                   long(4611686018427387904),
                   'Failed testI64 2')
  assertEqual(client:testI64(long('0x7fffffffffffffff')),
                   long('9223372036854775807'),
                   'Failed testI64 3')
  assertEqual(client:testI64(long(0x8000000000000000)),
                   long(-9223372036854775808),
                   'Failed testI64 4')
  assertEqual(client:testI64(long('0xbfffffffffffffff')),
                   long('-4611686018427387905'),
                   'Failed testI64 5')
  assertEqual(client:testI64(long('0xffffffffffffffff')),
                   long(-1),
                   'Failed testI64 6')

  -- Double
  assertEqual(
      client:testDouble(1.23456789), 1.23456789, 'Failed testDouble 1')
  assertEqual(
      client:testDouble(0.123456789), 0.123456789, 'Failed testDouble 2')
  assertEqual(
      client:testDouble(0.123456789), 0.123456789, 'Failed testDouble 3')

  -- TODO testBinary() ...
	  
  -- Accuracy of 16 decimal digits (rounds)
  local a, b = 1.12345678906666663, 1.12345678906666661
  assertEqual(a, b)
  assertEqual(client:testDouble(a), b, 'Failed testDouble 5')

  -- Struct
  local o = Xtruct:new{
    string_thing = 'Zero',
    byte_thing = 1,
    i32_thing = -3,
    i64_thing = long(-5)
  }
  local r = client:testStruct(o)
  assertEqual(o.string_thing, r.string_thing, 'Failed testStruct 1')
  assertEqual(o.byte_thing, r.byte_thing, 'Failed testStruct 2')
  assertEqual(o.i32_thing, r.i32_thing, 'Failed testStruct 3')
  assertEqual(o.i64_thing, r.i64_thing, 'Failed testStruct 4')

  -- oneway
  client:testOneway(3)

  -- TODO add list map set exception etc etc
end

testBasicClient(arg)
teardown()
thrift-0.16.0/test/lua/test_basic_server.lua000066400000000000000000000070421420101504100210360ustar00rootroot00000000000000-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at

--   http://www.apache.org/licenses/LICENSE-2.0

-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.

require('ThriftTest_ThriftTest')
require('TSocket')
require('TBufferedTransport')
require('TFramedTransport')
require('THttpTransport')
require('TCompactProtocol')
require('TJsonProtocol')
require('TBinaryProtocol')
require('TServer')
require('liblualongnumber')

--------------------------------------------------------------------------------
-- Handler
TestHandler = ThriftTestIface:new{}

-- Stops the server
function TestHandler:testVoid()
end

function TestHandler:testString(str)
  return str
end

function TestHandler:testBool(bool)
  return bool
end

function TestHandler:testByte(byte)
  return byte
end

function TestHandler:testI32(i32)
  return i32
end

function TestHandler:testI64(i64)
  return i64
end

function TestHandler:testDouble(d)
  return d
end

function TestHandler:testBinary(by)
  return by
end

function TestHandler:testStruct(thing)
  return thing
end

function TestHandler:testOneway(secondsToSleep)
  print("testOneway secondsToSleep:", secondsToSleep)
end

--------------------------------------------------------------------------------
-- Test
local server

function teardown()
  if server then
    server:close()
  end
end

function parseArgs(rawArgs)
  local opt = {
    protocol='binary',
    transport='buffered',
    port='9090',
  }
  for i, str in pairs(rawArgs) do
    if i > 0 then
      k, v = string.match(str, '--(%w+)=(%w+)')
      assert(opt[k] ~= nil, 'Unknown argument')
      opt[k] = v
    end
  end
  return opt
end

function testBasicServer(rawArgs)
  local opt = parseArgs(rawArgs)
  -- Handler & Processor
  local handler = TestHandler:new{}
  assert(handler, 'Failed to create handler')
  local processor = ThriftTestProcessor:new{
    handler = handler
  }
  assert(processor, 'Failed to create processor')

  -- Server Socket
  local socket = TServerSocket:new{
    port = opt.port
  }
  assert(socket, 'Failed to create server socket')

  -- Transport & Factory
  local transports = {
    buffered = TBufferedTransportFactory,
    framed = TFramedTransportFactory,
    http = THttpTransportFactory,
  }
  assert(transports[opt.transport], 'Failed to create framed transport factory')
  local trans_factory = transports[opt.transport]:new{}
  local protocols = {
    binary = TBinaryProtocolFactory,
    compact = TCompactProtocolFactory,
    json = TJSONProtocolFactory,
  }
  local prot_factory = protocols[opt.protocol]:new{}
  assert(prot_factory, 'Failed to create binary protocol factory')

  -- Simple Server
  server = TSimpleServer:new{
    processor = processor,
    serverTransport = socket,
    transportFactory = trans_factory,
    protocolFactory = prot_factory
  }
  assert(server, 'Failed to create server')
  server:setExceptionHandler(function (err) error(err) end)

  -- Serve
  server:serve()
  server = nil
end

testBasicServer(arg)
teardown()
thrift-0.16.0/test/netstd/000077500000000000000000000000001420101504100153425ustar00rootroot00000000000000thrift-0.16.0/test/netstd/Client/000077500000000000000000000000001420101504100165605ustar00rootroot00000000000000thrift-0.16.0/test/netstd/Client/Client.csproj000066400000000000000000000055311420101504100212240ustar00rootroot00000000000000
  

  
    net6.0
    9.0
    Client
    Client
    Exe
    0.16.0.0
    false
    false
    false
    false
    false
    false
    enable
  

  
    
    
    
    
  

  
    
  

  
    
      
    
    
    
    
  

thrift-0.16.0/test/netstd/Client/Performance/000077500000000000000000000000001420101504100210215ustar00rootroot00000000000000thrift-0.16.0/test/netstd/Client/Performance/PerformanceTests.cs000066400000000000000000000132061420101504100246360ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

using System;
using System.Collections.Generic;
using System.Text;
using ThriftTest;
using Thrift.Collections;
using Thrift;
using Thrift.Protocol;
using System.Threading;
using Thrift.Transport.Client;
using System.Threading.Tasks;
using System.Diagnostics;
using Thrift.Transport;

#pragma warning disable CS1998  // no await in async method

namespace Client.Tests
{
    public class PerformanceTests
    {
        private CancellationTokenSource Cancel = new();
        private CrazyNesting? Testdata;
        private TMemoryBufferTransport? MemBuffer;
        private TTransport? Transport;
        private LayeredChoice Layered;
        private readonly TConfiguration Configuration = new();

        internal static async Task Execute()
        {
            var instance = new PerformanceTests();
            instance.ProtocolPeformanceTestAsync().Wait();

            // debug only
            if (Debugger.IsAttached)
            {
                Console.Write("Hit ENTER ...");
                Console.ReadKey();
            }

            return 0;
        }

        public PerformanceTests()
        {
            Configuration.MaxFrameSize = Configuration.MaxMessageSize;  // default frame size is too small for this test
        }

        private async Task ProtocolPeformanceTestAsync()
        {
            Console.WriteLine("Setting up for ProtocolPeformanceTestAsync ...");
            Cancel = new CancellationTokenSource();
            Testdata = TestDataFactory.CreateCrazyNesting();

            foreach (var layered in Enum.GetValues(typeof(LayeredChoice)))
            {
                Layered = (LayeredChoice)layered;
                await RunTestAsync(async (bool b) => { return await GenericProtocolFactory(b); });
                await RunTestAsync(async (bool b) => { return await GenericProtocolFactory(b); });
                await RunTestAsync(async (bool b) => { return await GenericProtocolFactory(b); });
            }
        }

        private async Task GenericProtocolFactory(bool forWrite)
            where T : TProtocol
        {
            var oldTrans = Transport;
            try
            {
                Transport = null;

                // read happens after write here, so let's take over the written bytes
                if (forWrite)
                    MemBuffer = new TMemoryBufferTransport(Configuration);  
                else
                    MemBuffer = new TMemoryBufferTransport(MemBuffer?.GetBuffer(), Configuration);

                //  layered transports anyone?
                Transport = Layered switch
                {
                    LayeredChoice.None => MemBuffer,
                    LayeredChoice.Framed => new TFramedTransport(MemBuffer),
                    LayeredChoice.Buffered => new TBufferedTransport(MemBuffer),
                    _ => throw new Exception("Unhandled case " + Layered.ToString()),
                };
                ;

                if (!Transport.IsOpen)
                    Transport.OpenAsync().Wait();

                if (Activator.CreateInstance(typeof(T), Transport) is T instance)
                    return instance;

                throw new Exception("Unexpected.");
            }
            finally
            {
                oldTrans?.Dispose();
            }
        }

        private string GetProtocolTransportName(TProtocol proto)
        {
            var name = Transport?.GetType().Name;
            var bufnm = MemBuffer?.GetType().Name;
            if ((name is null) || name.Equals(bufnm))
                name = string.Empty;
            else
                name = " + " + name;

            name = proto.GetType().Name + name;
            return name;
        }


        private async Task RunTestAsync(Func> factory)
        {
            var stop = new Stopwatch();

            if (Testdata is null)
                throw new Exception("unexpected internal state");

            var proto = await factory(true);
            if (Transport is null)
                throw new Exception("unexpected internal state");
            stop.Start();
            await Testdata.WriteAsync(proto, Cancel.Token);
            await Transport.FlushAsync(Cancel.Token);
            stop.Stop();
            Console.WriteLine("RunTestAsync({0}): write = {1} msec",
                GetProtocolTransportName(proto),
                stop.ElapsedMilliseconds);

            var restored = new CrazyNesting();
            proto = await factory(false);
            if (Transport is null)
                throw new Exception("unexpected internal state");
            stop.Start();
            await restored.ReadAsync(proto, Cancel.Token);
            stop.Stop();
            Console.WriteLine("RunTestAsync({0}): read = {1} msec",
                GetProtocolTransportName(proto),
                stop.ElapsedMilliseconds);
        }

    }
}
thrift-0.16.0/test/netstd/Client/Performance/TestDataFactory.cs000066400000000000000000000127741420101504100244240ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

using System;
using System.Collections.Generic;
using System.Text;
using ThriftTest;
using Thrift.Collections;

namespace Client.Tests
{
    
    static class TestDataFactory
    {
        public static CrazyNesting? CreateCrazyNesting(int count = 10)
        {
            if (count <= 0)
                return null;

            return new CrazyNesting()
            {
                Binary_field = CreateBytesArray(count),
                List_field = CreateListField(count),
                Set_field = CreateSetField(count),
                String_field = string.Format("data level {0}", count)
            };
        }

        private static THashSet CreateSetField(int count)
        {
            var retval = new THashSet();
            for (var i = 0; i < count; ++i)
                retval.Add(CreateInsanity(count));
            return retval;
        }

        private static Insanity CreateInsanity(int count)
        {
            return new Insanity()
            {
                UserMap = CreateUserMap(count),
                Xtructs = CreateXtructs(count)
            };
        }

        private static List CreateXtructs(int count)
        {
            var retval = new List();
            for (var i = 0; i < count; ++i)
                retval.Add(CreateXtruct(count));
            return retval;
        }

        private static Xtruct CreateXtruct(int count)
        {
            return new Xtruct()
            {
                Byte_thing = (sbyte)(count % 128),
                I32_thing = count,
                I64_thing = count,
                String_thing = string.Format("data level {0}", count)
            };
        }

        private static Dictionary CreateUserMap(int count)
        {
            var retval = new Dictionary
            {
                { Numberz.ONE, count },
                { Numberz.TWO, count },
                { Numberz.THREE, count },
                { Numberz.FIVE, count },
                { Numberz.SIX, count },
                { Numberz.EIGHT, count }
            };
            return retval;
        }

        private static List, Dictionary>>>>> CreateListField(int count)
        {
            var retval = new List, Dictionary>>>>>();
            for (var i = 0; i < count; ++i)
                retval.Add(CreateListFieldData(count));
            return retval;
        }

        private static Dictionary, Dictionary>>>> CreateListFieldData(int count)
        {
            var retval = new Dictionary, Dictionary>>>>();
            for (var i = 0; i < count; ++i)
                retval.Add( CreateIntHashSet(count), CreateListFieldDataDict(count));
            return retval;
        }

        private static THashSet CreateIntHashSet(int count)
        {
            var retval = new THashSet();
            for (var i = 0; i < count; ++i)
                retval.Add(i);
            return retval;
        }

        private static Dictionary>>> CreateListFieldDataDict(int count)
        {
            var retval = new Dictionary>>>();
            for (var i = 0; i < count; ++i)
                retval.Add(i, CreateListFieldDataDictValue(count));
            return retval;
        }

        private static THashSet>> CreateListFieldDataDictValue(int count)
        {
            var retval = new THashSet>>();
            for (var i = 0; i < count; ++i)
                retval.Add( CreateListFieldDataDictValueList(count));
            return retval;
        }

        private static List> CreateListFieldDataDictValueList(int count)
        {
            var retval = new List>();
            for (var i = 0; i < count; ++i)
                retval.Add(CreateListFieldDataDictValueListDict(count));
            return retval;
        }

        private static Dictionary CreateListFieldDataDictValueListDict(int count)
        {
            return new Dictionary
            {
                { CreateInsanity(count), string.Format("data level {0}", count) }
            };
        }

        private static byte[] CreateBytesArray(int count)
        {
            var retval = new byte[count];
            for (var i = 0; i < count; ++i)
                retval[i] = (byte)(i % 0xFF);
            return retval;
        }
    }
}
thrift-0.16.0/test/netstd/Client/Program.cs000066400000000000000000000050671420101504100205260ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ThriftTest;

namespace Client
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                try
                {
                    Console.SetBufferSize(Console.BufferWidth, 4096);
                }
                catch (Exception)
                {
                    Console.WriteLine("Failed to grow scroll-back buffer");
                }
            }

            // run whatever mode is choosen, default to test impl
            var argslist = new List(args);
            switch (argslist.FirstOrDefault())
            {
                case "client":  // crosstest wants to pass this, so just emit a hint and ignore
                    Console.WriteLine("Hint: The 'client' argument is no longer required.");
                    argslist.RemoveAt(0);
                    return await TestClient.Execute(argslist);
                case "--performance":
                case "--performance-test":
                    return await Tests.PerformanceTests.Execute();
                case "--help":
                    PrintHelp();
                    return 0;
                default:
                    return await TestClient.Execute(argslist);
            }
        }

        private static void PrintHelp()
        {
            Console.WriteLine("Usage:");
            Console.WriteLine("  Client  [options]");
            Console.WriteLine("  Client  --performance-test");
            Console.WriteLine("  Client  --help");
            Console.WriteLine("");

            TestClient.PrintOptionsHelp();
        }
    }
}
thrift-0.16.0/test/netstd/Client/Properties/000077500000000000000000000000001420101504100207145ustar00rootroot00000000000000thrift-0.16.0/test/netstd/Client/Properties/AssemblyInfo.cs000066400000000000000000000034301420101504100236360ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.

[assembly: AssemblyTitle("Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The Apache Software Foundation")]
[assembly: AssemblyProduct("Thrift")]
[assembly: AssemblyCopyright("The Apache Software Foundation")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.

[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM

[assembly: Guid("B0C13DA0-3117-4844-8AE8-B1775E46223D")]

thrift-0.16.0/test/netstd/Client/TestClient.cs000066400000000000000000001100021420101504100211570ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

#pragma warning disable IDE0066 // switch expression
#pragma warning disable IDE0057 // substring
#pragma warning disable CS1998  // no await in async method

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Thrift;
using Thrift.Collections;
using Thrift.Protocol;
using Thrift.Transport;
using Thrift.Transport.Client;

namespace ThriftTest
{
    internal enum ProtocolChoice
    {
        Binary,
        Compact,
        Json
    }

    // it does not make much sense to use buffered when we already use framed
    internal enum LayeredChoice
    {
        None,
        Buffered,
        Framed
    }

    internal enum TransportChoice
    {
        Socket,
        TlsSocket,
        Http,
        NamedPipe
    }

    public class TestClient
    {
        private class TestParams
        {
            public int numIterations = 1;
            public string host = "localhost";
            public int port = 9090;
            public int numThreads = 1;
            public string url = string.Empty;
            public string pipe = string.Empty;
            public LayeredChoice layered = LayeredChoice.None;
            public ProtocolChoice protocol = ProtocolChoice.Binary;
            public TransportChoice transport = TransportChoice.Socket;
            private readonly TConfiguration Configuration = new();

            internal void Parse(List args)
            {
                for (var i = 0; i < args.Count; ++i)
                {
                    if (args[i] == "-u")
                    {
                        url = args[++i];
                        transport = TransportChoice.Http;
                    }
                    else if (args[i] == "-n")
                    {
                        numIterations = Convert.ToInt32(args[++i]);
                    }
                    else if (args[i].StartsWith("--pipe="))
                    {
                        pipe = args[i].Substring(args[i].IndexOf("=") + 1);
                        transport = TransportChoice.NamedPipe;
                    }
                    else if (args[i].StartsWith("--host="))
                    {
                        // check there for ipaddress
                        host = args[i].Substring(args[i].IndexOf("=") + 1);
                        if (transport != TransportChoice.TlsSocket)
                            transport = TransportChoice.Socket;
                    }
                    else if (args[i].StartsWith("--port="))
                    {
                        port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
                        if (transport != TransportChoice.TlsSocket)
                            transport = TransportChoice.Socket;
                    }
                    else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
                    {
                        layered = LayeredChoice.Buffered;
                    }
                    else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
                    {
                        layered = LayeredChoice.Framed;
                    }
                    else if (args[i] == "-t")
                    {
                        numThreads = Convert.ToInt32(args[++i]);
                    }
                    else if (args[i] == "--binary" || args[i] == "--protocol=binary")
                    {
                        protocol = ProtocolChoice.Binary;
                    }
                    else if (args[i] == "--compact" || args[i] == "--protocol=compact")
                    {
                        protocol = ProtocolChoice.Compact;
                    }
                    else if (args[i] == "--json" || args[i] == "--protocol=json")
                    {
                        protocol = ProtocolChoice.Json;
                    }
                    else if (args[i] == "--ssl")
                    {
                        transport = TransportChoice.TlsSocket;
                    }
                    else if (args[i] == "--help")
                    {
                        PrintOptionsHelp();
                        return;
                    }
                    else
                    {
                        Console.WriteLine("Invalid argument: {0}", args[i]);
                        PrintOptionsHelp();
                        return;
                    }
                }

                switch (transport)
                {
                    case TransportChoice.Socket:
                        Console.WriteLine("Using socket transport");
                        break;
                    case TransportChoice.TlsSocket:
                        Console.WriteLine("Using encrypted transport");
                        break;
                    case TransportChoice.Http:
                        Console.WriteLine("Using HTTP transport");
                        break;
                    case TransportChoice.NamedPipe:
                        Console.WriteLine("Using named pipes transport");
                        break;
                    default:  // unhandled case
                        Debug.Assert(false);
                        break;
                }

                switch (layered)
                {
                    case LayeredChoice.Framed:
                        Console.WriteLine("Using framed transport");
                        break;
                    case LayeredChoice.Buffered:
                        Console.WriteLine("Using buffered transport");
                        break;
                    default:  // unhandled case?
                        Debug.Assert(layered == LayeredChoice.None);
                        break;
                }

                switch (protocol)
                {
                    case ProtocolChoice.Binary:
                        Console.WriteLine("Using binary protocol");
                        break;
                    case ProtocolChoice.Compact:
                        Console.WriteLine("Using compact protocol");
                        break;
                    case ProtocolChoice.Json:
                        Console.WriteLine("Using JSON protocol");
                        break;
                    default:  // unhandled case?
                        Debug.Assert(false);
                        break;
                }
            }

            private static X509Certificate2 GetClientCert()
            {
                var clientCertName = "client.p12";
                var possiblePaths = new List
                {
                    "../../../keys/",
                    "../../keys/",
                    "../keys/",
                    "keys/",
                };

                var existingPath = string.Empty;
                foreach (var possiblePath in possiblePaths)
                {
                    var path = Path.GetFullPath(possiblePath + clientCertName);
                    if (File.Exists(path))
                    {
                        existingPath = path;
                        break;
                    }
                }

                if (string.IsNullOrEmpty(existingPath))
                {
                    throw new FileNotFoundException($"Cannot find file: {clientCertName}");
                }

                var cert = new X509Certificate2(existingPath, "thrift");

                return cert;
            }

            public TTransport CreateTransport()
            {
                // endpoint transport
                TTransport trans;
                switch (transport)
                {
                    case TransportChoice.Http:
                        Debug.Assert(url != null);
                        trans = new THttpTransport(new Uri(url), Configuration);
                        break;

                    case TransportChoice.NamedPipe:
                        Debug.Assert(pipe != null);
                        trans = new TNamedPipeTransport(pipe,Configuration);
                        break;

                    case TransportChoice.TlsSocket:
                        var cert = GetClientCert();
                        if (cert == null || !cert.HasPrivateKey)
                        {
                            throw new InvalidOperationException("Certificate doesn't contain private key");
                        }

                        trans = new TTlsSocketTransport(host, port, Configuration, 0,
                            cert,
                            (sender, certificate, chain, errors) => true,
                            null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12);
                        break;

                    case TransportChoice.Socket:
                    default:
                        trans = new TSocketTransport(host, port, Configuration);
                        break;
                }


                // layered transport
                switch (layered)
                {
                    case LayeredChoice.Buffered:
                        trans = new TBufferedTransport(trans);
                        break;
                    case LayeredChoice.Framed:
                        trans = new TFramedTransport(trans);
                        break;
                    default:
                        Debug.Assert(layered == LayeredChoice.None);
                        break;
                }

                return trans;
            }

            public TProtocol CreateProtocol(TTransport transport)
            {
                switch (protocol)
                {
                    case ProtocolChoice.Compact:
                        return new TCompactProtocol(transport);
                    case ProtocolChoice.Json:
                        return new TJsonProtocol(transport);
                    case ProtocolChoice.Binary:
                    default:
                        return new TBinaryProtocol(transport);
                }
            }
        }


        private const int ErrorBaseTypes = 1;
        private const int ErrorStructs = 2;
        private const int ErrorContainers = 4;
        private const int ErrorExceptions = 8;
        private const int ErrorUnknown = 64;

        private class ClientTest
        {
            private readonly TTransport transport;
            private readonly ThriftTest.Client client;
            private readonly int numIterations;
            private bool done;

            public int ReturnCode { get; set; }

            public ClientTest(TestParams param)
            {
                transport = param.CreateTransport();
                client = new ThriftTest.Client(param.CreateProtocol(transport));
                numIterations = param.numIterations;
            }

            public async Task Execute()
            {
                if (done)
                {
                    Console.WriteLine("Execute called more than once");
                    throw new InvalidOperationException();
                }

                for (var i = 0; i < numIterations; i++)
                {
                    try
                    {
                        if (!transport.IsOpen)
                            await transport.OpenAsync(MakeTimeoutToken());
                    }
                    catch (TTransportException ex)
                    {
                        Console.WriteLine("*** FAILED ***");
                        Console.WriteLine("Connect failed: " + ex.Message);
                        ReturnCode |= ErrorUnknown;
                        Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                        continue;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("*** FAILED ***");
                        Console.WriteLine("Connect failed: " + ex.Message);
                        ReturnCode |= ErrorUnknown;
                        Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                        continue;
                    }

                    try
                    {
                        ReturnCode |= await ExecuteClientTest(client);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("*** FAILED ***");
                        Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                        ReturnCode |= ErrorUnknown;
                    }
                }
                try
                {
                    transport.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error while closing transport");
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                }
                done = true;
            }
        }

        internal static void PrintOptionsHelp()
        {
            Console.WriteLine("Client options:");
            Console.WriteLine("  -u ");
            Console.WriteLine("  -t <# of threads to run>        default = 1");
            Console.WriteLine("  -n <# of iterations>            per thread");
            Console.WriteLine("  --pipe=");
            Console.WriteLine("  --host=");
            Console.WriteLine("  --port=");
            Console.WriteLine("  --transport=    one of buffered,framed  (defaults to none)");
            Console.WriteLine("  --protocol=      one of compact,json  (defaults to binary)");
            Console.WriteLine("  --ssl");
            Console.WriteLine();
        }

        public static async Task Execute(List args)
        {
            try
            {
                var param = new TestParams();

                try
                {
                    param.Parse(args);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("*** FAILED ***");
                    Console.WriteLine("Error while parsing arguments");
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                    return ErrorUnknown;
                }

                var tests = Enumerable.Range(0, param.numThreads).Select(_ => new ClientTest(param)).ToArray();

                //issue tests on separate threads simultaneously
                var start = DateTime.Now;
                var tasks = tests.Select(test => test.Execute()).ToArray();
                Task.WaitAll(tasks);
                Console.WriteLine("Total time: " + (DateTime.Now - start));
                Console.WriteLine();
                return tests.Select(t => t.ReturnCode).Aggregate((r1, r2) => r1 | r2);
            }
            catch (Exception outerEx)
            {
                Console.WriteLine("*** FAILED ***");
                Console.WriteLine("Unexpected error");
                Console.WriteLine(outerEx.Message + "\n" + outerEx.StackTrace);
                return ErrorUnknown;
            }
        }

        public static string BytesToHex(byte[] data)
        {
            return BitConverter.ToString(data).Replace("-", string.Empty);
        }


        public enum BinaryTestSize
        {
            Empty,           // Edge case: the zero-length empty binary
            Normal,          // Fairly small array of usual size (256 bytes)
            Large,           // Large writes/reads may cause range check errors
            PipeWriteLimit,  // Windows Limit: Pipe write operations across a network are limited to 65,535 bytes per write.
            FifteenMB        // that's quite a bit of data
        };

        public static byte[] PrepareTestData(bool randomDist, BinaryTestSize testcase)
        {
            int amount;
            switch (testcase)
            {
                case BinaryTestSize.Empty:
                    amount = 0;
                    break;
                case BinaryTestSize.Normal:
                    amount = 0x100;
                    break;
                case BinaryTestSize.Large:
                    amount = 0x8000 + 128;
                    break;
                case BinaryTestSize.PipeWriteLimit:
                    amount = 0xFFFF + 128;
                    break;
                case BinaryTestSize.FifteenMB:
                    amount = 15 * 1024 * 1024;
                    break;
                default:
                    throw new ArgumentException("invalid argument",nameof(testcase));
            }

            var retval = new byte[amount];

            // linear distribution, unless random is requested
            if (!randomDist)
            {
                for (var i = 0; i < retval.Length; ++i)
                {
                    retval[i] = (byte)i;
                }
                return retval;
            }

            // random distribution
            var rnd = new Random();
            for (var i = 1; i < retval.Length; ++i)
            {
                retval[i] = (byte)rnd.Next(0x100);
            }
            return retval;
        }

        private static CancellationToken MakeTimeoutToken(int msec = 5000)
        {
            var token = new CancellationTokenSource(msec);
            return token.Token;
        }

        public static async Task ExecuteClientTest(ThriftTest.Client client)
        {
            var returnCode = 0;

            Console.Write("testVoid()");
            await client.testVoid(MakeTimeoutToken());
            Console.WriteLine(" = void");

            Console.Write("testString(\"Test\")");
            var s = await client.testString("Test", MakeTimeoutToken());
            Console.WriteLine(" = \"" + s + "\"");
            if ("Test" != s)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }

            Console.Write("testBool(true)");
            var t = await client.testBool((bool)true, MakeTimeoutToken());
            Console.WriteLine(" = " + t);
            if (!t)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }
            Console.Write("testBool(false)");
            var f = await client.testBool((bool)false, MakeTimeoutToken());
            Console.WriteLine(" = " + f);
            if (f)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }

            Console.Write("testByte(1)");
            var i8 = await client.testByte((sbyte)1, MakeTimeoutToken());
            Console.WriteLine(" = " + i8);
            if (1 != i8)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }

            Console.Write("testI32(-1)");
            var i32 = await client.testI32(-1, MakeTimeoutToken());
            Console.WriteLine(" = " + i32);
            if (-1 != i32)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }

            Console.Write("testI64(-34359738368)");
            var i64 = await client.testI64(-34359738368, MakeTimeoutToken());
            Console.WriteLine(" = " + i64);
            if (-34359738368 != i64)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }

            // TODO: Validate received message
            Console.Write("testDouble(5.325098235)");
            var dub = await client.testDouble(5.325098235, MakeTimeoutToken());
            Console.WriteLine(" = " + dub);
            if (5.325098235 != dub)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }
            Console.Write("testDouble(-0.000341012439638598279)");
            dub = await client.testDouble(-0.000341012439638598279, MakeTimeoutToken());
            Console.WriteLine(" = " + dub);
            if (-0.000341012439638598279 != dub)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }

            // testBinary()
            foreach(BinaryTestSize binTestCase in Enum.GetValues(typeof(BinaryTestSize)))
            {
                var binOut = PrepareTestData(true, binTestCase);

                Console.Write("testBinary({0} bytes)", binOut.Length);
                try
                {
                    var binIn = await client.testBinary(binOut, MakeTimeoutToken());
                    Console.WriteLine(" = {0} bytes", binIn.Length);
                    if (binIn.Length != binOut.Length)
                    {
                        Console.WriteLine("*** FAILED ***");
                        returnCode |= ErrorBaseTypes;
                    }
                    for (var ofs = 0; ofs < Math.Min(binIn.Length, binOut.Length); ++ofs)
                    {
                        if (binIn[ofs] != binOut[ofs])
                        {
                            Console.WriteLine("*** FAILED ***");
                            returnCode |= ErrorBaseTypes;
                        }
                    }
                }
                catch (Thrift.TApplicationException ex)
                {
                    Console.WriteLine("*** FAILED ***");
                    returnCode |= ErrorBaseTypes;
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                }
            }

            // CrazyNesting
            Console.WriteLine("Test CrazyNesting");
            var one = new CrazyNesting();
            var two = new CrazyNesting();
            one.String_field = "crazy";
            two.String_field = "crazy";
            one.Binary_field = new byte[] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
            two.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
            if (typeof(CrazyNesting).GetMethod("Equals")?.DeclaringType == typeof(CrazyNesting))
            {
                if (!one.Equals(two))
                {
                    Console.WriteLine("*** FAILED ***");
                    returnCode |= ErrorContainers;
                }
            }

            // TODO: Validate received message
            Console.Write("testStruct({\"Zero\", 1, -3, -5})");
            var o = new Xtruct
            {
                String_thing = "Zero",
                Byte_thing = (sbyte)1,
                I32_thing = -3,
                I64_thing = -5
            };
            var i = await client.testStruct(o, MakeTimeoutToken());
            Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}");

            // TODO: Validate received message
            Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})");
            var o2 = new Xtruct2
            {
                Byte_thing = (sbyte)1,
                Struct_thing = o,
                I32_thing = 5
            };
            var i2 = await client.testNest(o2, MakeTimeoutToken());
            i = i2.Struct_thing;
            Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");

            var mapout = new Dictionary();
            for (var j = 0; j < 5; j++)
            {
                mapout[j] = j - 10;
            }
            Console.Write("testMap({");
            Console.Write(string.Join(", ", mapout.Select((pair) => { return pair.Key + " => " + pair.Value; })));
            Console.Write("})");

            var mapin = await client.testMap(mapout, MakeTimeoutToken());

            Console.Write(" = {");
            Console.Write(string.Join(", ", mapin.Select((pair) => { return pair.Key + " => " + pair.Value; })));
            Console.WriteLine("}");

            // TODO: Validate received message
            var listout = new List();
            for (var j = -2; j < 3; j++)
            {
                listout.Add(j);
            }
            Console.Write("testList({");
            Console.Write(string.Join(", ", listout));
            Console.Write("})");

            var listin = await client.testList(listout, MakeTimeoutToken());

            Console.Write(" = {");
            Console.Write(string.Join(", ", listin));
            Console.WriteLine("}");

            //set
            // TODO: Validate received message
            var setout = new THashSet();
            for (var j = -2; j < 3; j++)
            {
                setout.Add(j);
            }
            Console.Write("testSet({");
            Console.Write(string.Join(", ", setout));
            Console.Write("})");

            var setin = await client.testSet(setout, MakeTimeoutToken());

            Console.Write(" = {");
            Console.Write(string.Join(", ", setin));
            Console.WriteLine("}");


            Console.Write("testEnum(ONE)");
            var ret = await client.testEnum(Numberz.ONE, MakeTimeoutToken());
            Console.WriteLine(" = " + ret);
            if (Numberz.ONE != ret)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorStructs;
            }

            Console.Write("testEnum(TWO)");
            ret = await client.testEnum(Numberz.TWO, MakeTimeoutToken());
            Console.WriteLine(" = " + ret);
            if (Numberz.TWO != ret)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorStructs;
            }

            Console.Write("testEnum(THREE)");
            ret = await client.testEnum(Numberz.THREE, MakeTimeoutToken());
            Console.WriteLine(" = " + ret);
            if (Numberz.THREE != ret)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorStructs;
            }

            Console.Write("testEnum(FIVE)");
            ret = await client.testEnum(Numberz.FIVE, MakeTimeoutToken());
            Console.WriteLine(" = " + ret);
            if (Numberz.FIVE != ret)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorStructs;
            }

            Console.Write("testEnum(EIGHT)");
            ret = await client.testEnum(Numberz.EIGHT, MakeTimeoutToken());
            Console.WriteLine(" = " + ret);
            if (Numberz.EIGHT != ret)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorStructs;
            }

            Console.Write("testTypedef(309858235082523)");
            var uid = await client.testTypedef(309858235082523L, MakeTimeoutToken());
            Console.WriteLine(" = " + uid);
            if (309858235082523L != uid)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorStructs;
            }

            // TODO: Validate received message
            Console.Write("testMapMap(1)");
            var mm = await client.testMapMap(1, MakeTimeoutToken());
            Console.Write(" = {");
            foreach (var key in mm.Keys)
            {
                Console.Write(key + " => {");
                var m2 = mm[key];
                foreach (var k2 in m2.Keys)
                {
                    Console.Write(k2 + " => " + m2[k2] + ", ");
                }
                Console.Write("}, ");
            }
            Console.WriteLine("}");

            // TODO: Validate received message
            var insane = new Insanity
            {
                UserMap = new Dictionary
                {
                    [Numberz.FIVE] = 5000L
                }
            };
            var truck = new Xtruct
            {
                String_thing = "Truck",
                Byte_thing = (sbyte)8,
                I32_thing = 8,
                I64_thing = 8
            };
            insane.Xtructs = new List
            {
                truck
            };
            Console.Write("testInsanity()");
            var whoa = await client.testInsanity(insane, MakeTimeoutToken());
            Console.Write(" = {");
            foreach (var key in whoa.Keys)
            {
                var val = whoa[key];
                Console.Write(key + " => {");

                foreach (var k2 in val.Keys)
                {
                    var v2 = val[k2];

                    Console.Write(k2 + " => {");
                    var userMap = v2.UserMap;

                    Console.Write("{");
                    if (userMap != null)
                    {
                        foreach (var k3 in userMap.Keys)
                        {
                            Console.Write(k3 + " => " + userMap[k3] + ", ");
                        }
                    }
                    else
                    {
                        Console.Write("null");
                    }
                    Console.Write("}, ");

                    var xtructs = v2.Xtructs;

                    Console.Write("{");
                    if (xtructs != null)
                    {
                        foreach (var x in xtructs)
                        {
                            Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, ");
                        }
                    }
                    else
                    {
                        Console.Write("null");
                    }
                    Console.Write("}");

                    Console.Write("}, ");
                }
                Console.Write("}, ");
            }
            Console.WriteLine("}");

            sbyte arg0 = 1;
            var arg1 = 2;
            var arg2 = long.MaxValue;
            var multiDict = new Dictionary
            {
                [1] = "one"
            };

            var tmpMultiDict = new List();
            foreach (var pair in multiDict)
                tmpMultiDict.Add(pair.Key +" => "+ pair.Value);

            var arg4 = Numberz.FIVE;
            long arg5 = 5000000;
            Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + ",{" + string.Join(",", tmpMultiDict) + "}," + arg4 + "," + arg5 + ")");
            var multiResponse = await client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5, MakeTimeoutToken());
            Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing
                          + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n");

            try
            {
                Console.WriteLine("testException(\"Xception\")");
                await client.testException("Xception", MakeTimeoutToken());
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
            }
            catch (Xception ex)
            {
                if (ex.ErrorCode != 1001 || ex.Message != "Xception")
                {
                    Console.WriteLine("*** FAILED ***");
                    returnCode |= ErrorExceptions;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }
            try
            {
                Console.WriteLine("testException(\"TException\")");
                await client.testException("TException", MakeTimeoutToken());
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
            }
            catch (Thrift.TException)
            {
                // OK
            }
            catch (Exception ex)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }
            try
            {
                Console.WriteLine("testException(\"ok\")");
                await client.testException("ok", MakeTimeoutToken());
                // OK
            }
            catch (Exception ex)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }

            try
            {
                Console.WriteLine("testMultiException(\"Xception\", ...)");
                await client.testMultiException("Xception", "ignore", MakeTimeoutToken());
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
            }
            catch (Xception ex)
            {
                if (ex.ErrorCode != 1001 || ex.Message != "This is an Xception")
                {
                    Console.WriteLine("*** FAILED ***");
                    returnCode |= ErrorExceptions;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }
            try
            {
                Console.WriteLine("testMultiException(\"Xception2\", ...)");
                await client.testMultiException("Xception2", "ignore", MakeTimeoutToken());
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
            }
            catch (Xception2 ex)
            {
                if (ex.ErrorCode != 2002 || ex.Struct_thing.String_thing != "This is an Xception2")
                {
                    Console.WriteLine("*** FAILED ***");
                    returnCode |= ErrorExceptions;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }
            try
            {
                Console.WriteLine("testMultiException(\"success\", \"OK\")");
                if ("OK" != (await client.testMultiException("success", "OK", MakeTimeoutToken())).String_thing)
                {
                    Console.WriteLine("*** FAILED ***");
                    returnCode |= ErrorExceptions;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorExceptions;
                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
            }

            Console.WriteLine("Test Oneway(1)");
            var sw = new Stopwatch();
            sw.Start();
            await client.testOneway(1, MakeTimeoutToken());
            sw.Stop();
            if (sw.ElapsedMilliseconds > 1000)
            {
                Console.WriteLine("*** FAILED ***");
                returnCode |= ErrorBaseTypes;
            }

            Console.Write("Test Calltime()");
            var times = 50;
            sw.Reset();
            sw.Start();
            var token = MakeTimeoutToken(20000);
            for (var k = 0; k < times; ++k)
                await client.testVoid(token);
            sw.Stop();
            Console.WriteLine(" = {0} ms a testVoid() call", sw.ElapsedMilliseconds / times);
            return returnCode;
        }
    }
}
thrift-0.16.0/test/netstd/Makefile.am000066400000000000000000000021221420101504100173730ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

SUBDIRS = . 

all-local:
	$(DOTNETCORE) build -c Release

precross:
	$(DOTNETCORE) build -c Release

clean-local:
	$(RM) -r Client/bin
	$(RM) -r Server/bin
	$(RM) -r Client/obj
	$(RM) -r Server/obj
	$(RM) -r ThriftTest/ThriftTest

EXTRA_DIST = \
	Client \
	README.md \
	Server \
	ThriftTest.sln \
	build.cmd \
	build.sh
thrift-0.16.0/test/netstd/README.md000066400000000000000000000011231420101504100166160ustar00rootroot00000000000000# Apache Thrift net-core-lib tests

Tests for Thrift client library ported to Microsoft .NET Core 

# Content
- ThriftTest - tests for Thrift library 

# Reused components 
- NET Core SDK 3.1 (LTS)

# How to build on Windows
- Get Thrift IDL compiler executable, add to some folder and add path to this folder into PATH variable
- Open ThriftTest.sln in Visual Studio and build
or 
- Build with scripts

# How to build on Unix
- Ensure you have .NET Core 3.0 SDK installed or use the Ubuntu Xenial docker image
- Follow common build practice for Thrift: bootstrap, configure, and make precross

thrift-0.16.0/test/netstd/Server/000077500000000000000000000000001420101504100166105ustar00rootroot00000000000000thrift-0.16.0/test/netstd/Server/Program.cs000066400000000000000000000045451420101504100205560ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ThriftTest;
using System.Threading.Tasks;

namespace Server
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                try
                {
                    Console.SetBufferSize(Console.BufferWidth, 4096);
                }
                catch (Exception)
                {
                    Console.WriteLine("Failed to grow scroll-back buffer");
                }
            }

            // run whatever mode is choosen, default to test impl
            var argslist = new List(args);
            switch (argslist.FirstOrDefault())
            {
                case "server":  // crosstest wants to pass this, so just emit a hint and ignore
                    Console.WriteLine("Hint: The 'server' argument is no longer required.");
                    argslist.RemoveAt(0);
                    return await TestServer.Execute(argslist);
                case "--help":
                    PrintHelp();
                    return 0;
                default:
                    return await TestServer.Execute(argslist);
            }
        }

        private static void PrintHelp()
        {
            Console.WriteLine("Usage:");
            Console.WriteLine("  Server  [options]");
            Console.WriteLine("  Server  --help");
            Console.WriteLine("");

            ServerParam.PrintOptionsHelp();
        }
    }
}
thrift-0.16.0/test/netstd/Server/Properties/000077500000000000000000000000001420101504100207445ustar00rootroot00000000000000thrift-0.16.0/test/netstd/Server/Properties/AssemblyInfo.cs000066400000000000000000000034301420101504100236660ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.

[assembly: AssemblyTitle("Server")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The Apache Software Foundation")]
[assembly: AssemblyProduct("Thrift")]
[assembly: AssemblyCopyright("The Apache Software Foundation")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.

[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM

[assembly: Guid("B0C13DA0-3117-4844-8AE8-B1775E46223D")]

thrift-0.16.0/test/netstd/Server/Server.csproj000066400000000000000000000057601420101504100213100ustar00rootroot00000000000000
  

  
    net6.0
    9.0
    Server
    Server
    Exe
    0.16.0.0
    false
    false
    false
    false
    false
    false
    enable
  

  
    
    
    
    
    
    
  

  
    
  

  
    
      
    
    
    
    
  

thrift-0.16.0/test/netstd/Server/TestServer.cs000066400000000000000000000611051420101504100212500ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Thrift;
using Thrift.Collections;
using Thrift.Processor;
using Thrift.Protocol;
using Thrift.Server;
using Thrift.Transport;
using Thrift.Transport.Server;

#pragma warning disable IDE0063  // using can be simplified, we don't
#pragma warning disable IDE0057  // substr can be simplified, we don't
#pragma warning disable CS1998   // await missing

namespace ThriftTest
{
    internal enum ProtocolChoice
    {
        Binary,
        Compact,
        Json
    }

    internal enum TransportChoice
    {
        Socket,
        TlsSocket,
        NamedPipe
    }

    internal enum BufferChoice
    {
        None,
        Buffered,
        Framed
    }

    internal enum ServerChoice
    {
        Simple,
        ThreadPool
    }


    internal class ServerParam
    {
        internal BufferChoice buffering = BufferChoice.None;
        internal ProtocolChoice protocol = ProtocolChoice.Binary;
        internal TransportChoice transport = TransportChoice.Socket;
        internal ServerChoice server = ServerChoice.Simple;
        internal int port = 9090;
        internal string pipe = string.Empty;

        internal void Parse(List args)
        {
            for (var i = 0; i < args.Count; i++)
            {
                if (args[i].StartsWith("--pipe="))
                {
                    pipe = args[i].Substring(args[i].IndexOf("=") + 1);
                    transport = TransportChoice.NamedPipe;
                }
                else if (args[i].StartsWith("--port="))
                {
                    port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
                    if(transport != TransportChoice.TlsSocket)
                        transport = TransportChoice.Socket;
                }
                else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
                {
                    buffering = BufferChoice.Buffered;
                }
                else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
                {
                    buffering = BufferChoice.Framed;
                }
                else if (args[i] == "--binary" || args[i] == "--protocol=binary")
                {
                    protocol = ProtocolChoice.Binary;
                }
                else if (args[i] == "--compact" || args[i] == "--protocol=compact")
                {
                    protocol = ProtocolChoice.Compact;
                }
                else if (args[i] == "--json" || args[i] == "--protocol=json")
                {
                    protocol = ProtocolChoice.Json;
                }
                else if (args[i] == "--server-type=simple")
                {
                    server = ServerChoice.Simple;
                }
                else if (args[i] == "--threaded" || args[i] == "--server-type=threaded")
                {
                    throw new NotImplementedException(args[i]);
                }
                else if (args[i] == "--threadpool" || args[i] == "--server-type=threadpool")
                {
                    server = ServerChoice.ThreadPool;
                }
                else if (args[i] == "--prototype" || args[i] == "--processor=prototype")
                {
                    throw new NotImplementedException(args[i]);
                }
                else if (args[i] == "--ssl")
                {
                    transport = TransportChoice.TlsSocket;
                }
                else if (args[i] == "--help")
                {
                    PrintOptionsHelp();
                    return;
                }
                else
                {
                    Console.WriteLine("Invalid argument: {0}", args[i]);
                    PrintOptionsHelp();
                    return;
                }
            }

        }

        internal static void PrintOptionsHelp()
        {
            Console.WriteLine("Server options:");
            Console.WriteLine("  --pipe=");
            Console.WriteLine("  --port=");
            Console.WriteLine("  --transport=    one of buffered,framed  (defaults to none)");
            Console.WriteLine("  --protocol=      one of compact,json  (defaults to binary)");
            Console.WriteLine("  --server-type=            one of threaded,threadpool  (defaults to simple)");
            Console.WriteLine("  --processor=");
            Console.WriteLine("  --ssl");
            Console.WriteLine();
        }
    }

    public class TestServer
    {
        #pragma warning disable CA2211
        public static int _clientID = -1;  // use with Interlocked only!
        #pragma warning restore CA2211

        private static readonly TConfiguration Configuration = new(); 

        public delegate void TestLogDelegate(string msg, params object[] values);

        public class MyServerEventHandler : TServerEventHandler
        {
            public int callCount = 0;

            public Task PreServeAsync(CancellationToken cancellationToken)
            {
                callCount++;
                return Task.CompletedTask;
            }

            public async Task CreateContextAsync(TProtocol input, TProtocol output, CancellationToken cancellationToken)
            {
                callCount++;
                return null;
            }

            public Task DeleteContextAsync(object serverContext, TProtocol input, TProtocol output, CancellationToken cancellationToken)
            {
                callCount++;
                return Task.CompletedTask;
            }

            public Task ProcessContextAsync(object serverContext, TTransport transport, CancellationToken cancellationToken)
            {
                callCount++;
                return Task.CompletedTask;
            }
        }

        public class TestHandlerAsync : ThriftTest.IAsync
        {
            //public TServer Server { get; set; }
            private readonly int handlerID;
            private readonly StringBuilder sb = new();
            private readonly TestLogDelegate logger;

            public TestHandlerAsync()
            {
                handlerID = Interlocked.Increment(ref _clientID);
                logger += TestConsoleLogger;
                logger.Invoke("New TestHandler instance created");
            }

            public void TestConsoleLogger(string msg, params object[] values)
            {
                sb.Clear();
                sb.AppendFormat("handler{0:D3}:", handlerID);
                sb.AppendFormat(msg, values);
                sb.AppendLine();
                Console.Write(sb.ToString());
            }

            public Task testVoid(CancellationToken cancellationToken)
            {
                logger.Invoke("testVoid()");
                return Task.CompletedTask;
            }

            public Task testString(string thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testString({0})", thing);
                return Task.FromResult(thing);
            }

            public Task testBool(bool thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testBool({0})", thing);
                return Task.FromResult(thing);
            }

            public Task testByte(sbyte thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testByte({0})", thing);
                return Task.FromResult(thing);
            }

            public Task testI32(int thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testI32({0})", thing);
                return Task.FromResult(thing);
            }

            public Task testI64(long thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testI64({0})", thing);
                return Task.FromResult(thing);
            }

            public Task testDouble(double thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testDouble({0})", thing);
                return Task.FromResult(thing);
            }

            public Task testBinary(byte[] thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testBinary({0} bytes)", thing.Length);
                return Task.FromResult(thing);
            }

            public Task testStruct(Xtruct thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing.String_thing, thing.Byte_thing, thing.I32_thing, thing.I64_thing);
                return Task.FromResult(thing);
            }

            public Task testNest(Xtruct2 nest, CancellationToken cancellationToken)
            {
                var thing = nest.Struct_thing;
                logger.Invoke("testNest({{{0}, {{\"{1}\", {2}, {3}, {4}, {5}}}}})",
                    nest.Byte_thing,
                    thing.String_thing,
                    thing.Byte_thing,
                    thing.I32_thing,
                    thing.I64_thing,
                    nest.I32_thing);
                return Task.FromResult(nest);
            }

            public Task> testMap(Dictionary thing, CancellationToken cancellationToken)
            {
                sb.Clear();
                sb.Append("testMap({{");
                var first = true;
                foreach (var key in thing.Keys)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        sb.Append(", ");
                    }
                    sb.AppendFormat("{0} => {1}", key, thing[key]);
                }
                sb.Append("}})");
                logger.Invoke(sb.ToString());
                return Task.FromResult(thing);
            }

            public Task> testStringMap(Dictionary thing, CancellationToken cancellationToken)
            {
                sb.Clear();
                sb.Append("testStringMap({{");
                var first = true;
                foreach (var key in thing.Keys)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        sb.Append(", ");
                    }
                    sb.AppendFormat("{0} => {1}", key, thing[key]);
                }
                sb.Append("}})");
                logger.Invoke(sb.ToString());
                return Task.FromResult(thing);
            }

            public Task> testSet(THashSet thing, CancellationToken cancellationToken)
            {
                sb.Clear();
                sb.Append("testSet({{");
                var first = true;
                foreach (int elem in thing)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        sb.Append(", ");
                    }
                    sb.AppendFormat("{0}", elem);
                }
                sb.Append("}})");
                logger.Invoke(sb.ToString());
                return Task.FromResult(thing);
            }

            public Task> testList(List thing, CancellationToken cancellationToken)
            {
                sb.Clear();
                sb.Append("testList({{");
                var first = true;
                foreach (var elem in thing)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        sb.Append(", ");
                    }
                    sb.AppendFormat("{0}", elem);
                }
                sb.Append("}})");
                logger.Invoke(sb.ToString());
                return Task.FromResult(thing);
            }

            public Task testEnum(Numberz thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testEnum({0})", thing);
                return Task.FromResult(thing);
            }

            public Task testTypedef(long thing, CancellationToken cancellationToken)
            {
                logger.Invoke("testTypedef({0})", thing);
                return Task.FromResult(thing);
            }

            public Task>> testMapMap(int hello, CancellationToken cancellationToken)
            {
                logger.Invoke("testMapMap({0})", hello);
                var mapmap = new Dictionary>();

                var pos = new Dictionary();
                var neg = new Dictionary();
                for (var i = 1; i < 5; i++)
                {
                    pos[i] = i;
                    neg[-i] = -i;
                }

                mapmap[4] = pos;
                mapmap[-4] = neg;

                return Task.FromResult(mapmap);
            }

            public Task>> testInsanity(Insanity argument, CancellationToken cancellationToken)
            {
                logger.Invoke("testInsanity()");

                /** from ThriftTest.thrift:
                 * So you think you've got this all worked, out eh?
                 *
                 * Creates a the returned map with these values and prints it out:
                 *   { 1 => { 2 => argument,
                 *            3 => argument,
                 *          },
                 *     2 => { 6 => , },
                 *   }
                 * @return map> - a map with the above values
                 */

                var first_map = new Dictionary();
                var second_map = new Dictionary(); ;

                first_map[Numberz.TWO] = argument;
                first_map[Numberz.THREE] = argument;

                second_map[Numberz.SIX] = new Insanity();

                var insane = new Dictionary>
                {
                    [1] = first_map,
                    [2] = second_map
                };

                return Task.FromResult(insane);
            }

            public Task testMulti(sbyte arg0, int arg1, long arg2, Dictionary arg3, Numberz arg4, long arg5,
                CancellationToken cancellationToken)
            {
                logger.Invoke("testMulti()");

                var hello = new Xtruct(); ;
                hello.String_thing = "Hello2";
                hello.Byte_thing = arg0;
                hello.I32_thing = arg1;
                hello.I64_thing = arg2;
                return Task.FromResult(hello);
            }

            public Task testException(string arg, CancellationToken cancellationToken)
            {
                logger.Invoke("testException({0})", arg);
                if (arg == "Xception")
                {
                    var x = new Xception
                    {
                        ErrorCode = 1001,
                        Message = arg
                    };
                    throw x;
                }
                if (arg == "TException")
                {
                    throw new TException();
                }
                return Task.CompletedTask;
            }

            public Task testMultiException(string arg0, string arg1, CancellationToken cancellationToken)
            {
                logger.Invoke("testMultiException({0}, {1})", arg0, arg1);
                if (arg0 == "Xception")
                {
                    var x = new Xception
                    {
                        ErrorCode = 1001,
                        Message = "This is an Xception"
                    };
                    throw x;
                }

                if (arg0 == "Xception2")
                {
                    var x = new Xception2
                    {
                        ErrorCode = 2002,
                        Struct_thing = new Xtruct { String_thing = "This is an Xception2" }
                    };
                    throw x;
                }

                var result = new Xtruct { String_thing = arg1 };
                return Task.FromResult(result);
            }

            public async Task testOneway(int secondsToSleep, CancellationToken cancellationToken)
            {
                logger.Invoke("testOneway({0}), sleeping...", secondsToSleep);
                await Task.Delay(secondsToSleep * 1000, cancellationToken);
                logger.Invoke("testOneway finished");
            }
        }


        private static X509Certificate2 GetServerCert()
        {
            var serverCertName = "server.p12";
            var possiblePaths = new List
            {
                "../../../keys/",
                "../../keys/",
                "../keys/",
                "keys/",
            };
                        
            var existingPath = string.Empty;
            foreach (var possiblePath in possiblePaths)
            {
                var path = Path.GetFullPath(possiblePath + serverCertName);
                if (File.Exists(path))
                {
                    existingPath = path;
                    break;
                }
            }
                        
            if (string.IsNullOrEmpty(existingPath))
            {
                throw new FileNotFoundException($"Cannot find file: {serverCertName}");
            }
                                    
            var cert = new X509Certificate2(existingPath, "thrift");
                        
            return cert;
        }

        public static async Task Execute(List args)
        {
            using (var loggerFactory = new LoggerFactory()) //.AddConsole().AddDebug();
            {
                var logger = loggerFactory.CreateLogger("Test");

                try
                {
                    var param = new ServerParam();

                    try
                    {
                        param.Parse(args);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("*** FAILED ***");
                        Console.WriteLine("Error while  parsing arguments");
                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
                        return 1;
                    }


                    // Endpoint transport (mandatory)
                    TServerTransport trans;
                    switch (param.transport)
                    {
                        case TransportChoice.NamedPipe:
                            Debug.Assert(param.pipe != null);
                            trans = new TNamedPipeServerTransport(param.pipe, Configuration, NamedPipeClientFlags.OnlyLocalClients);
                            break;


                        case TransportChoice.TlsSocket:
                            var cert = GetServerCert();
                            if (cert == null || !cert.HasPrivateKey)
                            {
                                cert?.Dispose();
                                throw new InvalidOperationException("Certificate doesn't contain private key");
                            }

                            trans = new TTlsServerSocketTransport(param.port, Configuration,
                                cert,
                                (sender, certificate, chain, errors) => true,
                                null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12);
                            break;

                        case TransportChoice.Socket:
                        default:
                            trans = new TServerSocketTransport(param.port, Configuration);
                            break;
                    }

                    // Layered transport (mandatory)
                    TTransportFactory? transFactory;
                    switch (param.buffering)
                    {
                        case BufferChoice.Framed:
                            transFactory = new TFramedTransport.Factory();
                            break;
                        case BufferChoice.Buffered:
                            transFactory = new TBufferedTransport.Factory();
                            break;
                        default:
                            Debug.Assert(param.buffering == BufferChoice.None, "unhandled case");
                            transFactory = null;  // no layered transprt
                            break;
                    }

                    TProtocolFactory proto = param.protocol switch
                    {
                        ProtocolChoice.Compact => new TCompactProtocol.Factory(),
                        ProtocolChoice.Json => new TJsonProtocol.Factory(),
                        ProtocolChoice.Binary => new TBinaryProtocol.Factory(),
                        _ => new TBinaryProtocol.Factory(),
                    };

                    // Processor
                    var testHandler = new TestHandlerAsync();
                    var testProcessor = new ThriftTest.AsyncProcessor(testHandler);
                    var processorFactory = new TSingletonProcessorFactory(testProcessor);

                    var poolconfig = new TThreadPoolAsyncServer.Configuration();  // use platform defaults
                    TServer serverEngine = param.server switch
                    {
                        ServerChoice.Simple => new TSimpleAsyncServer(processorFactory, trans, transFactory, transFactory, proto, proto, logger),
                        ServerChoice.ThreadPool => new TThreadPoolAsyncServer(processorFactory, trans, transFactory, transFactory, proto, proto, poolconfig, logger),
                        _ => new TSimpleAsyncServer(processorFactory, trans, transFactory, transFactory, proto, proto, logger)
                    };

                    //Server event handler
                    var serverEvents = new MyServerEventHandler();
                    serverEngine.SetEventHandler(serverEvents);

                    // Run it
                    var where = (!string.IsNullOrEmpty(param.pipe)) ? "pipe " + param.pipe : "port " + param.port;
                    Console.WriteLine("Running "+ serverEngine.GetType().Name +
                                      " at "+ where +
                                      " using "+ processorFactory.GetType().Name + " processor prototype factory " +
                                      (param.buffering == BufferChoice.Buffered ? " with buffered transport" : "") +
                                      (param.buffering == BufferChoice.Framed ? " with framed transport" : "") +
                                      (param.transport == TransportChoice.TlsSocket ? " with encryption" : "") +
                                      (param.protocol == ProtocolChoice.Compact ? " with compact protocol" : "") +
                                      (param.protocol == ProtocolChoice.Json ? " with json protocol" : "") +
                                      "...");
                    await serverEngine.ServeAsync(CancellationToken.None);
                    Console.ReadLine();
                }
                catch (Exception x)
                {
                    Console.Error.Write(x);
                    return 1;
                }

                Console.WriteLine("done.");
                return 0;
            }
        }
    }

}
thrift-0.16.0/test/netstd/ThriftTest.sln000066400000000000000000000207441420101504100201670ustar00rootroot00000000000000
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30104.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "..\..\lib\netstd\Thrift\Thrift.csproj", "{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{21039F25-6ED7-4E80-A545-EBC93472EBD1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{0C6E8685-F191-4479-9842-882A38961127}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.IntegrationTests", "..\..\lib\netstd\Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj", "{C8148BFF-B943-4474-8D33-A641C6FD3DAB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.PublicInterfaces.Compile.Tests", "..\..\lib\netstd\Tests\Thrift.PublicInterfaces.Compile.Tests\Thrift.PublicInterfaces.Compile.Tests.csproj", "{5D86C1B6-0CDA-4D1D-80A5-240583B21148}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.Tests", "..\..\lib\netstd\Tests\Thrift.Tests\Thrift.Tests.csproj", "{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.Benchmarks", "..\..\lib\netstd\Benchmarks\Thrift.Benchmarks\Thrift.Benchmarks.csproj", "{66946544-8DE7-45E9-8D0E-93EADA028D44}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|Any CPU = Release|Any CPU
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.ActiveCfg = Debug|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.Build.0 = Debug|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.ActiveCfg = Debug|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.Build.0 = Debug|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.Build.0 = Release|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.ActiveCfg = Release|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.Build.0 = Release|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.ActiveCfg = Release|Any CPU
		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.Build.0 = Release|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x64.ActiveCfg = Debug|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x64.Build.0 = Debug|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x86.ActiveCfg = Debug|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x86.Build.0 = Debug|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|Any CPU.Build.0 = Release|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x64.ActiveCfg = Release|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x64.Build.0 = Release|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x86.ActiveCfg = Release|Any CPU
		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x86.Build.0 = Release|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x64.ActiveCfg = Debug|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x64.Build.0 = Debug|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x86.ActiveCfg = Debug|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x86.Build.0 = Debug|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Release|Any CPU.Build.0 = Release|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Release|x64.ActiveCfg = Release|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Release|x64.Build.0 = Release|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Release|x86.ActiveCfg = Release|Any CPU
		{0C6E8685-F191-4479-9842-882A38961127}.Release|x86.Build.0 = Release|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x64.ActiveCfg = Debug|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x64.Build.0 = Debug|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x86.ActiveCfg = Debug|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Debug|x86.Build.0 = Debug|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|Any CPU.Build.0 = Release|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x64.ActiveCfg = Release|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x64.Build.0 = Release|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x86.ActiveCfg = Release|Any CPU
		{C8148BFF-B943-4474-8D33-A641C6FD3DAB}.Release|x86.Build.0 = Release|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x64.ActiveCfg = Debug|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x64.Build.0 = Debug|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x86.ActiveCfg = Debug|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Debug|x86.Build.0 = Debug|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|Any CPU.Build.0 = Release|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x64.ActiveCfg = Release|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x64.Build.0 = Release|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x86.ActiveCfg = Release|Any CPU
		{5D86C1B6-0CDA-4D1D-80A5-240583B21148}.Release|x86.Build.0 = Release|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x64.ActiveCfg = Debug|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x64.Build.0 = Debug|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x86.ActiveCfg = Debug|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Debug|x86.Build.0 = Debug|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|Any CPU.Build.0 = Release|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x64.ActiveCfg = Release|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x64.Build.0 = Release|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x86.ActiveCfg = Release|Any CPU
		{37FDED71-F8FB-434B-B2A8-1C53CCD9FD38}.Release|x86.Build.0 = Release|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x64.ActiveCfg = Debug|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x64.Build.0 = Debug|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x86.ActiveCfg = Debug|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Debug|x86.Build.0 = Debug|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|Any CPU.Build.0 = Release|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x64.ActiveCfg = Release|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x64.Build.0 = Release|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x86.ActiveCfg = Release|Any CPU
		{66946544-8DE7-45E9-8D0E-93EADA028D44}.Release|x86.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {52CE9A12-F6CB-4F0C-BB42-0105612F5FF4}
	EndGlobalSection
EndGlobal
thrift-0.16.0/test/netstd/build.cmd000066400000000000000000000016411420101504100171300ustar00rootroot00000000000000@echo off
rem /*
rem  * Licensed to the Apache Software Foundation (ASF) under one
rem  * or more contributor license agreements. See the NOTICE file
rem  * distributed with this work for additional information
rem  * regarding copyright ownership. The ASF licenses this file
rem  * to you under the Apache License, Version 2.0 (the
rem  * "License"); you may not use this file except in compliance
rem  * with the License. You may obtain a copy of the License at
rem  *
rem  *   http://www.apache.org/licenses/LICENSE-2.0
rem  *
rem  * Unless required by applicable law or agreed to in writing,
rem  * software distributed under the License is distributed on an
rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
rem  * KIND, either express or implied. See the License for the
rem  * specific language governing permissions and limitations
rem  * under the License.
rem  */
setlocal

dotnet --info
dotnet build

:eof
thrift-0.16.0/test/netstd/build.sh000066400000000000000000000015451420101504100170020ustar00rootroot00000000000000#!/usr/bin/env bash

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

#exit if any command fails
set -e

dotnet --info
dotnet build
thrift-0.16.0/test/ocaml/000077500000000000000000000000001420101504100151345ustar00rootroot00000000000000thrift-0.16.0/test/ocaml/Makefile000066400000000000000000000015751420101504100166040ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

all:
	cd client; make; cd ..; cd server; make
clean:
	cd client; make clean; cd ..; cd server; make clean

thrift-0.16.0/test/ocaml/client/000077500000000000000000000000001420101504100164125ustar00rootroot00000000000000thrift-0.16.0/test/ocaml/client/Makefile000066400000000000000000000021131420101504100200470ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestClient.ml
RESULT = tc
INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/"
LIBS = unix thrift
all: nc
OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile
include $(OCAMLMAKEFILE)
thrift-0.16.0/test/ocaml/client/TestClient.ml000066400000000000000000000044361420101504100210310ustar00rootroot00000000000000(*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements. See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership. The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License. You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied. See the License for the
 specific language governing permissions and limitations
 under the License.
*)

open Thrift;;
open ThriftTest_types;;

let s = new TSocket.t "127.0.0.1" 9090;;
let p = new TBinaryProtocol.t s;;
let c = new ThriftTest.client p p;;
let sod = function
    Some v -> v
  | None -> raise Thrift_error;;

s#opn;
print_string (c#testString "bya");
print_char '\n';
print_int (c#testByte 8);
print_char '\n';
print_int (c#testByte (-8));
print_char '\n';
print_int (c#testI32 32);
print_char '\n';
print_string (Int64.to_string (c#testI64 64L));
print_char '\n';
print_float (c#testDouble 3.14);
print_char '\n';

let l = [1;2;3;4] in
  if l = (c#testList l) then print_string "list ok\n" else print_string "list fail\n";;
let h = Hashtbl.create 5 in
let a = Hashtbl.add h in
  for i=1 to 10 do
    a i (10*i)
  done;
  let r = c#testMap h in
    for i=1 to 10 do
      try
        let g = Hashtbl.find r i in
          print_int i;
          print_char ' ';
          print_int g;
          print_char '\n'
      with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n")
    done;;

let s = Hashtbl.create 5 in
let a = Hashtbl.add s in
  for i = 1 to 10 do
    a i true
  done;
  let r = c#testSet s in
    for i = 1 to 10 do
      try
        let g = Hashtbl.find r i in
          print_int i;
          print_char '\n'
      with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n")
    done;;
try
  c#testException "Xception"
with Xception _ -> print_string "testException ok\n";;
try
  ignore(c#testMultiException "Xception" "bya")
with Xception e -> Printf.printf "%d %s\n" (sod e#get_errorCode) (sod e#get_message);;


thrift-0.16.0/test/ocaml/server/000077500000000000000000000000001420101504100164425ustar00rootroot00000000000000thrift-0.16.0/test/ocaml/server/Makefile000066400000000000000000000021241420101504100201010ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestServer.ml
RESULT = ts
INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/"
LIBS = thrift
THREADS = yes
all: nc
OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile
include $(OCAMLMAKEFILE)
thrift-0.16.0/test/ocaml/server/TestServer.ml000066400000000000000000000106421420101504100211050ustar00rootroot00000000000000(*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements. See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership. The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License. You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied. See the License for the
 specific language governing permissions and limitations
 under the License.
*)

open Thrift
open ThriftTest_types

let p = Printf.printf;;
exception Die;;
let sod = function
    Some v -> v
  | None -> raise Die;;


class test_handler =
object (self)
  inherit ThriftTest.iface
  method testVoid = p "testVoid()\n"
  method testString x = p "testString(%s)\n" (sod x); (sod x)
  method testByte x = p "testByte(%d)\n" (sod x); (sod x)
  method testI32 x = p "testI32(%d)\n" (sod x); (sod x)
  method testI64 x = p "testI64(%s)\n" (Int64.to_string (sod x)); (sod x)
  method testDouble x = p "testDouble(%f)\n" (sod x); (sod x)
  method testBinary x = p "testBinary(%s)\n" (sod x); (sod x)
  method testStruct x = p "testStruct(---)\n"; (sod x)
  method testNest x = p "testNest(---)\n"; (sod x)
  method testMap x = p "testMap(---)\n"; (sod x)
  method testSet x = p "testSet(---)\n"; (sod x)
  method testList x = p "testList(---)\n"; (sod x)
  method testEnum x = p "testEnum(---)\n"; (sod x)
  method testTypedef x = p "testTypedef(---)\n"; (sod x)
  method testMapMap x = p "testMapMap(%d)\n" (sod x);
    let mm = Hashtbl.create 3 in
    let pos = Hashtbl.create 7 in
    let neg = Hashtbl.create 7 in
      for i=1 to 4 do
        Hashtbl.add pos i i;
        Hashtbl.add neg (-i) (-i);
      done;
      Hashtbl.add mm 4 pos;
      Hashtbl.add mm (-4) neg;
      mm
  method testInsanity x = p "testInsanity()\n";
    p "testinsanity()\n";
    let hello = new xtruct in
    let goodbye = new xtruct in
    let crazy = new insanity in
    let looney = new insanity in
    let cumap = Hashtbl.create 7 in
    let insane = Hashtbl.create 7 in
    let firstmap = Hashtbl.create 7 in
    let secondmap = Hashtbl.create 7 in
      hello#set_string_thing "Hello2";
      hello#set_byte_thing 2;
      hello#set_i32_thing 2;
      hello#set_i64_thing 2L;
      goodbye#set_string_thing "Goodbye4";
      goodbye#set_byte_thing 4;
      goodbye#set_i32_thing 4;
      goodbye#set_i64_thing 4L;
      Hashtbl.add cumap Numberz.EIGHT 8L;
      Hashtbl.add cumap Numberz.FIVE 5L;
      crazy#set_userMap cumap;
      crazy#set_xtructs [goodbye; hello];
      Hashtbl.add firstmap Numberz.TWO crazy;
      Hashtbl.add firstmap Numberz.THREE crazy;
      Hashtbl.add secondmap Numberz.SIX looney;
      Hashtbl.add insane 1L firstmap;
      Hashtbl.add insane 2L secondmap;
      insane
  method testMulti a0 a1 a2 a3 a4 a5 =
    p "testMulti()\n";
    let hello = new xtruct in
      hello#set_string_thing "Hello2";
      hello#set_byte_thing (sod a0);
      hello#set_i32_thing (sod a1);
      hello#set_i64_thing (sod a2);
      hello
  method testException s =
    p "testException(%S)\n" (sod s);
    if (sod s) = "Xception" then
      let x = new xception in
        x#set_errorCode 1001;
        x#set_message "This is an Xception";
        raise (Xception x)
    else ()
  method testMultiException a0 a1 =
    p "testMultiException(%S, %S)\n" (sod a0) (sod a1);
    if (sod a0) = "Xception" then
      let x = new xception in
        x#set_errorCode 1001;
        x#set_message "This is an Xception";
        raise (Xception x)
    else (if (sod a0) = "Xception2" then
              let x = new xception2 in
              let s = new xtruct in
                x#set_errorCode 2002;
                s#set_string_thing "This as an Xception2";
                x#set_struct_thing s;
                raise (Xception2 x)
          else ());
    let res = new xtruct in
      res#set_string_thing (sod a1);
      res
  method testOneway i =
    Unix.sleep (sod i)
end;;

let h = new test_handler in
let proc = new ThriftTest.processor h in
let port = 9090 in
let pf = new TBinaryProtocol.factory in
let server = new TThreadedServer.t
  proc
  (new TServerSocket.t port)
  (new Transport.factory)
  pf
  pf
in
  server#serve


thrift-0.16.0/test/partial/000077500000000000000000000000001420101504100154755ustar00rootroot00000000000000thrift-0.16.0/test/partial/thrift_test_schema.thrift000066400000000000000000000103401420101504100225740ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

namespace java org.apache.thrift.partial

// This thrift file is meant for testing partial deserialization.
// It includes all field types and most combinations of complex types.
// Those fields help ensure correctness of partial deserialization.

enum TstEnum {
    UNKNOWN = 0,
    E_ONE = 1,
    E_TWO = 2
}

struct SmallStruct {
    // Primitive fields
    1: optional byte byteField;
    2: optional i16 i16Field;
    3: optional i32 i32Field;
    4: optional i64 i64Field;
    5: optional double doubleField;
    6: optional string stringField;

    // Enum
    7: optional TstEnum enumField;
}

// TODO(kpandit): Need to add bool field
struct TestStruct {
    // Primitive fields
    1: optional byte byteField;
    2: optional i16 i16Field;
    3: optional i32 i32Field;
    4: optional i64 i64Field;
    5: optional double doubleField;
    6: optional string stringField;

    // Enum
    7: optional TstEnum enumField;

    8: optional binary binaryField;

    // List
    10: optional list byteList;
    11: optional list i16List;
    12: optional list i32List;
    13: optional list i64List;
    14: optional list doubleList;
    15: optional list stringList;
    16: optional list enumList;
    17: optional list> listList;
    18: optional list> setList;
    19: optional list> mapList;
    20: optional list structList;
    21: optional list binaryList;

    // Set
    30: optional set byteSet;
    31: optional set i16Set;
    32: optional set i32Set;
    33: optional set i64Set;
    34: optional set doubleSet;
    35: optional set stringSet;
    36: optional set enumSet;
    37: optional set> listSet (nolint = "set.value.type");
    38: optional set> setSet (nolint = "set.value.type");
    39: optional set> mapSet (nolint = "set.value.type");
    40: optional set structSet (nolint = "set.value.type");
    41: optional set binarySet;

    // Map
    50: optional map byteMap;
    51: optional map i16Map;
    52: optional map i32Map;
    53: optional map i64Map;
    54: optional map doubleMap;
    55: optional map stringMap;
    56: optional map enumMap;
    57: optional map> listMap;
    58: optional map> setMap;
    59: optional map> mapMap;
    60: optional map structMap (nolint = "map.key.type");
    61: optional map binaryMap;

    70: optional SmallStruct structField;
}

struct InnermostStruct {
  1: optional string value;
  2: optional i32 intValue;
}

struct InnerStruct {
  1: optional InnermostStruct value;
  2: optional i32 intValue;
}

struct OuterStruct {
  1: optional InnerStruct value;
  2: optional map structMap;
}

union SimpleUnion {
  1: optional i32 intValue;
  2: optional string stringValue;
}

struct StructWithUnions {
  1: optional i32 intValue;
  2: optional SmallStruct smallStruct;
  3: optional SimpleUnion simpleUnion;
  4: optional list unionList;
  5: optional set unionSet (nolint = "set.value.type");
  6: optional map keyUnionMap (nolint = "map.key.type");
  7: optional map valUnionMap;
  8: optional map unionMap (nolint = "map.key.type");
}
thrift-0.16.0/test/perl/000077500000000000000000000000001420101504100150035ustar00rootroot00000000000000thrift-0.16.0/test/perl/Makefile.am000066400000000000000000000017051420101504100170420ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

stubs: ../ThriftTest.thrift
	$(THRIFT) --gen perl ../ThriftTest.thrift

precross: stubs

check: stubs

clean-local:
	$(RM) -r gen-perl/

dist-hook:
	$(RM) -r $(distdir)/gen-perl/
thrift-0.16.0/test/perl/TestClient.pl000077500000000000000000000243541420101504100174310ustar00rootroot00000000000000#!/usr/bin/env perl

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

use 5.10.0;
use strict;
use warnings;
use Data::Dumper;
use Getopt::Long qw(GetOptions);
use Time::HiRes qw(gettimeofday);

use lib '../../lib/perl/lib';
use lib 'gen-perl';

use Thrift;
use Thrift::BinaryProtocol;
use Thrift::BufferedTransport;
use Thrift::FramedTransport;
use Thrift::MultiplexedProtocol;
use Thrift::SSLSocket;
use Thrift::Socket;
use Thrift::UnixSocket;

use ThriftTest::SecondService;
use ThriftTest::ThriftTest;
use ThriftTest::Types;

$|++;

sub usage {
    print <<"EOF";
Usage: $0 [OPTIONS]

Options:                          (default)
  --ca                                         CA to validate server with.
  --cert                                       Certificate to use.
                                               Required if using --ssl.
  --ciphers                                    Acceptable cipher list.
  --domain-socket                        Use a unix domain socket.
  --help                                       Show usage.
  --key                                        Certificate key.
                                               Required if using --ssl.
  --port                 9090         Port to use.
  --protocol {binary}             binary       Protocol to use.
  --ssl                                        If present, use SSL.
  --transport {buffered|framed}   buffered     Transport to use.

EOF
}

my %opts = (
    'port' => 9090,
    'protocol' => 'binary',
    'transport' => 'buffered'
);

GetOptions(\%opts, qw (
    ca=s
    cert=s
    ciphers=s
    key=s
    domain-socket=s
    help
    host=s
    port=i
    protocol=s
    ssl
    transport=s
)) || exit 1;

if ($opts{help}) {
    usage();
    exit 0;
}

my $socket = undef;
if ($opts{'domain-socket'}) {
    $socket = Thrift::UnixSocket->new($opts{'domain-socket'});
}
elsif ($opts{ssl}) {
  $socket = Thrift::SSLSocket->new(\%opts);
}
else {
  $socket = Thrift::Socket->new($opts{host}, $opts{port});
}

my $transport;
if ($opts{transport} eq 'buffered') {
    $transport = Thrift::BufferedTransport->new($socket, 1024, 1024);
}
elsif ($opts{transport} eq 'framed') {
    $transport = Thrift::FramedTransport->new($socket);
}
else {
    usage();
    exit 1;
}

my $protocol;
my $protocol2;
if ($opts{protocol} eq 'binary' || $opts{protocol} eq 'multi') {
    $protocol = Thrift::BinaryProtocol->new($transport);
}
else {
    usage();
    exit 1;
}

my $secondService = undef;
if (index($opts{protocol}, 'multi') == 0) {
  $protocol2     = Thrift::MultiplexedProtocol->new($protocol, 'SecondService');
  $protocol      = Thrift::MultiplexedProtocol->new($protocol, 'ThriftTest');
  $secondService = ThriftTest::SecondServiceClient->new($protocol2);
}

my $testClient = ThriftTest::ThriftTestClient->new($protocol);

eval {
  $transport->open();
};
if($@){
    die(Dumper($@));
}

use constant ERR_BASETYPES => 1;
use constant ERR_STRUCTS => 2;
use constant ERR_CONTAINERS => 4;
use constant ERR_EXCEPTIONS => 8;
use constant ERR_PROTOCOL => 16;
use constant ERR_UNKNOWN => 64;

my $start = gettimeofday();

#
# VOID TEST
#
print('testVoid()');
$testClient->testVoid();
print(" = void\n");

#
# STRING TEST
#
print('testString("Test")');
my $s = $testClient->testString('Test');
print(qq| = "$s"\n|);
exit(ERR_BASETYPES) if ($s ne 'Test');

#
# MULTIPLEXED TEST
#
if (index($opts{protocol}, 'multi') == 0) {
    print('secondtestString("Test2")');
    $s = $secondService->secondtestString('Test2');
    print(qq| = "$s"\n|);
    exit(ERR_PROTOCOL) if ($s ne 'testString("Test2")');
}

#
# BOOL TEST
#
print('testBool(1)');
my $t = $testClient->testBool(1);
print(" = $t\n");
exit(ERR_BASETYPES) if ($t ne 1);
print('testBool(0)');
my $f = $testClient->testBool(0);
print(" = $f\n");
exit(ERR_BASETYPES) if ($f ne q||);


#
# BYTE TEST
#
print('testByte(1)');
my $u8 = $testClient->testByte(1);
print(" = $u8\n");

#
# I32 TEST
#
print('testI32(-1)');
my $i32 = $testClient->testI32(-1);
print(" = $i32\n");
exit(ERR_BASETYPES) if ($i32 ne -1);

#
# I64 TEST
#
print('testI64(-34359738368)');
my $i64 = $testClient->testI64(-34359738368);
print(" = $i64\n");
exit(ERR_BASETYPES) if ($i64 ne -34359738368);

#
# DOUBLE TEST
#
print('testDouble(-852.234234234)');
my $dub = $testClient->testDouble(-852.234234234);
print(" = $dub\n");
exit(ERR_BASETYPES) if ($dub ne -852.234234234);

#
# BINARY TEST
#
print("testBinary(pack('C*', 0..255))");
my $bin = $testClient->testBinary(pack('C*', 0..255));
printf(" = %s\n", join ' ', map { sprintf '%02x', $_ } unpack('C*', $bin));
exit(ERR_BASETYPES) if ($bin ne pack('C*', 0..255));

#
# STRUCT TEST
#
print('testStruct({"Zero", 1, -3, -5})');
my $out = ThriftTest::Xtruct->new();
$out->string_thing('Zero');
$out->byte_thing(1);
$out->i32_thing(-3);
$out->i64_thing(-5);
my $in = $testClient->testStruct($out);
print(' = {"'.$in->string_thing.'", '.
        $in->byte_thing.', '.
        $in->i32_thing.', '.
        $in->i64_thing."}\n");

#
# NESTED STRUCT TEST
#
print('testNest({1, {"Zero", 1, -3, -5}, 5}');
my $out2 = ThriftTest::Xtruct2->new();
$out2->byte_thing(1);
$out2->struct_thing($out);
$out2->i32_thing(5);
my $in2 = $testClient->testNest($out2);
$in = $in2->struct_thing;
print(' = {'.$in2->byte_thing.', {"'.
      $in->string_thing.'", '.
      $in->byte_thing.', '.
      $in->i32_thing.', '.
      $in->i64_thing.'}, '.
      $in2->i32_thing."}\n");

#
# MAP TEST
#
my $mapout = {};
for (my $i = 0; $i < 5; ++$i) {
  $mapout->{$i} = $i-10;
}
print('testMap({');
my $first = 1;
while( my($key,$val) = each %$mapout) {
    if ($first) {
        $first = 0;
    }
    else {
        print(', ');
    }
    print("$key => $val");
}
print('})');


my $mapin = $testClient->testMap($mapout);
print(' = {');

$first = 1;
while( my($key,$val) = each %$mapin){
    if ($first) {
        $first = 0;
    }
    else {
        print(', ');
    }
    print("$key => $val");
}
print("}\n");

#
# SET TEST
#
my $setout = [];
for (my $i = -2; $i < 3; ++$i) {
    push(@$setout, $i);
}

print('testSet({'.join(',',@$setout).'})');

my $setin = $testClient->testSet($setout);

print(' = {'.join(',',@$setout)."}\n");

#
# LIST TEST
#
my $listout = [];
for (my $i = -2; $i < 3; ++$i) {
    push(@$listout, $i);
}

print('testList({'.join(',',@$listout).'})');

my $listin = $testClient->testList($listout);

print(' = {'.join(',',@$listin)."}\n");

#
# ENUM TEST
#
print('testEnum(ONE)');
my $ret = $testClient->testEnum(ThriftTest::Numberz::ONE);
print(" = $ret\n");

print('testEnum(TWO)');
$ret = $testClient->testEnum(ThriftTest::Numberz::TWO);
print(" = $ret\n");

print('testEnum(THREE)');
$ret = $testClient->testEnum(ThriftTest::Numberz::THREE);
print(" = $ret\n");

print('testEnum(FIVE)');
$ret = $testClient->testEnum(ThriftTest::Numberz::FIVE);
print(" = $ret\n");

print('testEnum(EIGHT)');
$ret = $testClient->testEnum(ThriftTest::Numberz::EIGHT);
print(" = $ret\n");

#
# TYPEDEF TEST
#
print('testTypedef(309858235082523)');
my $uid = $testClient->testTypedef(309858235082523);
print(" = $uid\n");

#
# NESTED MAP TEST
#
print('testMapMap(1)');
my $mm = $testClient->testMapMap(1);
print(' = {');
while( my ($key,$val) = each %$mm) {
    print("$key => {");
    while( my($k2,$v2) = each %$val) {
        print("$k2 => $v2, ");
    }
    print('}, ');
}
print("}\n");

#
# INSANITY TEST
#
my $insane = ThriftTest::Insanity->new();
$insane->{userMap}->{ThriftTest::Numberz::FIVE} = 5000;
my $truck = ThriftTest::Xtruct->new();
$truck->string_thing('Hello2');
$truck->byte_thing(2);
$truck->i32_thing(2);
$truck->i64_thing(2);
my $truck2 = ThriftTest::Xtruct->new();
$truck2->string_thing('Goodbye4');
$truck2->byte_thing(4);
$truck2->i32_thing(4);
$truck2->i64_thing(4);
push(@{$insane->{xtructs}}, $truck);
push(@{$insane->{xtructs}}, $truck2);

print('testInsanity()');
my $whoa = $testClient->testInsanity($insane);
print(' = {');
while( my ($key,$val) = each %$whoa) {
    print("$key => {");
    while( my($k2,$v2) = each %$val) {
        print("$k2 => {");
        my $userMap = $v2->{userMap};
        print('{');
        if (ref($userMap) eq 'HASH') {
            while( my($k3,$v3) = each %$userMap) {
                print("$k3 => $v3, ");
            }
        }
        print('}, ');

        my $xtructs = $v2->{xtructs};
        print('{');
        if (ref($xtructs) eq 'ARRAY') {
            foreach my $x (@$xtructs) {
                print('{"'.$x->{string_thing}.'", '.
                      $x->{byte_thing}.', '.$x->{i32_thing}.', '.$x->{i64_thing}.'}, ');
            }
        }
        print('}');

        print('}, ');
    }
    print('}, ');
}
print("}\n");

#
# EXCEPTION TEST
#
print(q|testException('Xception')|);
eval {
    $testClient->testException('Xception');
    print("  void\nFAILURE\n");
}; if($@ && $@->UNIVERSAL::isa('ThriftTest::Xception')) {
    print(' caught xception '.$@->{errorCode}.': '.$@->{message}."\n");
}


#
# Normal tests done.
#
my $stop = gettimeofday();
my $elp  = sprintf('%d',1000*($stop - $start), 0);
print("Total time: $elp ms\n");

#
# Extraneous "I don't trust PHP to pack/unpack integer" tests
#

# Max I32
my $num = 2**30 + 2**30 - 1;
my $num2 = $testClient->testI32($num);
if ($num != $num2) {
    print "Missed max32 $num = $num2\n";
}

# Min I32
$num = 0 - 2**31;
$num2 = $testClient->testI32($num);
if ($num != $num2) {
    print "Missed min32 $num = $num2\n";
}

# Max Number I can get out of my perl
$num = 2**40;
$num2 = $testClient->testI64($num);
if ($num != $num2) {
    print "Missed max64 $num = $num2\n";
}

# Max Number I can get out of my perl
$num = 0 - 2**40;
$num2 = $testClient->testI64($num);
if ($num != $num2) {
    print "Missed min64 $num = $num2\n";
}

$transport->close();



thrift-0.16.0/test/perl/TestServer.pl000066400000000000000000000232361420101504100174540ustar00rootroot00000000000000#!/usr/bin/env perl

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

use 5.10.0;
use strict;
use warnings;
use Data::Dumper;
use Getopt::Long qw(GetOptions);
use Time::HiRes qw(gettimeofday);

$SIG{INT} = \&sigint_handler;

use lib '../../lib/perl/lib';
use lib 'gen-perl';

use Thrift;
use Thrift::BinaryProtocol;
use Thrift::BufferedTransport;
use Thrift::FramedTransport;
use Thrift::MultiplexedProcessor;
use Thrift::SSLServerSocket;
use Thrift::ServerSocket;
use Thrift::Server;
use Thrift::UnixServerSocket;

use ThriftTest::SecondService;
use ThriftTest::ThriftTest;
use ThriftTest::Types;

$|++;

sub usage {
    print <<"EOF";
Usage: $0 [OPTIONS]

Options:                          (default)
  --ca                                         Certificate authority file (optional).
  --cert                                       Certificate file.
                                               Required if using --ssl.
  --ciphers                                    Acceptable cipher list.
  --domain-socket                        Use a unix domain socket.
  --help                                       Show usage.
  --key                                        Private key file for certificate.
                                               Required if using --ssl and private key is
                                               not in the certificate file.
  --port                 9090         Port to use.
  --protocol {binary}             binary       Protocol to use.
  --ssl                                        If present, use SSL/TLS.
  --transport {buffered|framed}   buffered     Transport to use.

EOF
}

my %opts = (
    'port' => 9090,
    'protocol' => 'binary',
    'transport' => 'buffered'
);

GetOptions(\%opts, qw (
    ca=s
    cert=s
    ciphers=s
    domain-socket=s
    help
    host=s
    key=s
    port=i
    protocol=s
    ssl
    transport=s
)) || exit 1;

if ($opts{help}) {
    usage();
    exit 0;
}

if ($opts{ssl} and not defined $opts{cert}) {
    usage();
    exit 1;
}

my $handler    = ThriftTestHandler->new();
my $handler2   = SecondServiceHandler->new();
my $processor  = ThriftTest::ThriftTestProcessor->new($handler);
my $processor2 = ThriftTest::SecondServiceProcessor->new($handler2);

my $serversocket;
if ($opts{'domain-socket'}) {
    unlink($opts{'domain-socket'});
    $serversocket = Thrift::UnixServerSocket->new($opts{'domain-socket'});
}
elsif ($opts{ssl}) {
    $serversocket = Thrift::SSLServerSocket->new(\%opts);
}
else {
    $serversocket = Thrift::ServerSocket->new(\%opts);
}
my $transport;
if ($opts{transport} eq 'buffered') {
    $transport = Thrift::BufferedTransportFactory->new();
}
elsif ($opts{transport} eq 'framed') {
    $transport = Thrift::FramedTransportFactory->new();
}
else {
    usage();
    exit 1;
}
my $protocol;
if ($opts{protocol} eq 'binary' || $opts{protocol} eq 'multi') {
    $protocol = Thrift::BinaryProtocolFactory->new();
}
else {
    usage();
    exit 1;
}

if (index($opts{protocol}, 'multi') == 0) {
  my $newProcessor = Thrift::MultiplexedProcessor->new($protocol);
  $newProcessor->defaultProcessor($processor);
  $newProcessor->registerProcessor('ThriftTest', $processor);
  $newProcessor->registerProcessor('SecondService', $processor2);
  $processor = $newProcessor;
}

my $ssltag = '';
if ($opts{ssl}) {
    $ssltag = '(SSL)';
}
my $listening_on = "$opts{port} $ssltag";
if ($opts{'domain-socket'}) {
    $listening_on = $opts{'domain-socket'};
}
my $server = Thrift::SimpleServer->new($processor, $serversocket, $transport, $protocol);
print qq|Starting "simple" server ($opts{transport}/$opts{protocol}) listen on: $listening_on\n|;
$server->serve();
print "done.\n";

sub sigint_handler {
  print "received SIGINT, stopping...\n";
  $server->stop();
}

###
### Test server implementation
###

package ThriftTestHandler;

use base qw( ThriftTest::ThriftTestIf );

sub new {
    my $classname = shift;
    my $self = {};
    return bless($self, $classname);
}

sub testVoid {
  print("testVoid()\n");
}

sub testString {
  my $self = shift;
  my $thing = shift;
  print("testString($thing)\n");
  return $thing;
}

sub testBool {
  my $self = shift;
  my $thing = shift;
  my $str = $thing ? 'true' : 'false';
  print("testBool($str)\n");
  return $thing;
}

sub testByte {
  my $self = shift;
  my $thing = shift;
  print("testByte($thing)\n");
  return $thing;
}

sub testI32 {
  my $self = shift;
  my $thing = shift;
  print("testI32($thing)\n");
  return $thing;
}

sub testI64 {
  my $self = shift;
  my $thing = shift;
  print("testI64($thing)\n");
  return $thing;
}

sub testDouble {
  my $self = shift;
  my $thing = shift;
  print("testDouble($thing)\n");
  return $thing;
}

sub testBinary {
    my $self = shift;
    my $thing = shift;
    my @bytes = split //, $thing;
    print 'testBinary(';
    printf( '%02lx', ord $_ ) foreach (@bytes);
    print ")\n";
    return $thing;
}

sub testStruct {
  my $self = shift;
  my $thing = shift;
  printf(qq|testStruct({"%s", %d, %d, %lld})\n|,
           $thing->{string_thing},
           $thing->{byte_thing},
           $thing->{i32_thing},
           $thing->{i64_thing});
  return $thing;
}

sub testNest {
  my $self = shift;
  my $nest = shift;
  my $thing = $nest->{struct_thing};
  printf(qq|testNest({%d, {"%s", %d, %d, %lld}, %d})\n|,
           $nest->{byte_thing},
           $thing->{string_thing},
           $thing->{byte_thing},
           $thing->{i32_thing},
           $thing->{i64_thing},
           $nest->{i32_thing});
  return $nest;
}

sub testMap {
  my $self = shift;
  my $thing = shift;
  printf "testMap({%s})\n",
    join( ', ',
          map { $_ . ' => ' . $thing->{$_} }
          sort keys %$thing
    );
  return $thing;
}

sub testStringMap {
  my $self = shift;
  my $thing = shift;
  printf "testStringMap({%s})\n",
    join( ', ',
          map { $_ . ' => ' . $thing->{$_} }
          sort keys %$thing
    );
  return $thing;
}

sub testSet {
  my $self = shift;
  my $thing = shift;
  my @result = sort keys %$thing;
  printf "testSet({%s})\n", join(', ', @result );
  return \@result;
}

sub testList {
  my $self = shift;
  my $thing = shift;
  print "testList({%s})\n", join(', ', @$thing);
  return $thing;
}

sub testEnum {
  my $self = shift;
  my $thing = shift;
  print "testEnum($thing)\n";
  return $thing;
}

sub testTypedef {
  my $self = shift;
  my $thing = shift;
  print("testTypedef($thing)\n");
  return $thing;
}

sub testMapMap {
  my $self = shift;
  my $hello = shift;

  printf("testMapMap(%d)\n", $hello);
  my $result = { 4 => { 1 => 1, 2 => 2, 3 => 3, 4 => 4 }, -4 => { -1 => -1, -2 => -2, -3 => -3, -4 => -4 } };
  return $result;
}

sub testInsanity {
  my $self = shift;
  my $argument = shift;
  print("testInsanity()\n");

  my $hello = ThriftTest::Xtruct->new({string_thing => 'Hello2', byte_thing => 2, i32_thing => 2, i64_thing => 2});
  my @hellos;
  push(@hellos, $hello);
  my $goodbye = ThriftTest::Xtruct->new({string_thing => 'Goodbye4', byte_thing => 4, i32_thing => 4, i64_thing => 4});
  my @goodbyes;
  push(@goodbyes, $goodbye);
  my $crazy = ThriftTest::Insanity->new({userMap => { ThriftTest::Numberz::EIGHT => 8 }, xtructs => \@goodbyes});
  my $loony = ThriftTest::Insanity->new();
  my $result = { 1 => { ThriftTest::Numberz::TWO => $argument, ThriftTest::Numberz::THREE => $argument },
                 2 => { ThriftTest::Numberz::SIX => $loony } };
  return $result;
}

sub testMulti {
  my $self = shift;
  my $arg0 = shift;
  my $arg1 = shift;
  my $arg2 = shift;
  my $arg3 = shift;
  my $arg4 = shift;
  my $arg5 = shift;

  print("testMulti()\n");
  return ThriftTest::Xtruct->new({string_thing => 'Hello2', byte_thing => $arg0, i32_thing => $arg1, i64_thing => $arg2});
}

sub testException {
  my $self = shift;
  my $arg = shift;
  print("testException($arg)\n");
  if ($arg eq 'Xception') {
      die ThriftTest::Xception->new({errorCode => 1001, message => $arg});
  }
  elsif ($arg eq 'TException') {
      die 'astring'; # all unhandled exceptions become TExceptions
  }
  else {
      return ThriftTest::Xtruct->new({string_thing => $arg});
  }
}

sub testMultiException {
  my $self = shift;
  my $arg0 = shift;
  my $arg1 = shift;

  printf("testMultiException(%s, %s)\n", $arg0, $arg1);
  if ($arg0 eq 'Xception') {
    die ThriftTest::Xception->new({errorCode => 1001, message => 'This is an Xception'});
  }
  elsif ($arg0 eq 'Xception2') {
    my $struct_thing = ThriftTest::Xtruct->new({string_thing => 'This is an Xception2'});
    die ThriftTest::Xception2->new({errorCode => 2002, struct_thing => $struct_thing});
  }
  else {
    return ThriftTest::Xtruct->new({string_thing => $arg1});
  }
}

sub testOneway {
  my $self = shift;
  my $num = shift;
  print("testOneway($num): received\n");
}

###
### Test server implementation
###

package SecondServiceHandler;

use base qw( ThriftTest::SecondServiceIf );

sub new {
    my $classname = shift;
    my $self = {};
    return bless($self, $classname);
}

sub secondtestString {
  my $self = shift;
  my $thing = shift;
  print("testString($thing)\n");
  return qq|testString("$thing")|;
}

1;
thrift-0.16.0/test/php/000077500000000000000000000000001420101504100146305ustar00rootroot00000000000000thrift-0.16.0/test/php/Makefile.am000077500000000000000000000027161420101504100166750ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

stubs: ../ThriftTest.thrift
	$(THRIFT) --gen php ../ThriftTest.thrift
	$(THRIFT) --gen php:inlined ../ThriftTest.thrift
	$(MKDIR_P) gen-php-classmap
	$(THRIFT) -out gen-php-classmap --gen php:classmap ../ThriftTest.thrift

php_ext_dir:
	mkdir -p php_ext_dir
	ln -s ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so php_ext_dir/
	ln -s "$$(php-config --extension-dir)/json.so" php_ext_dir/
	ln -s "$$(php-config --extension-dir)/sockets.so" php_ext_dir/

precross: stubs php_ext_dir

check: stubs php_ext_dir

clean-local:
	$(RM) -r gen-*/
	$(RM) -r php_ext_dir

dist-hook:
	$(RM) -r $(distdir)/gen-*/
	$(RM) -r $(distdir)/php_ext_dir/

client: stubs php_ext_dir
	php TestClient.php
thrift-0.16.0/test/php/TestClassmap.php000066400000000000000000000015551420101504100177520ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */


thrift-0.16.0/test/php/TestClient.php000077500000000000000000000311121420101504100174200ustar00rootroot00000000000000addPsr4('', $GEN_DIR);
} else {
  $loader = new ThriftClassLoader();
  $loader->registerDefinition('ThriftTest', $GEN_DIR);
  $loader->register();
}

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/** Include the Thrift base */
/** Include the protocols */
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Protocol\TBinaryProtocolAccelerated;
use Thrift\Protocol\TCompactProtocol;
use Thrift\Protocol\TJSONProtocol;

/** Include the socket layer */
use Thrift\Transport\TSocket;
use Thrift\Transport\TSocketPool;

/** Include the socket layer */
use Thrift\Transport\TFramedTransport;
use Thrift\Transport\TBufferedTransport;

function makeProtocol($transport, $PROTO)
{
  if ($PROTO == 'binary') {
    return new TBinaryProtocol($transport);
  } else if ($PROTO == 'compact') {
    return new TCompactProtocol($transport);
  } else if ($PROTO == 'json') {
    return new TJSONProtocol($transport);
  } else if ($PROTO == 'accel') {
    if (!function_exists('thrift_protocol_write_binary')) {
      echo "Acceleration extension is not loaded\n";
      exit(1);
    }
    return new TBinaryProtocolAccelerated($transport);
  }

  echo "--protocol must be one of {binary|compact|json|accel}\n";
  exit(1);
}

$host = 'localhost';
$port = 9090;

if ($argc > 1) {
  $host = $argv[0];
}

if ($argc > 2) {
  $host = $argv[1];
}

foreach ($argv as $arg) {
  if (substr($arg, 0, 7) == '--port=') {
    $port = substr($arg, 7);
  } else if (substr($arg, 0, 12) == '--transport=') {
    $MODE = substr($arg, 12);
  } else if (substr($arg, 0, 11) == '--protocol=') {
    $PROTO = substr($arg, 11);
  }
}

$hosts = array('localhost');

$socket = new TSocket($host, $port);
$socket = new TSocketPool($hosts, $port);
$socket->setDebug(TRUE);

if ($MODE == 'inline') {
  $transport = $socket;
  $testClient = new \ThriftTest\ThriftTestClient($transport);
} else if ($MODE == 'framed') {
  $framedSocket = new TFramedTransport($socket);
  $transport = $framedSocket;
  $protocol = makeProtocol($transport, $PROTO);
  $testClient = new \ThriftTest\ThriftTestClient($protocol);
} else {
  $bufferedSocket = new TBufferedTransport($socket, 1024, 1024);
  $transport = $bufferedSocket;
  $protocol = makeProtocol($transport, $PROTO);
  $testClient = new \ThriftTest\ThriftTestClient($protocol);
}

$transport->open();

$start = microtime(true);

define('ERR_BASETYPES', 1);
define('ERR_STRUCTS', 2);
define('ERR_CONTAINERS', 4);
define('ERR_EXCEPTIONS', 8);
define('ERR_UNKNOWN', 64);
$exitcode = 0;
/**
 * VOID TEST
 */
print_r("testVoid()");
$testClient->testVoid();
print_r(" = void\n");

function roundtrip($testClient, $method, $value) {
  global $exitcode;
  print_r("$method($value)");
  $ret = $testClient->$method($value);
  print_r(" = \"$ret\"\n");
  if ($value !== $ret) {
    print_r("*** FAILED ***\n");
    $exitcode |= ERR_BASETYPES;
  }
}

/**
 * STRING TEST
 */
roundtrip($testClient, 'testString', "Test");

/**
 * BOOL TEST
 */
roundtrip($testClient, 'testBool', true);
roundtrip($testClient, 'testBool', false);

/**
 * BYTE TEST
 */
roundtrip($testClient, 'testByte', 1);
roundtrip($testClient, 'testByte', -1);
roundtrip($testClient, 'testByte', 127);
roundtrip($testClient, 'testByte', -128);

/**
 * I32 TEST
 */
roundtrip($testClient, 'testI32', -1);

/**
 * I64 TEST
 */
roundtrip($testClient, 'testI64', 0);
roundtrip($testClient, 'testI64', 1);
roundtrip($testClient, 'testI64', -1);
roundtrip($testClient, 'testI64', -34359738368);

/**
 * DOUBLE TEST
 */
roundtrip($testClient, 'testDouble', -852.234234234);

/**
 * BINARY TEST  --  TODO
 */

/**
 * STRUCT TEST
 */
print_r("testStruct({\"Zero\", 1, -3, -5})");
$out = new \ThriftTest\Xtruct();
$out->string_thing = "Zero";
$out->byte_thing = 1;
$out->i32_thing = -3;
$out->i64_thing = -5;
$in = $testClient->testStruct($out);
print_r(" = {\"".$in->string_thing."\", ".
        $in->byte_thing.", ".
        $in->i32_thing.", ".
        $in->i64_thing."}\n");

if ($in != $out) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

/**
 * NESTED STRUCT TEST
 */
print_r("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
$out2 = new \ThriftTest\Xtruct2();
$out2->byte_thing = 1;
$out2->struct_thing = $out;
$out2->i32_thing = 5;
$in2 = $testClient->testNest($out2);
$in = $in2->struct_thing;
print_r(" = {".$in2->byte_thing.", {\"".
        $in->string_thing."\", ".
        $in->byte_thing.", ".
        $in->i32_thing.", ".
        $in->i64_thing."}, ".
        $in2->i32_thing."}\n");

if ($in2 != $out2) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

/**
 * MAP TEST
 */
$mapout = array();
for ($i = 0; $i < 5; ++$i) {
  $mapout[$i] = $i-10;
}
print_r("testMap({");
$first = true;
foreach ($mapout as $key => $val) {
  if ($first) {
    $first = false;
  } else {
    print_r(", ");
  }
  print_r("$key => $val");
}
print_r("})");

$mapin = $testClient->testMap($mapout);
print_r(" = {");
$first = true;
foreach ($mapin as $key => $val) {
  if ($first) {
    $first = false;
  } else {
    print_r(", ");
  }
  print_r("$key => $val");
}
print_r("}\n");

if ($mapin != $mapout) {
    echo "**FAILED**\n";
    $exitcode |= ERR_CONTAINERS;
}

$mapout = array();
for ($i = 0; $i < 10; $i++) {
    $mapout["key$i"] = "val$i";
}
print_r('testStringMap({');
$first = true;
foreach ($mapout as $key => $val) {
  if ($first) {
    $first = false;
  } else {
    print_r(", ");
  }
  print_r("\"$key\" => \"$val\"");
}
print_r("})");
$mapin = $testClient->testStringMap($mapout);
print_r(" = {");
$first = true;
foreach ($mapin as $key => $val) {
  if ($first) {
    $first = false;
  } else {
    print_r(", ");
  }
  print_r("\"$key\" => \"$val\"");
}
print_r("}\n");
ksort($mapin);
if ($mapin != $mapout) {
    echo "**FAILED**\n";
    $exitcode |= ERR_CONTAINERS;
}

/**
 * SET TEST
 */
$setout = array();;
for ($i = -2; $i < 3; ++$i) {
  $setout[$i]= true;
}
print_r("testSet({");
echo implode(',', array_keys($setout));
print_r("})");
$setin = $testClient->testSet($setout);
print_r(" = {");
echo implode(', ', array_keys($setin));
print_r("}\n");
// Order of keys in set does not matter
ksort($setin);
if ($setout !== $setin) {
    echo "**FAILED**\n";
    $exitcode |= ERR_CONTAINERS;
}
// Regression test for corrupted array
if ($setin[2] !== $setout[2] || is_int($setin[2])) {
    echo "**FAILED**\n";
    $exitcode |= ERR_CONTAINERS;
}

/**
 * LIST TEST
 */
$listout = array();
for ($i = -2; $i < 3; ++$i) {
  $listout []= $i;
}
print_r("testList({");
$first = true;
foreach ($listout as $val) {
  if ($first) {
    $first = false;
  } else {
    print_r(", ");
  }
  print_r($val);
}
print_r("})");
$listin = $testClient->testList($listout);
print_r(" = {");
$first = true;
foreach ($listin as $val) {
  if ($first) {
    $first = false;
  } else {
    print_r(", ");
  }
  print_r($val);
}
print_r("}\n");
if ($listin !== $listout) {
    echo "**FAILED**\n";
    $exitcode |= ERR_CONTAINERS;
}

/**
 * ENUM TEST
 */
print_r("testEnum(ONE)");
$ret = $testClient->testEnum(\ThriftTest\Numberz::ONE);
print_r(" = $ret\n");
if ($ret != \ThriftTest\Numberz::ONE) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

print_r("testEnum(TWO)");
$ret = $testClient->testEnum(\ThriftTest\Numberz::TWO);
print_r(" = $ret\n");
if ($ret != \ThriftTest\Numberz::TWO) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

print_r("testEnum(THREE)");
$ret = $testClient->testEnum(\ThriftTest\Numberz::THREE);
print_r(" = $ret\n");
if ($ret != \ThriftTest\Numberz::THREE) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

print_r("testEnum(FIVE)");
$ret = $testClient->testEnum(\ThriftTest\Numberz::FIVE);
print_r(" = $ret\n");
if ($ret != \ThriftTest\Numberz::FIVE) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

print_r("testEnum(EIGHT)");
$ret = $testClient->testEnum(\ThriftTest\Numberz::EIGHT);
print_r(" = $ret\n");
if ($ret != \ThriftTest\Numberz::EIGHT) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

/**
 * TYPEDEF TEST
 */
print_r("testTypedef(309858235082523)");
$uid = $testClient->testTypedef(309858235082523);
print_r(" = $uid\n");
if ($uid !== 309858235082523) {
    echo "**FAILED**\n";
    $exitcode |= ERR_STRUCTS;
}

/**
 * NESTED MAP TEST
 */
print_r("testMapMap(1)");
$mm = $testClient->testMapMap(1);
print_r(" = {");
foreach ($mm as $key => $val) {
  print_r("$key => {");
  foreach ($val as $k2 => $v2) {
    print_r("$k2 => $v2, ");
  }
  print_r("}, ");
}
print_r("}\n");
$expected_mm = [
  -4 => [-4 => -4, -3 => -3, -2 => -2, -1 => -1],
  4 => [4 => 4, 3 => 3, 2 => 2, 1 => 1],
];
if ($mm != $expected_mm) {
    echo "**FAILED**\n";
    $exitcode |= ERR_CONTAINERS;
}

/**
 * INSANITY TEST
 */
$insane = new \ThriftTest\Insanity();
$insane->userMap[\ThriftTest\Numberz::FIVE] = 5000;
$truck = new \ThriftTest\Xtruct();
$truck->string_thing = "Truck";
$truck->byte_thing = 8;
$truck->i32_thing = 8;
$truck->i64_thing = 8;
$insane->xtructs []= $truck;
print_r("testInsanity()");
$whoa = $testClient->testInsanity($insane);
print_r(" = {");
foreach ($whoa as $key => $val) {
  print_r("$key => {");
  foreach ($val as $k2 => $v2) {
    print_r("$k2 => {");
    $userMap = $v2->userMap;
    print_r("{");
    if (is_array($userMap)) {
      foreach ($userMap as $k3 => $v3) {
        print_r("$k3 => $v3, ");
      }
    }
    print_r("}, ");

    $xtructs = $v2->xtructs;
    print_r("{");
    if (is_array($xtructs)) {
      foreach ($xtructs as $x) {
        print_r("{\"".$x->string_thing."\", ".
                $x->byte_thing.", ".$x->i32_thing.", ".$x->i64_thing."}, ");
      }
    }
    print_r("}");

    print_r("}, ");
  }
  print_r("}, ");
}
print_r("}\n");

/**
 * EXCEPTION TEST
 */
print_r("testException('Xception')");
try {
  $testClient->testException('Xception');
  print_r("  void\nFAILURE\n");
  $exitcode |= ERR_EXCEPTIONS;
} catch (\ThriftTest\Xception $x) {
  print_r(' caught xception '.$x->errorCode.': '.$x->message."\n");
}

// Regression test for THRIFT-4263
print_r("testBinarySerializer_Deserialize('foo')");
try {
  \Thrift\Serializer\TBinarySerializer::deserialize(base64_decode('foo'), \ThriftTest\Xtruct2::class);
  echo "**FAILED**\n";
  $exitcode |= ERR_STRUCTS;
} catch (\Thrift\Exception\TTransportException $happy_exception) {
  // We expected this due to binary data of base64_decode('foo') is less then 4
  // bytes and it tries to find thrift version number in the transport by
  // reading i32() at the beginning.  Casting to string validates that
  // exception is still accessible in memory and not corrupted.  Without patch,
  // PHP will error log that the exception doesn't have any tostring method,
  // which is a lie due to corrupted memory.
  for($i=99; $i > 0; $i--) {
    (string)$happy_exception;
  }
  print_r("  SUCCESS\n");
}

/**
 * Normal tests done.
 */

$stop = microtime(true);
$elp = round(1000*($stop - $start), 0);
print_r("Total time: $elp ms\n");

/**
 * Extraneous "I don't trust PHP to pack/unpack integer" tests
 */

if ($protocol instanceof TBinaryProtocolAccelerated) {
    // Regression check: check that method name is not double-freed
    // Method name should not be an interned string.
    $method_name = "Void";
    $method_name = "test$method_name";

    $seqid = 0;
    $args = new \ThriftTest\ThriftTest_testVoid_args();
    thrift_protocol_write_binary($protocol, $method_name, \Thrift\Type\TMessageType::CALL, $args, $seqid, $protocol->isStrictWrite());
    $testClient->recv_testVoid();

}

// Max I32
$num = pow(2, 30) + (pow(2, 30) - 1);
roundtrip($testClient, 'testI32', $num);

// Min I32
$num = 0 - pow(2, 31);
roundtrip($testClient, 'testI32', $num);

// Max I64
$num = pow(2, 62) + (pow(2, 62) - 1);
roundtrip($testClient, 'testI64', $num);

// Min I64
$num = 0 - pow(2, 62) - pow(2, 62);
roundtrip($testClient, 'testI64', $num);

$transport->close();
exit($exitcode);
thrift-0.16.0/test/php/TestInline.php000066400000000000000000000015671420101504100174300ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */


thrift-0.16.0/test/php/test_php.ini000066400000000000000000000001041420101504100171520ustar00rootroot00000000000000extension=thrift_protocol.so
extension=json.so
extension=sockets.so
thrift-0.16.0/test/py.tornado/000077500000000000000000000000001420101504100161365ustar00rootroot00000000000000thrift-0.16.0/test/py.tornado/Makefile.am000066400000000000000000000025611420101504100201760ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

THRIFT = $(top_srcdir)/compiler/cpp/thrift

thrift_gen: ../ThriftTest.thrift ../SmallTest.thrift
	$(THRIFT) --gen py:tornado ../ThriftTest.thrift
	$(THRIFT) --gen py:tornado ../SmallTest.thrift

check: thrift_gen
	./test_suite.py

clean-local:
	$(RM) -r build
	find . -type f \( -iname "*.pyc" \) | xargs rm -f
	find . -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf
	$(RM) -r gen-py*/

dist-hook:
	find $(distdir) -type f \( -iname "*.pyc" \) | xargs rm -f
	find $(distdir) -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf
	$(RM) -r $(distdir)/gen-py*/
thrift-0.16.0/test/py.tornado/setup.cfg000066400000000000000000000000551420101504100177570ustar00rootroot00000000000000[flake8]
ignore = E402
max-line-length = 100
thrift-0.16.0/test/py.tornado/test_suite.py000077500000000000000000000142771420101504100207160ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

import datetime
import glob
import os
import sys
import time
import unittest

basepath = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, basepath + '/gen-py.tornado')
sys.path.insert(0, glob.glob(os.path.join(basepath, '../../lib/py/build/lib*'))[0])

try:
    __import__('tornado')
except ImportError:
    print("module `tornado` not found, skipping test")
    sys.exit(0)

from tornado import gen
from tornado.testing import AsyncTestCase, get_unused_port, gen_test

from thrift import TTornado
from thrift.Thrift import TApplicationException
from thrift.protocol import TBinaryProtocol

from ThriftTest import ThriftTest
from ThriftTest.ttypes import Xception, Xtruct


class TestHandler(object):
    def __init__(self, test_instance):
        self.test_instance = test_instance

    def testVoid(self):
        pass

    def testString(self, s):
        if s == 'unexpected_error':
            raise Exception(s)
        return s

    def testByte(self, b):
        return b

    def testI16(self, i16):
        return i16

    def testI32(self, i32):
        return i32

    def testI64(self, i64):
        return i64

    def testDouble(self, dub):
        return dub

    def testBinary(self, thing):
        return thing

    def testStruct(self, thing):
        return thing

    def testException(self, s):
        if s == 'Xception':
            raise Xception(1001, s)
        elif s == 'throw_undeclared':
            raise ValueError('testing undeclared exception')

    def testOneway(self, seconds):
        start = time.time()

        def fire_oneway():
            end = time.time()
            self.test_instance.stop((start, end, seconds))

        self.test_instance.io_loop.add_timeout(
            datetime.timedelta(seconds=seconds),
            fire_oneway)
        raise Exception('testing exception in oneway method')

    def testNest(self, thing):
        return thing

    @gen.coroutine
    def testMap(self, thing):
        yield gen.moment
        raise gen.Return(thing)

    def testSet(self, thing):
        return thing

    def testList(self, thing):
        return thing

    def testEnum(self, thing):
        return thing

    def testTypedef(self, thing):
        return thing


class ThriftTestCase(AsyncTestCase):
    def setUp(self):
        super(ThriftTestCase, self).setUp()

        self.port = get_unused_port()

        # server
        self.handler = TestHandler(self)
        self.processor = ThriftTest.Processor(self.handler)
        self.pfactory = TBinaryProtocol.TBinaryProtocolFactory()

        self.server = TTornado.TTornadoServer(self.processor, self.pfactory, io_loop=self.io_loop)
        self.server.bind(self.port)
        self.server.start(1)

        # client
        transport = TTornado.TTornadoStreamTransport('localhost', self.port, io_loop=self.io_loop)
        pfactory = TBinaryProtocol.TBinaryProtocolFactory()
        self.io_loop.run_sync(transport.open)
        self.client = ThriftTest.Client(transport, pfactory)

    @gen_test
    def test_void(self):
        v = yield self.client.testVoid()
        self.assertEqual(v, None)

    @gen_test
    def test_string(self):
        v = yield self.client.testString('Python')
        self.assertEqual(v, 'Python')

    @gen_test
    def test_byte(self):
        v = yield self.client.testByte(63)
        self.assertEqual(v, 63)

    @gen_test
    def test_i32(self):
        v = yield self.client.testI32(-1)
        self.assertEqual(v, -1)

        v = yield self.client.testI32(0)
        self.assertEqual(v, 0)

    @gen_test
    def test_i64(self):
        v = yield self.client.testI64(-34359738368)
        self.assertEqual(v, -34359738368)

    @gen_test
    def test_double(self):
        v = yield self.client.testDouble(-5.235098235)
        self.assertEqual(v, -5.235098235)

    @gen_test
    def test_struct(self):
        x = Xtruct()
        x.string_thing = "Zero"
        x.byte_thing = 1
        x.i32_thing = -3
        x.i64_thing = -5
        y = yield self.client.testStruct(x)

        self.assertEqual(y.string_thing, "Zero")
        self.assertEqual(y.byte_thing, 1)
        self.assertEqual(y.i32_thing, -3)
        self.assertEqual(y.i64_thing, -5)

    @gen_test
    def test_oneway(self):
        self.client.testOneway(1)
        v = yield self.client.testI32(-1)
        self.assertEqual(v, -1)

    @gen_test
    def test_map(self):
        """
        TestHandler.testMap is a coroutine, this test checks if gen.Return() from a coroutine works.
        """
        expected = {1: 1}
        res = yield self.client.testMap(expected)
        self.assertEqual(res, expected)

    @gen_test
    def test_exception(self):
        try:
            yield self.client.testException('Xception')
        except Xception as ex:
            self.assertEqual(ex.errorCode, 1001)
            self.assertEqual(ex.message, 'Xception')
        else:
            self.fail("should have gotten exception")
        try:
            yield self.client.testException('throw_undeclared')
        except TApplicationException:
            pass
        else:
            self.fail("should have gotten exception")

        yield self.client.testException('Safe')


def suite():
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(ThriftTestCase))
    return suite


if __name__ == '__main__':
    unittest.TestProgram(defaultTest='suite',
                         testRunner=unittest.TextTestRunner(verbosity=1))
thrift-0.16.0/test/py.twisted/000077500000000000000000000000001420101504100161535ustar00rootroot00000000000000thrift-0.16.0/test/py.twisted/Makefile.am000066400000000000000000000025241420101504100202120ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

TRIAL ?= trial

stubs: ../ThriftTest.thrift ../SmallTest.thrift
	$(THRIFT) --gen py:twisted ../ThriftTest.thrift
	$(THRIFT) --gen py:twisted ../SmallTest.thrift

check: stubs
	$(TRIAL) ./test_suite.py

clean-local:
	$(RM) -r build
	find . -type f \( -iname "*.pyc" \) | xargs rm -f
	find . -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf
	$(RM) -r gen-py*/

dist-hook:
	find $(distdir) -type f \( -iname "*.pyc" \) | xargs rm -f
	find $(distdir) -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf
	$(RM) -r $(distdir)/gen-py*/
thrift-0.16.0/test/py.twisted/setup.cfg000066400000000000000000000000551420101504100177740ustar00rootroot00000000000000[flake8]
ignore = E402
max-line-length = 100
thrift-0.16.0/test/py.twisted/test_suite.py000077500000000000000000000131261420101504100207230ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

import glob
import os
import sys
import time

basepath = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(basepath, 'gen-py.twisted'))
sys.path.insert(0, glob.glob(os.path.join(basepath, '../../lib/py/build/lib.*'))[0])

from thrift.Thrift import TApplicationException

from ThriftTest import ThriftTest
from ThriftTest.ttypes import Xception, Xtruct
from thrift.transport import TTwisted
from thrift.protocol import TBinaryProtocol

from twisted.trial import unittest
from twisted.internet import defer, reactor
from twisted.internet.protocol import ClientCreator

from zope.interface import implementer


@implementer(ThriftTest.Iface)
class TestHandler:
    def __init__(self):
        self.onewaysQueue = defer.DeferredQueue()

    def testVoid(self):
        pass

    def testString(self, s):
        return s

    def testByte(self, b):
        return b

    def testI16(self, i16):
        return i16

    def testI32(self, i32):
        return i32

    def testI64(self, i64):
        return i64

    def testDouble(self, dub):
        return dub

    def testBinary(self, thing):
        return thing

    def testStruct(self, thing):
        return thing

    def testException(self, s):
        if s == 'Xception':
            raise Xception(1001, s)
        elif s == "throw_undeclared":
            raise ValueError("foo")

    def testOneway(self, seconds):
        def fireOneway(t):
            self.onewaysQueue.put((t, time.time(), seconds))
        reactor.callLater(seconds, fireOneway, time.time())
        raise Exception('')

    def testNest(self, thing):
        return thing

    def testMap(self, thing):
        return thing

    def testSet(self, thing):
        return thing

    def testList(self, thing):
        return thing

    def testEnum(self, thing):
        return thing

    def testTypedef(self, thing):
        return thing


class ThriftTestCase(unittest.TestCase):

    @defer.inlineCallbacks
    def setUp(self):
        self.handler = TestHandler()
        self.processor = ThriftTest.Processor(self.handler)
        self.pfactory = TBinaryProtocol.TBinaryProtocolFactory()

        self.server = reactor.listenTCP(
            0, TTwisted.ThriftServerFactory(self.processor, self.pfactory), interface="127.0.0.1")

        self.portNo = self.server.getHost().port

        self.txclient = yield ClientCreator(reactor,
                                            TTwisted.ThriftClientProtocol,
                                            ThriftTest.Client,
                                            self.pfactory).connectTCP("127.0.0.1", self.portNo)
        self.client = self.txclient.client

    @defer.inlineCallbacks
    def tearDown(self):
        yield self.server.stopListening()
        self.txclient.transport.loseConnection()

    @defer.inlineCallbacks
    def testVoid(self):
        self.assertEquals((yield self.client.testVoid()), None)

    @defer.inlineCallbacks
    def testString(self):
        self.assertEquals((yield self.client.testString('Python')), 'Python')

    @defer.inlineCallbacks
    def testByte(self):
        self.assertEquals((yield self.client.testByte(63)), 63)

    @defer.inlineCallbacks
    def testI32(self):
        self.assertEquals((yield self.client.testI32(-1)), -1)
        self.assertEquals((yield self.client.testI32(0)), 0)

    @defer.inlineCallbacks
    def testI64(self):
        self.assertEquals((yield self.client.testI64(-34359738368)), -34359738368)

    @defer.inlineCallbacks
    def testDouble(self):
        self.assertEquals((yield self.client.testDouble(-5.235098235)), -5.235098235)

    # TODO: def testBinary(self) ...

    @defer.inlineCallbacks
    def testStruct(self):
        x = Xtruct()
        x.string_thing = "Zero"
        x.byte_thing = 1
        x.i32_thing = -3
        x.i64_thing = -5
        y = yield self.client.testStruct(x)

        self.assertEquals(y.string_thing, "Zero")
        self.assertEquals(y.byte_thing, 1)
        self.assertEquals(y.i32_thing, -3)
        self.assertEquals(y.i64_thing, -5)

    @defer.inlineCallbacks
    def testException(self):
        try:
            yield self.client.testException('Xception')
            self.fail("should have gotten exception")
        except Xception as x:
            self.assertEquals(x.errorCode, 1001)
            self.assertEquals(x.message, 'Xception')

        try:
            yield self.client.testException("throw_undeclared")
            self.fail("should have gotten exception")
        except TApplicationException:
            pass

        yield self.client.testException('Safe')

    @defer.inlineCallbacks
    def testOneway(self):
        yield self.client.testOneway(1)
        start, end, seconds = yield self.handler.onewaysQueue.get()
        self.assertAlmostEquals(seconds, (end - start), places=1)
        self.assertEquals((yield self.client.testI32(-1)), -1)
thrift-0.16.0/test/py/000077500000000000000000000000001420101504100144715ustar00rootroot00000000000000thrift-0.16.0/test/py/CMakeLists.txt000066400000000000000000000025351420101504100172360ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

add_test(NAME python_test_generate
    COMMAND ${CMAKE_COMMAND}
            -DTHRIFTCOMPILER=$
            -DMY_PROJECT_DIR=${PROJECT_SOURCE_DIR}
            -DMY_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
            -DMY_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
    -P ${CMAKE_CURRENT_SOURCE_DIR}/generate.cmake
)

add_test(NAME python_test
    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/RunClientServer.py --gen-base=${CMAKE_CURRENT_BINARY_DIR}
    DEPENDS python_test_generate
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

thrift-0.16.0/test/py/FastbinaryTest.py000077500000000000000000000171761420101504100200240ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

r"""
PYTHONPATH=./gen-py:../../lib/py/build/lib... ./FastbinaryTest.py
"""

# TODO(dreiss): Test error cases.  Check for memory leaks.

from __future__ import print_function

import math
import os
import sys
import timeit

from copy import deepcopy
from pprint import pprint

from thrift.transport import TTransport
from thrift.protocol.TBinaryProtocol import TBinaryProtocol, TBinaryProtocolAccelerated
from thrift.protocol.TCompactProtocol import TCompactProtocol, TCompactProtocolAccelerated

from DebugProtoTest import Srv
from DebugProtoTest.ttypes import Backwards, Bonk, Empty, HolyMoley, OneOfEach, RandomStuff, Wrapper


class TDevNullTransport(TTransport.TTransportBase):
    def __init__(self):
        pass

    def isOpen(self):
        return True


ooe1 = OneOfEach()
ooe1.im_true = True
ooe1.im_false = False
ooe1.a_bite = 0xd6
ooe1.integer16 = 27000
ooe1.integer32 = 1 << 24
ooe1.integer64 = 6000 * 1000 * 1000
ooe1.double_precision = math.pi
ooe1.some_characters = "Debug THIS!"
ooe1.zomg_unicode = u"\xd7\n\a\t"

ooe2 = OneOfEach()
ooe2.integer16 = 16
ooe2.integer32 = 32
ooe2.integer64 = 64
ooe2.double_precision = (math.sqrt(5) + 1) / 2
ooe2.some_characters = ":R (me going \"rrrr\")"
ooe2.zomg_unicode = u"\xd3\x80\xe2\x85\xae\xce\x9d\x20"\
                    u"\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe"\
                    u"\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"\
                    u"\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba"\
                    u"\xc7\x83\xe2\x80\xbc"

if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
    ooe1.zomg_unicode = ooe1.zomg_unicode.encode('utf8')
    ooe2.zomg_unicode = ooe2.zomg_unicode.encode('utf8')

hm = HolyMoley(**{"big": [], "contain": set(), "bonks": {}})
hm.big.append(ooe1)
hm.big.append(ooe2)
hm.big[0].a_bite = 0x22
hm.big[1].a_bite = 0x22

hm.contain.add(("and a one", "and a two"))
hm.contain.add(("then a one, two", "three!", "FOUR!"))
if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
    hm.contain.add((u"\xd7\n\a\t".encode('utf8'),))
else:
    hm.contain.add((u"\xd7\n\a\t",))
hm.contain.add(())

hm.bonks["nothing"] = []
hm.bonks["something"] = [
    Bonk(**{"type": 1, "message": "Wait."}),
    Bonk(**{"type": 2, "message": "What?"}),
]
hm.bonks["poe"] = [
    Bonk(**{"type": 3, "message": "quoth"}),
    Bonk(**{"type": 4, "message": "the raven"}),
    Bonk(**{"type": 5, "message": "nevermore"}),
]

rs = RandomStuff()
rs.a = 1
rs.b = 2
rs.c = 3
rs.myintlist = list(range(20))
rs.maps = {1: Wrapper(**{"foo": Empty()}), 2: Wrapper(**{"foo": Empty()})}
rs.bigint = 124523452435
rs.triple = 3.14

# make sure this splits two buffers in a buffered protocol
rshuge = RandomStuff()
rshuge.myintlist = list(range(10000))

my_zero = Srv.Janky_result(**{"success": 5})


class Test(object):
    def __init__(self, fast, slow):
        self._fast = fast
        self._slow = slow

    def _check_write(self, o):
        trans_fast = TTransport.TMemoryBuffer()
        trans_slow = TTransport.TMemoryBuffer()
        prot_fast = self._fast(trans_fast, fallback=False)
        prot_slow = self._slow(trans_slow)

        o.write(prot_fast)
        o.write(prot_slow)
        ORIG = trans_slow.getvalue()
        MINE = trans_fast.getvalue()
        if ORIG != MINE:
            print("actual  : %s\nexpected: %s" % (repr(MINE), repr(ORIG)))
            raise Exception('write value mismatch')

    def _check_read(self, o):
        prot = self._slow(TTransport.TMemoryBuffer())
        o.write(prot)

        slow_version_binary = prot.trans.getvalue()

        prot = self._fast(
            TTransport.TMemoryBuffer(slow_version_binary), fallback=False)
        c = o.__class__()
        c.read(prot)
        if c != o:
            print("actual  : ")
            pprint(repr(c))
            print("expected: ")
            pprint(repr(o))
            raise Exception('read value mismatch')

        prot = self._fast(
            TTransport.TBufferedTransport(
                TTransport.TMemoryBuffer(slow_version_binary)), fallback=False)
        c = o.__class__()
        c.read(prot)
        if c != o:
            print("actual  : ")
            pprint(repr(c))
            print("expected: ")
            pprint(repr(o))
            raise Exception('read value mismatch')

    def do_test(self):
        self._check_write(HolyMoley())
        self._check_read(HolyMoley())

        self._check_write(hm)
        no_set = deepcopy(hm)
        no_set.contain = set()
        self._check_read(no_set)
        self._check_read(hm)

        self._check_write(rs)
        self._check_read(rs)

        self._check_write(rshuge)
        self._check_read(rshuge)

        self._check_write(my_zero)
        self._check_read(my_zero)

        self._check_read(Backwards(**{"first_tag2": 4, "second_tag1": 2}))

        # One case where the serialized form changes, but only superficially.
        o = Backwards(**{"first_tag2": 4, "second_tag1": 2})
        trans_fast = TTransport.TMemoryBuffer()
        trans_slow = TTransport.TMemoryBuffer()
        prot_fast = self._fast(trans_fast, fallback=False)
        prot_slow = self._slow(trans_slow)

        o.write(prot_fast)
        o.write(prot_slow)
        ORIG = trans_slow.getvalue()
        MINE = trans_fast.getvalue()
        assert id(ORIG) != id(MINE)

        prot = self._fast(TTransport.TMemoryBuffer(), fallback=False)
        o.write(prot)
        prot = self._slow(
            TTransport.TMemoryBuffer(prot.trans.getvalue()))
        c = o.__class__()
        c.read(prot)
        if c != o:
            print("copy: ")
            pprint(repr(c))
            print("orig: ")
            pprint(repr(o))


def do_test(fast, slow):
    Test(fast, slow).do_test()


def do_benchmark(protocol, iters=5000, skip_slow=False):
    setup = """
from __main__ import hm, rs, TDevNullTransport
from thrift.protocol.{0} import {0}{1}
trans = TDevNullTransport()
prot = {0}{1}(trans{2})
"""

    setup_fast = setup.format(protocol, 'Accelerated', ', fallback=False')
    if not skip_slow:
        setup_slow = setup.format(protocol, '', '')

    print("Starting Benchmarks")

    if not skip_slow:
        print("HolyMoley Standard = %f" %
              timeit.Timer('hm.write(prot)', setup_slow).timeit(number=iters))

    print("HolyMoley Acceler. = %f" %
          timeit.Timer('hm.write(prot)', setup_fast).timeit(number=iters))

    if not skip_slow:
        print("FastStruct Standard = %f" %
              timeit.Timer('rs.write(prot)', setup_slow).timeit(number=iters))

    print("FastStruct Acceler. = %f" %
          timeit.Timer('rs.write(prot)', setup_fast).timeit(number=iters))


if __name__ == '__main__':
    print('Testing TBinaryAccelerated')
    do_test(TBinaryProtocolAccelerated, TBinaryProtocol)
    do_benchmark('TBinaryProtocol')
    print('Testing TCompactAccelerated')
    do_test(TCompactProtocolAccelerated, TCompactProtocol)
    do_benchmark('TCompactProtocol')
thrift-0.16.0/test/py/Makefile.am000066400000000000000000000101311420101504100165210ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
AUTOMAKE_OPTIONS = serial-tests

py_unit_tests = RunClientServer.py

thrift_gen =                                    \
        gen-py/ThriftTest/__init__.py           \
        gen-py/DebugProtoTest/__init__.py \
        gen-py/DoubleConstantsTest/__init__.py \
        gen-py/Recursive/__init__.py \
        gen-py-default/ThriftTest/__init__.py           \
        gen-py-default/DebugProtoTest/__init__.py \
        gen-py-default/DoubleConstantsTest/__init__.py \
        gen-py-default/Recursive/__init__.py \
        gen-py-slots/ThriftTest/__init__.py           \
        gen-py-slots/DebugProtoTest/__init__.py \
        gen-py-slots/DoubleConstantsTest/__init__.py \
        gen-py-slots/Recursive/__init__.py \
        gen-py-oldstyle/ThriftTest/__init__.py \
        gen-py-oldstyle/DebugProtoTest/__init__.py \
        gen-py-oldstyle/DoubleConstantsTest/__init__.py \
        gen-py-oldstyle/Recursive/__init__.py \
        gen-py-no_utf8strings/ThriftTest/__init__.py \
        gen-py-no_utf8strings/DebugProtoTest/__init__.py \
        gen-py-no_utf8strings/DoubleConstantsTest/__init__.py \
        gen-py-no_utf8strings/Recursive/__init__.py \
        gen-py-dynamic/ThriftTest/__init__.py           \
        gen-py-dynamic/DebugProtoTest/__init__.py \
        gen-py-dynamic/DoubleConstantsTest/__init__.py \
        gen-py-dynamic/Recursive/__init__.py \
        gen-py-dynamicslots/ThriftTest/__init__.py           \
        gen-py-dynamicslots/DebugProtoTest/__init__.py \
        gen-py-dynamicslots/DoubleConstantsTest/__init__.py \
        gen-py-dynamicslots/Recursive/__init__.py


precross: $(thrift_gen)
BUILT_SOURCES = $(thrift_gen)

helper_scripts=                                 \
        TestClient.py                           \
        TestServer.py

check_SCRIPTS=                                  \
        $(thrift_gen) \
        $(py_unit_tests)                        \
        $(helper_scripts)

TESTS= $(py_unit_tests)


gen-py/%/__init__.py: ../%.thrift $(THRIFT)
	$(THRIFT) --gen py  $<

gen-py-default/%/__init__.py: ../%.thrift $(THRIFT)
	test -d gen-py-default || $(MKDIR_P) gen-py-default
	$(THRIFT) --gen py -out gen-py-default $<

gen-py-slots/%/__init__.py: ../%.thrift $(THRIFT)
	test -d gen-py-slots || $(MKDIR_P) gen-py-slots
	$(THRIFT) --gen py:slots -out gen-py-slots $<

gen-py-oldstyle/%/__init__.py: ../%.thrift $(THRIFT)
	test -d gen-py-oldstyle || $(MKDIR_P) gen-py-oldstyle
	$(THRIFT) --gen py:old_style -out gen-py-oldstyle $<

gen-py-no_utf8strings/%/__init__.py: ../%.thrift $(THRIFT)
	test -d gen-py-no_utf8strings || $(MKDIR_P) gen-py-no_utf8strings
	$(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings $<

gen-py-dynamic/%/__init__.py: ../%.thrift $(THRIFT)
	test -d gen-py-dynamic || $(MKDIR_P) gen-py-dynamic
	$(THRIFT) --gen py:dynamic -out gen-py-dynamic $<

gen-py-dynamicslots/%/__init__.py: ../%.thrift $(THRIFT)
	test -d gen-py-dynamicslots || $(MKDIR_P) gen-py-dynamicslots
	$(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots $<

clean-local:
	$(RM) -r build
	find . -type f \( -iname "*.pyc" \) | xargs rm -f
	find . -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf
	$(RM) -r gen-py*/

dist-hook:
	find $(distdir) -type f \( -iname "*.pyc" \) | xargs rm -f
	find $(distdir) -type d \( -iname "__pycache__" -or -iname "_trial_temp" \) | xargs rm -rf
	$(RM) -r $(distdir)/gen-py*/
thrift-0.16.0/test/py/RunClientServer.py000077500000000000000000000303641420101504100201460ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

from __future__ import division
from __future__ import print_function
import platform
import copy
import os
import signal
import socket
import subprocess
import sys
import time
from optparse import OptionParser

from util import local_libpath

SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))

SCRIPTS = [
    'FastbinaryTest.py',
    'TestFrozen.py',
    'TestRenderedDoubleConstants.py',
    'TSimpleJSONProtocolTest.py',
    'SerializationTest.py',
    'TestEof.py',
    'TestSyntax.py',
    'TestSocket.py',
]
FRAMED = ["TNonblockingServer"]
SKIP_ZLIB = ['TNonblockingServer', 'THttpServer']
SKIP_SSL = ['THttpServer']
EXTRA_DELAY = dict(TProcessPoolServer=5.5)

PROTOS = [
    'accel',
    'accelc',
    'binary',
    'compact',
    'json',
    'header',
]


def default_servers():
    servers = [
        'TSimpleServer',
        'TThreadedServer',
        'TThreadPoolServer',
        'TNonblockingServer',
        'THttpServer',
    ]
    if platform.system() != 'Windows':
        servers.append('TProcessPoolServer')
        servers.append('TForkingServer')
    return servers


def relfile(fname):
    return os.path.join(SCRIPT_DIR, fname)


def setup_pypath(libdir, gendir):
    dirs = [libdir, gendir]
    env = copy.deepcopy(os.environ)
    pypath = env.get('PYTHONPATH', None)
    if pypath:
        dirs.append(pypath)
    env['PYTHONPATH'] = os.pathsep.join(dirs)
    if gendir.endswith('gen-py-no_utf8strings'):
        env['THRIFT_TEST_PY_NO_UTF8STRINGS'] = '1'
    return env


def runScriptTest(libdir, genbase, genpydir, script):
    env = setup_pypath(libdir, os.path.join(genbase, genpydir))
    script_args = [sys.executable, relfile(script)]
    print('\nTesting script: %s\n----' % (' '.join(script_args)))
    ret = subprocess.call(script_args, env=env)
    if ret != 0:
        print('*** FAILED ***', file=sys.stderr)
        print('LIBDIR: %s' % libdir, file=sys.stderr)
        print('PY_GEN: %s' % genpydir, file=sys.stderr)
        print('SCRIPT: %s' % script, file=sys.stderr)
        raise Exception("Script subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(script_args)))


def runServiceTest(libdir, genbase, genpydir, server_class, proto, port, use_zlib, use_ssl, verbose):
    env = setup_pypath(libdir, os.path.join(genbase, genpydir))
    # Build command line arguments
    server_args = [sys.executable, relfile('TestServer.py')]
    cli_args = [sys.executable, relfile('TestClient.py')]
    for which in (server_args, cli_args):
        which.append('--protocol=%s' % proto)  # accel, binary, compact or json
        which.append('--port=%d' % port)  # default to 9090
        if use_zlib:
            which.append('--zlib')
        if use_ssl:
            which.append('--ssl')
        if verbose == 0:
            which.append('-q')
        if verbose == 2:
            which.append('-v')
    # server-specific option to select server class
    server_args.append(server_class)
    # client-specific cmdline options
    if server_class in FRAMED:
        cli_args.append('--transport=framed')
    else:
        cli_args.append('--transport=buffered')
    if server_class == 'THttpServer':
        cli_args.append('--http=/')
    if verbose > 0:
        print('Testing server %s: %s' % (server_class, ' '.join(server_args)))
    serverproc = subprocess.Popen(server_args, env=env)

    def ensureServerAlive():
        if serverproc.poll() is not None:
            print(('FAIL: Server process (%s) failed with retcode %d')
                  % (' '.join(server_args), serverproc.returncode))
            raise Exception('Server subprocess %s died, args: %s'
                            % (server_class, ' '.join(server_args)))

    # Wait for the server to start accepting connections on the given port.
    sleep_time = 0.1  # Seconds
    max_attempts = 100
    attempt = 0
    while True:
        sock4 = socket.socket()
        sock6 = socket.socket(socket.AF_INET6)
        try:
            if sock4.connect_ex(('127.0.0.1', port)) == 0 \
                    or sock6.connect_ex(('::1', port)) == 0:
                break
            attempt += 1
            if attempt >= max_attempts:
                raise Exception("TestServer not ready on port %d after %.2f seconds"
                                % (port, sleep_time * attempt))
            ensureServerAlive()
            time.sleep(sleep_time)
        finally:
            sock4.close()
            sock6.close()

    try:
        if verbose > 0:
            print('Testing client: %s' % (' '.join(cli_args)))
        ret = subprocess.call(cli_args, env=env)
        if ret != 0:
            print('*** FAILED ***', file=sys.stderr)
            print('LIBDIR: %s' % libdir, file=sys.stderr)
            print('PY_GEN: %s' % genpydir, file=sys.stderr)
            raise Exception("Client subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(cli_args)))
    finally:
        # check that server didn't die
        ensureServerAlive()
        extra_sleep = EXTRA_DELAY.get(server_class, 0)
        if extra_sleep > 0 and verbose > 0:
            print('Giving %s (proto=%s,zlib=%s,ssl=%s) an extra %d seconds for child'
                  'processes to terminate via alarm'
                  % (server_class, proto, use_zlib, use_ssl, extra_sleep))
            time.sleep(extra_sleep)
        sig = signal.SIGKILL if platform.system() != 'Windows' else signal.SIGABRT
        os.kill(serverproc.pid, sig)
        serverproc.wait()


class TestCases(object):
    def __init__(self, genbase, libdir, port, gendirs, servers, verbose):
        self.genbase = genbase
        self.libdir = libdir
        self.port = port
        self.verbose = verbose
        self.gendirs = gendirs
        self.servers = servers

    def default_conf(self):
        return {
            'gendir': self.gendirs[0],
            'server': self.servers[0],
            'proto': PROTOS[0],
            'zlib': False,
            'ssl': False,
        }

    def run(self, conf, test_count):
        with_zlib = conf['zlib']
        with_ssl = conf['ssl']
        try_server = conf['server']
        try_proto = conf['proto']
        genpydir = conf['gendir']
        # skip any servers that don't work with the Zlib transport
        if with_zlib and try_server in SKIP_ZLIB:
            return False
        # skip any servers that don't work with SSL
        if with_ssl and try_server in SKIP_SSL:
            return False
        if self.verbose > 0:
            print('\nTest run #%d:  (includes %s) Server=%s,  Proto=%s,  zlib=%s,  SSL=%s'
                  % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl))
        runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl, self.verbose)
        if self.verbose > 0:
            print('OK: Finished (includes %s)  %s / %s proto / zlib=%s / SSL=%s.   %d combinations tested.'
                  % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count))
        return True

    def test_feature(self, name, values):
        test_count = 0
        conf = self.default_conf()
        for try_server in values:
            conf[name] = try_server
            if self.run(conf, test_count):
                test_count += 1
        return test_count

    def run_all_tests(self):
        test_count = 0
        for try_server in self.servers:
            for genpydir in self.gendirs:
                for try_proto in PROTOS:
                    for with_zlib in (False, True):
                        # skip any servers that don't work with the Zlib transport
                        if with_zlib and try_server in SKIP_ZLIB:
                            continue
                        for with_ssl in (False, True):
                            # skip any servers that don't work with SSL
                            if with_ssl and try_server in SKIP_SSL:
                                continue
                            test_count += 1
                            if self.verbose > 0:
                                print('\nTest run #%d:  (includes %s) Server=%s,  Proto=%s,  zlib=%s,  SSL=%s'
                                      % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl))
                            runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl)
                            if self.verbose > 0:
                                print('OK: Finished (includes %s)  %s / %s proto / zlib=%s / SSL=%s.   %d combinations tested.'
                                      % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count))
        return test_count


def main():
    parser = OptionParser()
    parser.add_option('--all', action="store_true", dest='all')
    parser.add_option('--genpydirs', type='string', dest='genpydirs',
                      default='default,slots,oldstyle,no_utf8strings,dynamic,dynamicslots',
                      help='directory extensions for generated code, used as suffixes for \"gen-py-*\" added sys.path for individual tests')
    parser.add_option("--port", type="int", dest="port", default=9090,
                      help="port number for server to listen on")
    parser.add_option('-v', '--verbose', action="store_const",
                      dest="verbose", const=2,
                      help="verbose output")
    parser.add_option('-q', '--quiet', action="store_const",
                      dest="verbose", const=0,
                      help="minimal output")
    parser.add_option('-L', '--libdir', dest="libdir", default=local_libpath(),
                      help="directory path that contains Thrift Python library")
    parser.add_option('--gen-base', dest="gen_base", default=SCRIPT_DIR,
                      help="directory path that contains Thrift Python library")
    parser.set_defaults(verbose=1)
    options, args = parser.parse_args()

    generated_dirs = []
    for gp_dir in options.genpydirs.split(','):
        generated_dirs.append('gen-py-%s' % (gp_dir))

    # commandline permits a single class name to be specified to override SERVERS=[...]
    servers = default_servers()
    if len(args) == 1:
        if args[0] in servers:
            servers = args
        else:
            print('Unavailable server type "%s", please choose one of: %s' % (args[0], servers))
            sys.exit(0)

    tests = TestCases(options.gen_base, options.libdir, options.port, generated_dirs, servers, options.verbose)

    # run tests without a client/server first
    print('----------------')
    print(' Executing individual test scripts with various generated code directories')
    print(' Directories to be tested: ' + ', '.join(generated_dirs))
    print(' Scripts to be tested: ' + ', '.join(SCRIPTS))
    print('----------------')
    for genpydir in generated_dirs:
        for script in SCRIPTS:
            runScriptTest(options.libdir, options.gen_base, genpydir, script)

    print('----------------')
    print(' Executing Client/Server tests with various generated code directories')
    print(' Servers to be tested: ' + ', '.join(servers))
    print(' Directories to be tested: ' + ', '.join(generated_dirs))
    print(' Protocols to be tested: ' + ', '.join(PROTOS))
    print(' Options to be tested: ZLIB(yes/no), SSL(yes/no)')
    print('----------------')

    if options.all:
        tests.run_all_tests()
    else:
        tests.test_feature('gendir', generated_dirs)
        tests.test_feature('server', servers)
        tests.test_feature('proto', PROTOS)
        tests.test_feature('zlib', [False, True])
        tests.test_feature('ssl', [False, True])


if __name__ == '__main__':
    sys.exit(main())
thrift-0.16.0/test/py/SerializationTest.py000077500000000000000000000414111420101504100205240ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

from ThriftTest.ttypes import (
    Bonk,
    Bools,
    LargeDeltas,
    ListBonks,
    NestedListsBonk,
    NestedListsI32x2,
    NestedListsI32x3,
    NestedMixedx2,
    Numberz,
    VersioningTestV1,
    VersioningTestV2,
    Xtruct,
    Xtruct2,
)

from Recursive.ttypes import RecTree
from Recursive.ttypes import RecList
from Recursive.ttypes import CoRec
from Recursive.ttypes import CoRec2
from Recursive.ttypes import VectorTest
from DebugProtoTest.ttypes import CompactProtoTestStruct, Empty
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol, TCompactProtocol, TJSONProtocol
from thrift.TSerialization import serialize, deserialize
import sys
import unittest


class AbstractTest(unittest.TestCase):

    def setUp(self):
        self.v1obj = VersioningTestV1(
            begin_in_both=12345,
            old_string='aaa',
            end_in_both=54321,
        )

        self.v2obj = VersioningTestV2(
            begin_in_both=12345,
            newint=1,
            newbyte=2,
            newshort=3,
            newlong=4,
            newdouble=5.0,
            newstruct=Bonk(message="Hello!", type=123),
            newlist=[7, 8, 9],
            newset=set([42, 1, 8]),
            newmap={1: 2, 2: 3},
            newstring="Hola!",
            end_in_both=54321,
        )

        self.bools = Bools(im_true=True, im_false=False)
        self.bools_flipped = Bools(im_true=False, im_false=True)

        self.large_deltas = LargeDeltas(
            b1=self.bools,
            b10=self.bools_flipped,
            b100=self.bools,
            check_true=True,
            b1000=self.bools_flipped,
            check_false=False,
            vertwo2000=VersioningTestV2(newstruct=Bonk(message='World!', type=314)),
            a_set2500=set(['lazy', 'brown', 'cow']),
            vertwo3000=VersioningTestV2(newset=set([2, 3, 5, 7, 11])),
            big_numbers=[2 ** 8, 2 ** 16, 2 ** 31 - 1, -(2 ** 31 - 1)]
        )

        self.compact_struct = CompactProtoTestStruct(
            a_byte=127,
            a_i16=32000,
            a_i32=1000000000,
            a_i64=0xffffffffff,
            a_double=5.6789,
            a_string="my string",
            true_field=True,
            false_field=False,
            empty_struct_field=Empty(),
            byte_list=[-127, -1, 0, 1, 127],
            i16_list=[-1, 0, 1, 0x7fff],
            i32_list=[-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff],
            i64_list=[-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
            double_list=[0.1, 0.2, 0.3],
            string_list=["first", "second", "third"],
            boolean_list=[True, True, True, False, False, False],
            struct_list=[Empty(), Empty()],
            byte_set=set([-127, -1, 0, 1, 127]),
            i16_set=set([-1, 0, 1, 0x7fff]),
            i32_set=set([1, 2, 3]),
            i64_set=set([-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff]),
            double_set=set([0.1, 0.2, 0.3]),
            string_set=set(["first", "second", "third"]),
            boolean_set=set([True, False]),
            # struct_set=set([Empty()]), # unhashable instance
            byte_byte_map={1: 2},
            i16_byte_map={1: 1, -1: 1, 0x7fff: 1},
            i32_byte_map={1: 1, -1: 1, 0x7fffffff: 1},
            i64_byte_map={0: 1, 1: 1, -1: 1, 0x7fffffffffffffff: 1},
            double_byte_map={-1.1: 1, 1.1: 1},
            string_byte_map={"first": 1, "second": 2, "third": 3, "": 0},
            boolean_byte_map={True: 1, False: 0},
            byte_i16_map={1: 1, 2: -1, 3: 0x7fff},
            byte_i32_map={1: 1, 2: -1, 3: 0x7fffffff},
            byte_i64_map={1: 1, 2: -1, 3: 0x7fffffffffffffff},
            byte_double_map={1: 0.1, 2: -0.1, 3: 1000000.1},
            byte_string_map={1: "", 2: "blah", 3: "loooooooooooooong string"},
            byte_boolean_map={1: True, 2: False},
            # list_byte_map # unhashable
            # set_byte_map={set([1, 2, 3]) : 1, set([0, 1]) : 2, set([]) : 0}, # unhashable
            # map_byte_map # unhashable
            byte_map_map={0: {}, 1: {1: 1}, 2: {1: 1, 2: 2}},
            byte_set_map={0: set([]), 1: set([1]), 2: set([1, 2])},
            byte_list_map={0: [], 1: [1], 2: [1, 2]},
        )

        self.nested_lists_i32x2 = NestedListsI32x2(
            [
                [1, 1, 2],
                [2, 7, 9],
                [3, 5, 8]
            ]
        )

        self.nested_lists_i32x3 = NestedListsI32x3(
            [
                [
                    [2, 7, 9],
                    [3, 5, 8]
                ],
                [
                    [1, 1, 2],
                    [1, 4, 9]
                ]
            ]
        )

        self.nested_mixedx2 = NestedMixedx2(int_set_list=[
            set([1, 2, 3]),
            set([1, 4, 9]),
            set([1, 2, 3, 5, 8, 13, 21]),
            set([-1, 0, 1])
        ],
            # note, the sets below are sets of chars, since the strings are iterated
            map_int_strset={10: set('abc'), 20: set('def'), 30: set('GHI')},
            map_int_strset_list=[
                {10: set('abc'), 20: set('def'), 30: set('GHI')},
                {100: set('lmn'), 200: set('opq'), 300: set('RST')},
                {1000: set('uvw'), 2000: set('wxy'), 3000: set('XYZ')}]
        )

        self.nested_lists_bonk = NestedListsBonk(
            [
                [
                    [
                        Bonk(message='inner A first', type=1),
                        Bonk(message='inner A second', type=1)
                    ],
                    [
                        Bonk(message='inner B first', type=2),
                        Bonk(message='inner B second', type=2)
                    ]
                ]
            ]
        )

        self.list_bonks = ListBonks(
            [
                Bonk(message='inner A', type=1),
                Bonk(message='inner B', type=2),
                Bonk(message='inner C', type=0)
            ]
        )

    def _serialize(self, obj):
        trans = TTransport.TMemoryBuffer()
        prot = self.protocol_factory.getProtocol(trans)
        obj.write(prot)
        return trans.getvalue()

    def _deserialize(self, objtype, data):
        prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
        ret = objtype()
        ret.read(prot)
        return ret

    def testForwards(self):
        obj = self._deserialize(VersioningTestV2, self._serialize(self.v1obj))
        self.assertEquals(obj.begin_in_both, self.v1obj.begin_in_both)
        self.assertEquals(obj.end_in_both, self.v1obj.end_in_both)

    def testBackwards(self):
        obj = self._deserialize(VersioningTestV1, self._serialize(self.v2obj))
        self.assertEquals(obj.begin_in_both, self.v2obj.begin_in_both)
        self.assertEquals(obj.end_in_both, self.v2obj.end_in_both)

    def testSerializeV1(self):
        obj = self._deserialize(VersioningTestV1, self._serialize(self.v1obj))
        self.assertEquals(obj, self.v1obj)

    def testSerializeV2(self):
        obj = self._deserialize(VersioningTestV2, self._serialize(self.v2obj))
        self.assertEquals(obj, self.v2obj)

    def testBools(self):
        self.assertNotEquals(self.bools, self.bools_flipped)
        self.assertNotEquals(self.bools, self.v1obj)
        obj = self._deserialize(Bools, self._serialize(self.bools))
        self.assertEquals(obj, self.bools)
        obj = self._deserialize(Bools, self._serialize(self.bools_flipped))
        self.assertEquals(obj, self.bools_flipped)
        rep = repr(self.bools)
        self.assertTrue(len(rep) > 0)

    def testLargeDeltas(self):
        # test large field deltas (meaningful in CompactProto only)
        obj = self._deserialize(LargeDeltas, self._serialize(self.large_deltas))
        self.assertEquals(obj, self.large_deltas)
        rep = repr(self.large_deltas)
        self.assertTrue(len(rep) > 0)

    def testNestedListsI32x2(self):
        obj = self._deserialize(NestedListsI32x2, self._serialize(self.nested_lists_i32x2))
        self.assertEquals(obj, self.nested_lists_i32x2)
        rep = repr(self.nested_lists_i32x2)
        self.assertTrue(len(rep) > 0)

    def testNestedListsI32x3(self):
        obj = self._deserialize(NestedListsI32x3, self._serialize(self.nested_lists_i32x3))
        self.assertEquals(obj, self.nested_lists_i32x3)
        rep = repr(self.nested_lists_i32x3)
        self.assertTrue(len(rep) > 0)

    def testNestedMixedx2(self):
        obj = self._deserialize(NestedMixedx2, self._serialize(self.nested_mixedx2))
        self.assertEquals(obj, self.nested_mixedx2)
        rep = repr(self.nested_mixedx2)
        self.assertTrue(len(rep) > 0)

    def testNestedListsBonk(self):
        obj = self._deserialize(NestedListsBonk, self._serialize(self.nested_lists_bonk))
        self.assertEquals(obj, self.nested_lists_bonk)
        rep = repr(self.nested_lists_bonk)
        self.assertTrue(len(rep) > 0)

    def testListBonks(self):
        obj = self._deserialize(ListBonks, self._serialize(self.list_bonks))
        self.assertEquals(obj, self.list_bonks)
        rep = repr(self.list_bonks)
        self.assertTrue(len(rep) > 0)

    def testCompactStruct(self):
        # test large field deltas (meaningful in CompactProto only)
        obj = self._deserialize(CompactProtoTestStruct, self._serialize(self.compact_struct))
        self.assertEquals(obj, self.compact_struct)
        rep = repr(self.compact_struct)
        self.assertTrue(len(rep) > 0)

    def testIntegerLimits(self):
        if (sys.version_info[0] == 2 and sys.version_info[1] <= 6):
            print('Skipping testIntegerLimits for Python 2.6')
            return
        bad_values = [CompactProtoTestStruct(a_byte=128), CompactProtoTestStruct(a_byte=-129),
                      CompactProtoTestStruct(a_i16=32768), CompactProtoTestStruct(a_i16=-32769),
                      CompactProtoTestStruct(a_i32=2147483648), CompactProtoTestStruct(a_i32=-2147483649),
                      CompactProtoTestStruct(a_i64=9223372036854775808), CompactProtoTestStruct(a_i64=-9223372036854775809)
                      ]

        for value in bad_values:
            self.assertRaises(Exception, self._serialize, value)

    def testRecTree(self):
        """Ensure recursive tree node can be created."""
        children = []
        for idx in range(1, 5):
            node = RecTree(item=idx, children=None)
            children.append(node)

        parent = RecTree(item=0, children=children)
        serde_parent = self._deserialize(RecTree, self._serialize(parent))
        self.assertEquals(0, serde_parent.item)
        self.assertEquals(4, len(serde_parent.children))
        for child in serde_parent.children:
            # Cannot use assertIsInstance in python 2.6?
            self.assertTrue(isinstance(child, RecTree))

    def _buildLinkedList(self):
        head = cur = RecList(item=0)
        for idx in range(1, 5):
            node = RecList(item=idx)
            cur.nextitem = node
            cur = node
        return head

    def _collapseLinkedList(self, head):
        out_list = []
        cur = head
        while cur is not None:
            out_list.append(cur.item)
            cur = cur.nextitem
        return out_list

    def testRecList(self):
        """Ensure recursive linked list can be created."""
        rec_list = self._buildLinkedList()
        serde_list = self._deserialize(RecList, self._serialize(rec_list))
        out_list = self._collapseLinkedList(serde_list)
        self.assertEquals([0, 1, 2, 3, 4], out_list)

    def testCoRec(self):
        """Ensure co-recursive structures can be created."""
        item1 = CoRec()
        item2 = CoRec2()

        item1.other = item2
        item2.other = item1

        # NOTE [econner724,2017-06-21]: These objects cannot be serialized as serialization
        # results in an infinite loop. fbthrift also suffers from this
        # problem.

    def testRecVector(self):
        """Ensure a list of recursive nodes can be created."""
        mylist = [self._buildLinkedList(), self._buildLinkedList()]
        myvec = VectorTest(lister=mylist)

        serde_vec = self._deserialize(VectorTest, self._serialize(myvec))
        golden_list = [0, 1, 2, 3, 4]
        for cur_list in serde_vec.lister:
            out_list = self._collapseLinkedList(cur_list)
            self.assertEqual(golden_list, out_list)


class NormalBinaryTest(AbstractTest):
    protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()


class AcceleratedBinaryTest(AbstractTest):
    protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False)


class CompactProtocolTest(AbstractTest):
    protocol_factory = TCompactProtocol.TCompactProtocolFactory()


class AcceleratedCompactTest(AbstractTest):
    protocol_factory = TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False)


class JSONProtocolTest(AbstractTest):
    protocol_factory = TJSONProtocol.TJSONProtocolFactory()


class AcceleratedFramedTest(unittest.TestCase):
    def testSplit(self):
        """Test FramedTransport and BinaryProtocolAccelerated

        Tests that TBinaryProtocolAccelerated and TFramedTransport
        play nicely together when a read spans a frame"""

        protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
        bigstring = "".join(chr(byte) for byte in range(ord("a"), ord("z") + 1))

        databuf = TTransport.TMemoryBuffer()
        prot = protocol_factory.getProtocol(databuf)
        prot.writeI32(42)
        prot.writeString(bigstring)
        prot.writeI16(24)
        data = databuf.getvalue()
        cutpoint = len(data) // 2
        parts = [data[:cutpoint], data[cutpoint:]]

        framed_buffer = TTransport.TMemoryBuffer()
        framed_writer = TTransport.TFramedTransport(framed_buffer)
        for part in parts:
            framed_writer.write(part)
            framed_writer.flush()
        self.assertEquals(len(framed_buffer.getvalue()), len(data) + 8)

        # Recreate framed_buffer so we can read from it.
        framed_buffer = TTransport.TMemoryBuffer(framed_buffer.getvalue())
        framed_reader = TTransport.TFramedTransport(framed_buffer)
        prot = protocol_factory.getProtocol(framed_reader)
        self.assertEqual(prot.readI32(), 42)
        self.assertEqual(prot.readString(), bigstring)
        self.assertEqual(prot.readI16(), 24)


class SerializersTest(unittest.TestCase):

    def testSerializeThenDeserialize(self):
        obj = Xtruct2(i32_thing=1,
                      struct_thing=Xtruct(string_thing="foo"))

        s1 = serialize(obj)
        for i in range(10):
            self.assertEquals(s1, serialize(obj))
            objcopy = Xtruct2()
            deserialize(objcopy, serialize(obj))
            self.assertEquals(obj, objcopy)

        obj = Xtruct(string_thing="bar")
        objcopy = Xtruct()
        deserialize(objcopy, serialize(obj))
        self.assertEquals(obj, objcopy)

        # test booleans
        obj = Bools(im_true=True, im_false=False)
        objcopy = Bools()
        deserialize(objcopy, serialize(obj))
        self.assertEquals(obj, objcopy)

        # test enums
        for num, name in Numberz._VALUES_TO_NAMES.items():
            obj = Bonk(message='enum Numberz value %d is string %s' % (num, name), type=num)
            objcopy = Bonk()
            deserialize(objcopy, serialize(obj))
            self.assertEquals(obj, objcopy)


def suite():
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()

    suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
    suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
    suite.addTest(loader.loadTestsFromTestCase(AcceleratedCompactTest))
    suite.addTest(loader.loadTestsFromTestCase(CompactProtocolTest))
    suite.addTest(loader.loadTestsFromTestCase(JSONProtocolTest))
    suite.addTest(loader.loadTestsFromTestCase(AcceleratedFramedTest))
    suite.addTest(loader.loadTestsFromTestCase(SerializersTest))
    return suite


if __name__ == "__main__":
    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
thrift-0.16.0/test/py/TSimpleJSONProtocolTest.py000066400000000000000000000075571420101504100215120ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

from ThriftTest.ttypes import Bonk, VersioningTestV1, VersioningTestV2
from thrift.protocol import TJSONProtocol
from thrift.transport import TTransport

import json
import unittest


class SimpleJSONProtocolTest(unittest.TestCase):
    protocol_factory = TJSONProtocol.TSimpleJSONProtocolFactory()

    def _assertDictEqual(self, a, b, msg=None):
        if hasattr(self, 'assertDictEqual'):
            # assertDictEqual only in Python 2.7. Depends on your machine.
            self.assertDictEqual(a, b, msg)
            return

        # Substitute implementation not as good as unittest library's
        self.assertEquals(len(a), len(b), msg)
        for k, v in a.iteritems():
            self.assertTrue(k in b, msg)
            self.assertEquals(b.get(k), v, msg)

    def _serialize(self, obj):
        trans = TTransport.TMemoryBuffer()
        prot = self.protocol_factory.getProtocol(trans)
        obj.write(prot)
        return trans.getvalue()

    def _deserialize(self, objtype, data):
        prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
        ret = objtype()
        ret.read(prot)
        return ret

    def testWriteOnly(self):
        self.assertRaises(NotImplementedError,
                          self._deserialize, VersioningTestV1, b'{}')

    def testSimpleMessage(self):
        v1obj = VersioningTestV1(
            begin_in_both=12345,
            old_string='aaa',
            end_in_both=54321)
        expected = dict(begin_in_both=v1obj.begin_in_both,
                        old_string=v1obj.old_string,
                        end_in_both=v1obj.end_in_both)
        actual = json.loads(self._serialize(v1obj).decode('ascii'))

        self._assertDictEqual(expected, actual)

    def testComplicated(self):
        v2obj = VersioningTestV2(
            begin_in_both=12345,
            newint=1,
            newbyte=2,
            newshort=3,
            newlong=4,
            newdouble=5.0,
            newstruct=Bonk(message="Hello!", type=123),
            newlist=[7, 8, 9],
            newset=set([42, 1, 8]),
            newmap={1: 2, 2: 3},
            newstring="Hola!",
            end_in_both=54321)
        expected = dict(begin_in_both=v2obj.begin_in_both,
                        newint=v2obj.newint,
                        newbyte=v2obj.newbyte,
                        newshort=v2obj.newshort,
                        newlong=v2obj.newlong,
                        newdouble=v2obj.newdouble,
                        newstruct=dict(message=v2obj.newstruct.message,
                                       type=v2obj.newstruct.type),
                        newlist=v2obj.newlist,
                        newset=list(v2obj.newset),
                        newmap=v2obj.newmap,
                        newstring=v2obj.newstring,
                        end_in_both=v2obj.end_in_both)

        # Need to load/dump because map keys get escaped.
        expected = json.loads(json.dumps(expected))
        actual = json.loads(self._serialize(v2obj).decode('ascii'))
        self._assertDictEqual(expected, actual)


if __name__ == '__main__':
    unittest.main()
thrift-0.16.0/test/py/TestClient.py000077500000000000000000000527761420101504100171450ustar00rootroot00000000000000#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

import os
import sys
import time
import unittest

from optparse import OptionParser
from util import local_libpath
sys.path.insert(0, local_libpath())
from thrift.protocol import TProtocol, TProtocolDecorator

SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))


class AbstractTest(unittest.TestCase):
    def setUp(self):
        if options.trans == 'http':
            uri = '{0}://{1}:{2}{3}'.format(('https' if options.ssl else 'http'),
                                            options.host,
                                            options.port,
                                            (options.http_path if options.http_path else '/'))
            if options.ssl:
                __cafile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "CA.pem")
                __certfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "client.crt")
                __keyfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "client.key")
                self.transport = THttpClient.THttpClient(uri, cafile=__cafile, cert_file=__certfile, key_file=__keyfile)
            else:
                self.transport = THttpClient.THttpClient(uri)
        else:
            if options.ssl:
                from thrift.transport import TSSLSocket
                socket = TSSLSocket.TSSLSocket(options.host, options.port, validate=False)
            else:
                socket = TSocket.TSocket(options.host, options.port, options.domain_socket)
            # frame or buffer depending upon args
            self.transport = TTransport.TBufferedTransport(socket)
            if options.trans == 'framed':
                self.transport = TTransport.TFramedTransport(socket)
            elif options.trans == 'buffered':
                self.transport = TTransport.TBufferedTransport(socket)
            elif options.trans == '':
                raise AssertionError('Unknown --transport option: %s' % options.trans)
            if options.zlib:
                self.transport = TZlibTransport.TZlibTransport(self.transport, 9)
        self.transport.open()
        protocol = self.get_protocol(self.transport)
        self.client = ThriftTest.Client(protocol)
        # for multiplexed services:
        protocol2 = self.get_protocol2(self.transport)
        self.client2 = SecondService.Client(protocol2) if protocol2 is not None else None

    def tearDown(self):
        self.transport.close()

    def testVoid(self):
        print('testVoid')
        self.client.testVoid()

    def testString(self):
        print('testString')
        self.assertEqual(self.client.testString('Python' * 20), 'Python' * 20)
        self.assertEqual(self.client.testString(''), '')
        s1 = u'\b\t\n/\\\\\r{}:パイソン"'
        s2 = u"""Afrikaans, Alemannisch, Aragonés, العربية, مصرى,
        Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška,
        Беларуская, Беларуская (тарашкевіца), Български, Bamanankan,
        বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн,
        Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg,
        Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English,
        Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt,
        Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego,
        Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski,
        Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia,
        Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa,
        ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар,
        Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino,
        Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa
        Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa
        Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪
        Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad,
        Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو,
        Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română,
        Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple
        English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk,
        Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog,
        Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük,
        Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文,
        Bân-lâm-gú, 粵語"""
        if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
            s1 = s1.encode('utf8')
            s2 = s2.encode('utf8')
        self.assertEqual(self.client.testString(s1), s1)
        self.assertEqual(self.client.testString(s2), s2)

    def testMultiplexed(self):
        if self.client2 is not None:
            print('testMultiplexed')
            self.assertEqual(self.client2.secondtestString('foobar'), 'testString("foobar")')

    def testBool(self):
        print('testBool')
        self.assertEqual(self.client.testBool(True), True)
        self.assertEqual(self.client.testBool(False), False)

    def testByte(self):
        print('testByte')
        self.assertEqual(self.client.testByte(63), 63)
        self.assertEqual(self.client.testByte(-127), -127)

    def testI32(self):
        print('testI32')
        self.assertEqual(self.client.testI32(-1), -1)
        self.assertEqual(self.client.testI32(0), 0)

    def testI64(self):
        print('testI64')
        self.assertEqual(self.client.testI64(1), 1)
        self.assertEqual(self.client.testI64(-34359738368), -34359738368)

    def testDouble(self):
        print('testDouble')
        self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
        self.assertEqual(self.client.testDouble(0), 0)
        self.assertEqual(self.client.testDouble(-1), -1)
        self.assertEqual(self.client.testDouble(-0.000341012439638598279), -0.000341012439638598279)

    def testBinary(self):
        print('testBinary')
        val = bytearray([i for i in range(0, 256)])
        self.assertEqual(bytearray(self.client.testBinary(bytes(val))), val)

    def testStruct(self):
        print('testStruct')
        x = Xtruct()
        x.string_thing = "Zero"
        x.byte_thing = 1
        x.i32_thing = -3
        x.i64_thing = -5
        y = self.client.testStruct(x)
        self.assertEqual(y, x)

    def testNest(self):
        print('testNest')
        inner = Xtruct(string_thing="Zero", byte_thing=1, i32_thing=-3, i64_thing=-5)
        x = Xtruct2(struct_thing=inner, byte_thing=0, i32_thing=0)
        y = self.client.testNest(x)
        self.assertEqual(y, x)

    def testMap(self):
        print('testMap')
        x = {0: 1, 1: 2, 2: 3, 3: 4, -1: -2}
        y = self.client.testMap(x)
        self.assertEqual(y, x)

    def testSet(self):
        print('testSet')
        x = set([8, 1, 42])
        y = self.client.testSet(x)
        self.assertEqual(y, x)

    def testList(self):
        print('testList')
        x = [1, 4, 9, -42]
        y = self.client.testList(x)
        self.assertEqual(y, x)

    def testEnum(self):
        print('testEnum')
        x = Numberz.FIVE
        y = self.client.testEnum(x)
        self.assertEqual(y, x)

    def testTypedef(self):
        print('testTypedef')
        x = 0xffffffffffffff  # 7 bytes of 0xff
        y = self.client.testTypedef(x)
        self.assertEqual(y, x)

    def testMapMap(self):
        print('testMapMap')
        x = {
            -4: {-4: -4, -3: -3, -2: -2, -1: -1},
            4: {4: 4, 3: 3, 2: 2, 1: 1},
        }
        y = self.client.testMapMap(42)
        self.assertEqual(y, x)

    def testMulti(self):
        print('testMulti')
        xpected = Xtruct(string_thing='Hello2', byte_thing=74, i32_thing=0xff00ff, i64_thing=0xffffffffd0d0)
        y = self.client.testMulti(xpected.byte_thing,
                                  xpected.i32_thing,
                                  xpected.i64_thing,
                                  {0: 'abc'},
                                  Numberz.FIVE,
                                  0xf0f0f0)
        self.assertEqual(y, xpected)

    def testException(self):
        print('testException')
        self.client.testException('Safe')
        try:
            self.client.testException('Xception')
            self.fail("should have gotten exception")
        except Xception as x:
            self.assertEqual(x.errorCode, 1001)
            self.assertEqual(x.message, 'Xception')
            # TODO ensure same behavior for repr within generated python variants
            # ensure exception's repr method works
            # x_repr = repr(x)
            # self.assertEqual(x_repr, 'Xception(errorCode=1001, message=\'Xception\')')

        try:
            self.client.testException('TException')
            self.fail("should have gotten exception")
        except TException as x:
            pass

        # Should not throw
        self.client.testException('success')

    def testMultiException(self):
        print('testMultiException')
        try:
            self.client.testMultiException('Xception', 'ignore')
        except Xception as ex:
            self.assertEqual(ex.errorCode, 1001)
            self.assertEqual(ex.message, 'This is an Xception')

        try:
            self.client.testMultiException('Xception2', 'ignore')
        except Xception2 as ex:
            self.assertEqual(ex.errorCode, 2002)
            self.assertEqual(ex.struct_thing.string_thing, 'This is an Xception2')

        y = self.client.testMultiException('success', 'foobar')
        self.assertEqual(y.string_thing, 'foobar')

    def testOneway(self):
        print('testOneway')
        start = time.time()
        self.client.testOneway(1)  # type is int, not float
        end = time.time()
        self.assertTrue(end - start < 3,
                        "oneway sleep took %f sec" % (end - start))

    def testOnewayThenNormal(self):
        print('testOnewayThenNormal')
        self.client.testOneway(1)  # type is int, not float
        self.assertEqual(self.client.testString('Python'), 'Python')


# LAST_SEQID is a global because we have one transport and multiple protocols
# running on it (when multiplexed)
LAST_SEQID = None


class TPedanticSequenceIdProtocolWrapper(TProtocolDecorator.TProtocolDecorator):
    """
    Wraps any protocol with sequence ID checking: looks for outbound
    uniqueness as well as request/response alignment.
    """
    def __init__(self, protocol):
        # TProtocolDecorator.__new__ does all the heavy lifting
        pass

    def writeMessageBegin(self, name, type, seqid):
        global LAST_SEQID
        if LAST_SEQID and LAST_SEQID == seqid:
            raise TProtocol.TProtocolException(
                TProtocol.TProtocolException.INVALID_DATA,
                "Python client reused sequence ID {0}".format(seqid))
        LAST_SEQID = seqid
        super(TPedanticSequenceIdProtocolWrapper, self).writeMessageBegin(
            name, type, seqid)

    def readMessageBegin(self):
        global LAST_SEQID
        (name, type, seqid) =\
            super(TPedanticSequenceIdProtocolWrapper, self).readMessageBegin()
        if LAST_SEQID != seqid:
            raise TProtocol.TProtocolException(
                TProtocol.TProtocolException.INVALID_DATA,
                "We sent seqid {0} and server returned seqid {1}".format(
                    self.last, seqid))
        return (name, type, seqid)


def make_pedantic(proto):
    """ Wrap a protocol in the pedantic sequence ID wrapper. """
    return TPedanticSequenceIdProtocolWrapper(proto)


class MultiplexedOptionalTest(AbstractTest):
    def get_protocol2(self, transport):
        return None


class BinaryTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        return make_pedantic(TBinaryProtocol.TBinaryProtocolFactory().getProtocol(transport))


class MultiplexedBinaryTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        wrapped_proto = make_pedantic(TBinaryProtocol.TBinaryProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")

    def get_protocol2(self, transport):
        wrapped_proto = make_pedantic(TBinaryProtocol.TBinaryProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")


class AcceleratedBinaryTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        return make_pedantic(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(transport))


class MultiplexedAcceleratedBinaryTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        wrapped_proto = make_pedantic(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")

    def get_protocol2(self, transport):
        wrapped_proto = make_pedantic(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")


class CompactTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        return make_pedantic(TCompactProtocol.TCompactProtocolFactory().getProtocol(transport))


class MultiplexedCompactTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        wrapped_proto = make_pedantic(TCompactProtocol.TCompactProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")

    def get_protocol2(self, transport):
        wrapped_proto = make_pedantic(TCompactProtocol.TCompactProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")


class AcceleratedCompactTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        return make_pedantic(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(transport))


class MultiplexedAcceleratedCompactTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        wrapped_proto = make_pedantic(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")

    def get_protocol2(self, transport):
        wrapped_proto = make_pedantic(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")


class JSONTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        return make_pedantic(TJSONProtocol.TJSONProtocolFactory().getProtocol(transport))


class MultiplexedJSONTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        wrapped_proto = make_pedantic(TJSONProtocol.TJSONProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")

    def get_protocol2(self, transport):
        wrapped_proto = make_pedantic(TJSONProtocol.TJSONProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")


class HeaderTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        factory = THeaderProtocol.THeaderProtocolFactory()
        return make_pedantic(factory.getProtocol(transport))


class MultiplexedHeaderTest(MultiplexedOptionalTest):
    def get_protocol(self, transport):
        wrapped_proto = make_pedantic(THeaderProtocol.THeaderProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")

    def get_protocol2(self, transport):
        wrapped_proto = make_pedantic(THeaderProtocol.THeaderProtocolFactory().getProtocol(transport))
        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")


def suite():
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()
    if options.proto == 'binary':  # look for --proto on cmdline
        suite.addTest(loader.loadTestsFromTestCase(BinaryTest))
    elif options.proto == 'accel':
        suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
    elif options.proto == 'accelc':
        suite.addTest(loader.loadTestsFromTestCase(AcceleratedCompactTest))
    elif options.proto == 'compact':
        suite.addTest(loader.loadTestsFromTestCase(CompactTest))
    elif options.proto == 'header':
        suite.addTest(loader.loadTestsFromTestCase(HeaderTest))
    elif options.proto == 'json':
        suite.addTest(loader.loadTestsFromTestCase(JSONTest))
    elif options.proto == 'multi':
        suite.addTest(loader.loadTestsFromTestCase(MultiplexedBinaryTest))
    elif options.proto == 'multia':
        suite.addTest(loader.loadTestsFromTestCase(MultiplexedAcceleratedBinaryTest))
    elif options.proto == 'multiac':
        suite.addTest(loader.loadTestsFromTestCase(MultiplexedAcceleratedCompactTest))
    elif options.proto == 'multic':
        suite.addTest(loader.loadTestsFromTestCase(MultiplexedCompactTest))
    elif options.proto == 'multih':
        suite.addTest(loader.loadTestsFromTestCase(MultiplexedHeaderTest))
    elif options.proto == 'multij':
        suite.addTest(loader.loadTestsFromTestCase(MultiplexedJSONTest))
    else:
        raise AssertionError('Unknown protocol given with --protocol: %s' % options.proto)
    return suite


class OwnArgsTestProgram(unittest.TestProgram):
    def parseArgs(self, argv):
        if args:
            self.testNames = args
        else:
            self.testNames = ([self.defaultTest])
        self.createTests()


if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option('--libpydir', type='string', dest='libpydir',
                      help='include this directory in sys.path for locating library code')
    parser.add_option('--genpydir', type='string', dest='genpydir',
                      help='include this directory in sys.path for locating generated code')
    parser.add_option("--port", type="int", dest="port",
                      help="connect to server at port")
    parser.add_option("--host", type="string", dest="host",
                      help="connect to server")
    parser.add_option("--zlib", action="store_true", dest="zlib",
                      help="use zlib wrapper for compressed transport")
    parser.add_option("--ssl", action="store_true", dest="ssl",
                      help="use SSL for encrypted transport")
    parser.add_option("--http", dest="http_path",
                      help="Use the HTTP transport with the specified path")
    parser.add_option('-v', '--verbose', action="store_const",
                      dest="verbose", const=2,
                      help="verbose output")
    parser.add_option('-q', '--quiet', action="store_const",
                      dest="verbose", const=0,
                      help="minimal output")
    parser.add_option('--protocol', dest="proto", type="string",
                      help="protocol to use, one of: accel, accelc, binary, compact, header, json, multi, multia, multiac, multic, multih, multij")
    parser.add_option('--transport', dest="trans", type="string",
                      help="transport to use, one of: buffered, framed, http")
    parser.add_option('--domain-socket', dest="domain_socket", type="string",
                      help="Unix domain socket path")
    parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090, proto='binary')
    options, args = parser.parse_args()

    if options.genpydir:
        sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))

    if options.http_path:
        options.trans = 'http'

    from ThriftTest import SecondService
    from ThriftTest import ThriftTest
    from ThriftTest.ttypes import Xtruct, Xtruct2, Numberz, Xception, Xception2
    from thrift.Thrift import TException
    from thrift.transport import TTransport
    from thrift.transport import TSocket
    from thrift.transport import THttpClient
    from thrift.transport import TZlibTransport
    from thrift.protocol import TBinaryProtocol
    from thrift.protocol import TCompactProtocol
    from thrift.protocol import THeaderProtocol
    from thrift.protocol import TJSONProtocol
    from thrift.protocol import TMultiplexedProtocol

    OwnArgsTestProgram(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=1))
thrift-0.16.0/test/py/TestEof.py000077500000000000000000000107761420101504100164320ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

from ThriftTest.ttypes import Xtruct
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.protocol import TCompactProtocol
import unittest


class TestEof(unittest.TestCase):

    def make_data(self, pfactory=None):
        trans = TTransport.TMemoryBuffer()
        if pfactory:
            prot = pfactory.getProtocol(trans)
        else:
            prot = TBinaryProtocol.TBinaryProtocol(trans)

        x = Xtruct()
        x.string_thing = "Zero"
        x.byte_thing = 0

        x.write(prot)

        x = Xtruct()
        x.string_thing = "One"
        x.byte_thing = 1

        x.write(prot)

        return trans.getvalue()

    def testTransportReadAll(self):
        """Test that readAll on any type of transport throws an EOFError"""
        trans = TTransport.TMemoryBuffer(self.make_data())
        trans.readAll(1)

        try:
            trans.readAll(10000)
        except EOFError:
            return

        self.fail("Should have gotten EOFError")

    def eofTestHelper(self, pfactory):
        trans = TTransport.TMemoryBuffer(self.make_data(pfactory))
        prot = pfactory.getProtocol(trans)

        x = Xtruct()
        x.read(prot)
        self.assertEqual(x.string_thing, "Zero")
        self.assertEqual(x.byte_thing, 0)

        x = Xtruct()
        x.read(prot)
        self.assertEqual(x.string_thing, "One")
        self.assertEqual(x.byte_thing, 1)

        try:
            x = Xtruct()
            x.read(prot)
        except EOFError:
            return

        self.fail("Should have gotten EOFError")

    def eofTestHelperStress(self, pfactory):
        """Test the ability of TBinaryProtocol to deal with the removal of every byte in the file"""
        # TODO: we should make sure this covers more of the code paths

        data = self.make_data(pfactory)
        for i in range(0, len(data) + 1):
            trans = TTransport.TMemoryBuffer(data[0:i])
            prot = pfactory.getProtocol(trans)
            try:
                x = Xtruct()
                x.read(prot)
                x.read(prot)
                x.read(prot)
            except EOFError:
                continue
            self.fail("Should have gotten an EOFError")

    def testBinaryProtocolEof(self):
        """Test that TBinaryProtocol throws an EOFError when it reaches the end of the stream"""
        self.eofTestHelper(TBinaryProtocol.TBinaryProtocolFactory())
        self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolFactory())

    def testBinaryProtocolAcceleratedBinaryEof(self):
        """Test that TBinaryProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
        self.eofTestHelper(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False))
        self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False))

    def testCompactProtocolEof(self):
        """Test that TCompactProtocol throws an EOFError when it reaches the end of the stream"""
        self.eofTestHelper(TCompactProtocol.TCompactProtocolFactory())
        self.eofTestHelperStress(TCompactProtocol.TCompactProtocolFactory())

    def testCompactProtocolAcceleratedCompactEof(self):
        """Test that TCompactProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
        self.eofTestHelper(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False))
        self.eofTestHelperStress(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False))


def suite():
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestEof))
    return suite


if __name__ == "__main__":
    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
thrift-0.16.0/test/py/TestFrozen.py000077500000000000000000000126021420101504100171520ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

from DebugProtoTest import Srv
from DebugProtoTest.ttypes import CompactProtoTestStruct, Empty, Wrapper
from DebugProtoTest.ttypes import ExceptionWithAMap, MutableException, ExceptionWithoutFields
from thrift.Thrift import TFrozenDict
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol, TCompactProtocol
import collections
import unittest


class TestFrozenBase(unittest.TestCase):
    def _roundtrip(self, src, dst):
        otrans = TTransport.TMemoryBuffer()
        optoro = self.protocol(otrans)
        src.write(optoro)
        itrans = TTransport.TMemoryBuffer(otrans.getvalue())
        iproto = self.protocol(itrans)
        return dst.read(iproto) or dst

    def test_dict_is_hashable_only_after_frozen(self):
        d0 = {}
        self.assertFalse(isinstance(d0, collections.Hashable))
        d1 = TFrozenDict(d0)
        self.assertTrue(isinstance(d1, collections.Hashable))

    def test_struct_with_collection_fields(self):
        pass

    def test_set(self):
        """Test that annotated set field can be serialized and deserialized"""
        x = CompactProtoTestStruct(set_byte_map={
            frozenset([42, 100, -100]): 99,
            frozenset([0]): 100,
            frozenset([]): 0,
        })
        x2 = self._roundtrip(x, CompactProtoTestStruct())
        self.assertEqual(x2.set_byte_map[frozenset([42, 100, -100])], 99)
        self.assertEqual(x2.set_byte_map[frozenset([0])], 100)
        self.assertEqual(x2.set_byte_map[frozenset([])], 0)

    def test_map(self):
        """Test that annotated map field can be serialized and deserialized"""
        x = CompactProtoTestStruct(map_byte_map={
            TFrozenDict({42: 42, 100: -100}): 99,
            TFrozenDict({0: 0}): 100,
            TFrozenDict({}): 0,
        })
        x2 = self._roundtrip(x, CompactProtoTestStruct())
        self.assertEqual(x2.map_byte_map[TFrozenDict({42: 42, 100: -100})], 99)
        self.assertEqual(x2.map_byte_map[TFrozenDict({0: 0})], 100)
        self.assertEqual(x2.map_byte_map[TFrozenDict({})], 0)

    def test_list(self):
        """Test that annotated list field can be serialized and deserialized"""
        x = CompactProtoTestStruct(list_byte_map={
            (42, 100, -100): 99,
            (0,): 100,
            (): 0,
        })
        x2 = self._roundtrip(x, CompactProtoTestStruct())
        self.assertEqual(x2.list_byte_map[(42, 100, -100)], 99)
        self.assertEqual(x2.list_byte_map[(0,)], 100)
        self.assertEqual(x2.list_byte_map[()], 0)

    def test_empty_struct(self):
        """Test that annotated empty struct can be serialized and deserialized"""
        x = CompactProtoTestStruct(empty_struct_field=Empty())
        x2 = self._roundtrip(x, CompactProtoTestStruct())
        self.assertEqual(x2.empty_struct_field, Empty())

    def test_struct(self):
        """Test that annotated struct can be serialized and deserialized"""
        x = Wrapper(foo=Empty())
        self.assertEqual(x.foo, Empty())
        x2 = self._roundtrip(x, Wrapper)
        self.assertEqual(x2.foo, Empty())

    def test_frozen_exception(self):
        exc = ExceptionWithAMap(blah='foo')
        with self.assertRaises(TypeError):
            exc.blah = 'bar'
        mutexc = MutableException(msg='foo')
        mutexc.msg = 'bar'
        self.assertEqual(mutexc.msg, 'bar')

    def test_frozen_exception_with_no_fields(self):
        ExceptionWithoutFields()

    def test_frozen_exception_serialization(self):
        result = Srv.declaredExceptionMethod_result(
            xwamap=ExceptionWithAMap(blah="error"))
        deserialized = self._roundtrip(
            result, Srv.declaredExceptionMethod_result())
        self.assertEqual(result, deserialized)


class TestFrozen(TestFrozenBase):
    def protocol(self, trans):
        return TBinaryProtocol.TBinaryProtocolFactory().getProtocol(trans)


class TestFrozenAcceleratedBinary(TestFrozenBase):
    def protocol(self, trans):
        return TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(trans)


class TestFrozenAcceleratedCompact(TestFrozenBase):
    def protocol(self, trans):
        return TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(trans)


def suite():
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestFrozen))
    suite.addTest(loader.loadTestsFromTestCase(TestFrozenAcceleratedBinary))
    suite.addTest(loader.loadTestsFromTestCase(TestFrozenAcceleratedCompact))
    return suite


if __name__ == "__main__":
    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
thrift-0.16.0/test/py/TestRenderedDoubleConstants.py000066400000000000000000000245201420101504100224660ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

import unittest

from DoubleConstantsTest import constants

#
# In order to run the test under Windows. We need to create symbolic link
# name 'thrift' to '../src' folder by using:
#
# mklink /D thrift ..\src
#


class TestRenderedDoubleConstants(unittest.TestCase):
    ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST = \
        "failed to verify a double constant generated by Thrift (expected = %f, got = %f)"
    ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_LIST_TEST =\
        "failed to verify a list item by Thrift (expected = %f, got = %f)"
    ASSERTION_MESSAGE_FOR_TYPE_CHECKS = "the rendered variable with name %s is not of double type"

    # to make sure the variables inside Thrift files are generated correctly
    def test_rendered_double_constants(self):
        EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1.0
        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100.0
        EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807.0
        EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807.0
        EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359
        EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1
        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1
        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308
        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43
        EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308
        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT, places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT, constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
            places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
            places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
                constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
            places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
                constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST,
            EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS, places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS,
                constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
            places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
                constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST,
            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE, places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE,
                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE, places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE,
                constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST,
            EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE, places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE,
                constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE, places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE,
                constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST))
        self.assertAlmostEqual(
            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST,
            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE, places=7,
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE,
                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST))
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST")
        self.assertTrue(
            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST, float),
            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
            "DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST")

    # to make sure the variables inside Thrift files are generated correctly
    def test_rendered_double_list(self):
        EXPECTED_DOUBLE_LIST = [1.0, -100.0, 100.0, 9223372036854775807.0, -9223372036854775807.0, 3.14159265359,
                                1000000.1, -1000000.1, 1.7e+308, -1.7e+308, 9223372036854775816.43,
                                -9223372036854775816.43]
        self.assertEqual(len(constants.DOUBLE_LIST_TEST), len(EXPECTED_DOUBLE_LIST))
        for i, expectedValue in enumerate(EXPECTED_DOUBLE_LIST):
            self.assertAlmostEqual(constants.DOUBLE_LIST_TEST[i], expectedValue, places=7)


def suite():
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestRenderedDoubleConstants))
    return suite


if __name__ == "__main__":
    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
thrift-0.16.0/test/py/TestServer.py000077500000000000000000000367231420101504100171670ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
from __future__ import division
import logging
import os
import signal
import sys
import time
from optparse import OptionParser

from util import local_libpath
sys.path.insert(0, local_libpath())
from thrift.protocol import TProtocol, TProtocolDecorator

SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))


class TestHandler(object):
    def testVoid(self):
        if options.verbose > 1:
            logging.info('testVoid()')

    def testString(self, str):
        if options.verbose > 1:
            logging.info('testString(%s)' % str)
        return str

    def testBool(self, boolean):
        if options.verbose > 1:
            logging.info('testBool(%s)' % str(boolean).lower())
        return boolean

    def testByte(self, byte):
        if options.verbose > 1:
            logging.info('testByte(%d)' % byte)
        return byte

    def testI16(self, i16):
        if options.verbose > 1:
            logging.info('testI16(%d)' % i16)
        return i16

    def testI32(self, i32):
        if options.verbose > 1:
            logging.info('testI32(%d)' % i32)
        return i32

    def testI64(self, i64):
        if options.verbose > 1:
            logging.info('testI64(%d)' % i64)
        return i64

    def testDouble(self, dub):
        if options.verbose > 1:
            logging.info('testDouble(%f)' % dub)
        return dub

    def testBinary(self, thing):
        if options.verbose > 1:
            logging.info('testBinary()')  # TODO: hex output
        return thing

    def testStruct(self, thing):
        if options.verbose > 1:
            logging.info('testStruct({%s, %s, %s, %s})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing))
        return thing

    def testException(self, arg):
        # if options.verbose > 1:
        logging.info('testException(%s)' % arg)
        if arg == 'Xception':
            raise Xception(errorCode=1001, message=arg)
        elif arg == 'TException':
            raise TException(message='This is a TException')

    def testMultiException(self, arg0, arg1):
        if options.verbose > 1:
            logging.info('testMultiException(%s, %s)' % (arg0, arg1))
        if arg0 == 'Xception':
            raise Xception(errorCode=1001, message='This is an Xception')
        elif arg0 == 'Xception2':
            raise Xception2(
                errorCode=2002,
                struct_thing=Xtruct(string_thing='This is an Xception2'))
        return Xtruct(string_thing=arg1)

    def testOneway(self, seconds):
        if options.verbose > 1:
            logging.info('testOneway(%d) => sleeping...' % seconds)
        time.sleep(seconds / 3)  # be quick
        if options.verbose > 1:
            logging.info('done sleeping')

    def testNest(self, thing):
        if options.verbose > 1:
            logging.info('testNest(%s)' % thing)
        return thing

    def testMap(self, thing):
        if options.verbose > 1:
            logging.info('testMap(%s)' % thing)
        return thing

    def testStringMap(self, thing):
        if options.verbose > 1:
            logging.info('testStringMap(%s)' % thing)
        return thing

    def testSet(self, thing):
        if options.verbose > 1:
            logging.info('testSet(%s)' % thing)
        return thing

    def testList(self, thing):
        if options.verbose > 1:
            logging.info('testList(%s)' % thing)
        return thing

    def testEnum(self, thing):
        if options.verbose > 1:
            logging.info('testEnum(%s)' % thing)
        return thing

    def testTypedef(self, thing):
        if options.verbose > 1:
            logging.info('testTypedef(%s)' % thing)
        return thing

    def testMapMap(self, thing):
        if options.verbose > 1:
            logging.info('testMapMap(%s)' % thing)
        return {
            -4: {
                -4: -4,
                -3: -3,
                -2: -2,
                -1: -1,
            },
            4: {
                4: 4,
                3: 3,
                2: 2,
                1: 1,
            },
        }

    def testInsanity(self, argument):
        if options.verbose > 1:
            logging.info('testInsanity(%s)' % argument)
        return {
            1: {
                2: argument,
                3: argument,
            },
            2: {6: Insanity()},
        }

    def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
        if options.verbose > 1:
            logging.info('testMulti(%s, %s, %s, %s, %s, %s)' % (arg0, arg1, arg2, arg3, arg4, arg5))
        return Xtruct(string_thing='Hello2',
                      byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)


class SecondHandler(object):
    def secondtestString(self, argument):
        return "testString(\"" + argument + "\")"


# LAST_SEQID is a global because we have one transport and multiple protocols
# running on it (when multiplexed)
LAST_SEQID = None


class TPedanticSequenceIdProtocolWrapper(TProtocolDecorator.TProtocolDecorator):
    """
    Wraps any protocol with sequence ID checking: looks for outbound
    uniqueness as well as request/response alignment.
    """
    def __init__(self, protocol):
        # TProtocolDecorator.__new__ does all the heavy lifting
        pass

    def readMessageBegin(self):
        global LAST_SEQID
        (name, type, seqid) =\
            super(TPedanticSequenceIdProtocolWrapper, self).readMessageBegin()
        if LAST_SEQID is not None and LAST_SEQID == seqid:
            raise TProtocol.TProtocolException(
                TProtocol.TProtocolException.INVALID_DATA,
                "We received the same seqid {0} twice in a row".format(seqid))
        LAST_SEQID = seqid
        return (name, type, seqid)


def make_pedantic(proto):
    """ Wrap a protocol in the pedantic sequence ID wrapper. """
    # NOTE: this is disabled for now as many clients send seqid
    #       of zero and that is okay, need a way to identify
    #       clients that MUST send seqid unique to function right
    #       or just force all implementations to send unique seqids (preferred)
    return proto  # TPedanticSequenceIdProtocolWrapper(proto)


class TPedanticSequenceIdProtocolFactory(TProtocol.TProtocolFactory):
    def __init__(self, encapsulated):
        super(TPedanticSequenceIdProtocolFactory, self).__init__()
        self.encapsulated = encapsulated

    def getProtocol(self, trans):
        return make_pedantic(self.encapsulated.getProtocol(trans))


def main(options):
    # common header allowed client types
    allowed_client_types = [
        THeaderTransport.THeaderClientType.HEADERS,
        THeaderTransport.THeaderClientType.FRAMED_BINARY,
        THeaderTransport.THeaderClientType.UNFRAMED_BINARY,
        THeaderTransport.THeaderClientType.FRAMED_COMPACT,
        THeaderTransport.THeaderClientType.UNFRAMED_COMPACT,
    ]

    # set up the protocol factory form the --protocol option
    prot_factories = {
        'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory(),
        'multia': TBinaryProtocol.TBinaryProtocolAcceleratedFactory(),
        'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory(),
        'multiac': TCompactProtocol.TCompactProtocolAcceleratedFactory(),
        'binary': TPedanticSequenceIdProtocolFactory(TBinaryProtocol.TBinaryProtocolFactory()),
        'multi': TPedanticSequenceIdProtocolFactory(TBinaryProtocol.TBinaryProtocolFactory()),
        'compact': TCompactProtocol.TCompactProtocolFactory(),
        'multic': TCompactProtocol.TCompactProtocolFactory(),
        'header': THeaderProtocol.THeaderProtocolFactory(allowed_client_types),
        'multih': THeaderProtocol.THeaderProtocolFactory(allowed_client_types),
        'json': TJSONProtocol.TJSONProtocolFactory(),
        'multij': TJSONProtocol.TJSONProtocolFactory(),
    }
    pfactory = prot_factories.get(options.proto, None)
    if pfactory is None:
        raise AssertionError('Unknown --protocol option: %s' % options.proto)
    try:
        pfactory.string_length_limit = options.string_limit
        pfactory.container_length_limit = options.container_limit
    except Exception:
        # Ignore errors for those protocols that does not support length limit
        pass

    # get the server type (TSimpleServer, TNonblockingServer, etc...)
    if len(args) > 1:
        raise AssertionError('Only one server type may be specified, not multiple types.')
    server_type = args[0]
    if options.trans == 'http':
        server_type = 'THttpServer'

    # Set up the handler and processor objects
    handler = TestHandler()
    processor = ThriftTest.Processor(handler)

    if options.proto.startswith('multi'):
        secondHandler = SecondHandler()
        secondProcessor = SecondService.Processor(secondHandler)

        multiplexedProcessor = TMultiplexedProcessor()
        multiplexedProcessor.registerDefault(processor)
        multiplexedProcessor.registerProcessor('ThriftTest', processor)
        multiplexedProcessor.registerProcessor('SecondService', secondProcessor)
        processor = multiplexedProcessor

    global server

    # Handle THttpServer as a special case
    if server_type == 'THttpServer':
        if options.ssl:
            __certfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.crt")
            __keyfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.key")
            server = THttpServer.THttpServer(processor, ('', options.port), pfactory, cert_file=__certfile, key_file=__keyfile)
        else:
            server = THttpServer.THttpServer(processor, ('', options.port), pfactory)
        server.serve()
        sys.exit(0)

    # set up server transport and transport factory

    abs_key_path = os.path.join(os.path.dirname(SCRIPT_DIR), 'keys', 'server.pem')

    host = None
    if options.ssl:
        from thrift.transport import TSSLSocket
        transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile=abs_key_path)
    else:
        transport = TSocket.TServerSocket(host, options.port, options.domain_socket)
    tfactory = TTransport.TBufferedTransportFactory()
    if options.trans == 'buffered':
        tfactory = TTransport.TBufferedTransportFactory()
    elif options.trans == 'framed':
        tfactory = TTransport.TFramedTransportFactory()
    elif options.trans == '':
        raise AssertionError('Unknown --transport option: %s' % options.trans)
    else:
        tfactory = TTransport.TBufferedTransportFactory()
    # if --zlib, then wrap server transport, and use a different transport factory
    if options.zlib:
        transport = TZlibTransport.TZlibTransport(transport)  # wrap  with zlib
        tfactory = TZlibTransport.TZlibTransportFactory()

    # do server-specific setup here:
    if server_type == "TNonblockingServer":
        server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
    elif server_type == "TProcessPoolServer":
        import signal
        from thrift.server import TProcessPoolServer
        server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
        server.setNumWorkers(5)

        def set_alarm():
            def clean_shutdown(signum, frame):
                for worker in server.workers:
                    if options.verbose > 0:
                        logging.info('Terminating worker: %s' % worker)
                    worker.terminate()
                if options.verbose > 0:
                    logging.info('Requesting server to stop()')
                try:
                    server.stop()
                except Exception:
                    pass
            signal.signal(signal.SIGALRM, clean_shutdown)
            signal.alarm(4)
        set_alarm()
    else:
        # look up server class dynamically to instantiate server
        ServerClass = getattr(TServer, server_type)
        server = ServerClass(processor, transport, tfactory, pfactory)
    # enter server main loop
    server.serve()


def exit_gracefully(signum, frame):
    print("SIGINT received\n")
    server.shutdown()   # doesn't work properly, yet
    sys.exit(0)


if __name__ == '__main__':
    signal.signal(signal.SIGINT, exit_gracefully)

    parser = OptionParser()
    parser.add_option('--libpydir', type='string', dest='libpydir',
                      help='include this directory to sys.path for locating library code')
    parser.add_option('--genpydir', type='string', dest='genpydir',
                      default='gen-py',
                      help='include this directory to sys.path for locating generated code')
    parser.add_option("--port", type="int", dest="port",
                      help="port number for server to listen on")
    parser.add_option("--zlib", action="store_true", dest="zlib",
                      help="use zlib wrapper for compressed transport")
    parser.add_option("--ssl", action="store_true", dest="ssl",
                      help="use SSL for encrypted transport")
    parser.add_option('-v', '--verbose', action="store_const",
                      dest="verbose", const=2,
                      help="verbose output")
    parser.add_option('-q', '--quiet', action="store_const",
                      dest="verbose", const=0,
                      help="minimal output")
    parser.add_option('--protocol', dest="proto", type="string",
                      help="protocol to use, one of: accel, accelc, binary, compact, json, multi, multia, multiac, multic, multih, multij")
    parser.add_option('--transport', dest="trans", type="string",
                      help="transport to use, one of: buffered, framed, http")
    parser.add_option('--domain-socket', dest="domain_socket", type="string",
                      help="Unix domain socket path")
    parser.add_option('--container-limit', dest='container_limit', type='int', default=None)
    parser.add_option('--string-limit', dest='string_limit', type='int', default=None)
    parser.set_defaults(port=9090, verbose=1, proto='binary', transport='buffered')
    options, args = parser.parse_args()

    # Print TServer log to stdout so that the test-runner can redirect it to log files
    logging.basicConfig(level=options.verbose)

    sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))

    from ThriftTest import ThriftTest, SecondService
    from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
    from thrift.Thrift import TException
    from thrift.TMultiplexedProcessor import TMultiplexedProcessor
    from thrift.transport import THeaderTransport
    from thrift.transport import TTransport
    from thrift.transport import TSocket
    from thrift.transport import TZlibTransport
    from thrift.protocol import TBinaryProtocol
    from thrift.protocol import TCompactProtocol
    from thrift.protocol import THeaderProtocol
    from thrift.protocol import TJSONProtocol
    from thrift.server import TServer, TNonblockingServer, THttpServer

    sys.exit(main(options))
thrift-0.16.0/test/py/TestSocket.py000077500000000000000000000045721420101504100171460ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

from thrift.transport import TSocket
import unittest
import time
import socket
import random


class TimeoutTest(unittest.TestCase):
    def setUp(self):
        for i in range(50):
            try:
                # find a port we can use
                self.listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.port = random.randint(10000, 30000)
                self.listen_sock.bind(('localhost', self.port))
                self.listen_sock.listen(5)
                break
            except Exception:
                if i == 49:
                    raise

    def testConnectTimeout(self):
        starttime = time.time()

        try:
            leaky = []
            for i in range(100):
                socket = TSocket.TSocket('localhost', self.port)
                socket.setTimeout(10)
                socket.open()
                leaky.append(socket)
        except Exception:
            self.assert_(time.time() - starttime < 5.0)

    def testWriteTimeout(self):
        starttime = time.time()

        try:
            socket = TSocket.TSocket('localhost', self.port)
            socket.setTimeout(10)
            socket.open()
            lsock = self.listen_sock.accept()
            while True:
                lsock.write("hi" * 100)

        except Exception:
            self.assert_(time.time() - starttime < 5.0)


if __name__ == '__main__':
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()

    suite.addTest(loader.loadTestsFromTestCase(TimeoutTest))

    testRunner = unittest.TextTestRunner(verbosity=2)
    testRunner.run(suite)
thrift-0.16.0/test/py/TestSyntax.py000077500000000000000000000017241420101504100172000ustar00rootroot00000000000000#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

# Just import these generated files to make sure they are syntactically valid
from DebugProtoTest import EmptyService  # noqa
from DebugProtoTest import Inherited  # noqa
thrift-0.16.0/test/py/explicit_module/000077500000000000000000000000001420101504100176575ustar00rootroot00000000000000thrift-0.16.0/test/py/explicit_module/runtest.sh000077500000000000000000000027401420101504100217250ustar00rootroot00000000000000#!/bin/bash

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

rm -rf gen-py
../../../compiler/cpp/thrift --gen py test1.thrift || exit 1
../../../compiler/cpp/thrift --gen py test2.thrift || exit 1
../../../compiler/cpp/thrift --gen py test3.thrift && exit 1  # Fail since test3.thrift has python keywords
PYTHONPATH=./gen-py python -c 'import foo.bar.baz' || exit 1
PYTHONPATH=./gen-py python -c 'import test2' || exit 1
PYTHONPATH=./gen-py python -c 'import test1' &>/dev/null && exit 1  # Should fail.
cp -r gen-py simple
../../../compiler/cpp/thrift -r --gen py test2.thrift || exit 1
PYTHONPATH=./gen-py python -c 'import test2' || exit 1
diff -ur simple gen-py > thediffs
file thediffs | grep -s -q empty || exit 1
rm -rf simple thediffs
echo 'All tests pass!'
thrift-0.16.0/test/py/explicit_module/test1.thrift000066400000000000000000000015531420101504100221450ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

namespace py foo.bar.baz

struct astruct {
  1: i32 how_unoriginal;
}
thrift-0.16.0/test/py/explicit_module/test2.thrift000066400000000000000000000015561420101504100221510ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

include "test1.thrift"

struct another {
  1: test1.astruct something;
}
thrift-0.16.0/test/py/explicit_module/test3.thrift000066400000000000000000000015361420101504100221500ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

namespace py validations

struct from {
  1: i32 def;
}

thrift-0.16.0/test/py/generate.cmake000066400000000000000000000045301420101504100172670ustar00rootroot00000000000000macro(GENERATE FILENAME GENERATOR OUTPUTDIR)
  file(MAKE_DIRECTORY ${MY_CURRENT_BINARY_DIR}/${OUTPUTDIR})
  execute_process(COMMAND ${THRIFTCOMPILER} --gen ${GENERATOR} -out ${MY_CURRENT_BINARY_DIR}/${OUTPUTDIR} ${FILENAME}
                  RESULT_VARIABLE CMD_RESULT)
  if(CMD_RESULT)
        message(FATAL_ERROR "Error generating ${FILENAME} with generator ${GENERATOR}")
  endif()
endmacro(GENERATE)

generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py gen-py-default)
generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:slots gen-py-slots)
generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:old_style gen-py-oldstyle)
generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:no_utf8strings gen-py-no_utf8strings)
generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic gen-py-dynamic)
generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic,slots gen-py-dynamicslots)

generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py gen-py-default)
generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:slots gen-py-slots)
generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:old_style gen-py-oldstyle)
generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:no_utf8strings gen-py-no_utf8strings)
generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic gen-py-dynamic)
generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic,slots gen-py-dynamicslots)

generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py gen-py-default)
generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:slots gen-py-slots)
generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:old_style gen-py-oldstyle)
generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:no_utf8strings gen-py-no_utf8strings)
generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:dynamic gen-py-dynamic)
generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:dynamic,slots gen-py-dynamicslots)

generate(${MY_PROJECT_DIR}/test/Recursive.thrift py gen-py-default)
generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:slots gen-py-slots)
generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:old_style gen-py-oldstyle)
generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:no_utf8strings gen-py-no_utf8strings)
generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:dynamic gen-py-dynamic)
generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:dynamic,slots gen-py-dynamicslots)
thrift-0.16.0/test/py/setup.cfg000066400000000000000000000000371420101504100163120ustar00rootroot00000000000000[flake8]
max-line-length = 100
thrift-0.16.0/test/py/util.py000066400000000000000000000022311420101504100160160ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

import glob
import os
import sys

_SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
_ROOT_DIR = os.path.dirname(os.path.dirname(_SCRIPT_DIR))


def local_libpath():
    globdir = os.path.join(_ROOT_DIR, 'lib', 'py', 'build', 'lib.*')
    for libpath in glob.glob(globdir):
        if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])):
            return libpath
thrift-0.16.0/test/rb/000077500000000000000000000000001420101504100144445ustar00rootroot00000000000000thrift-0.16.0/test/rb/Gemfile000066400000000000000000000002321420101504100157340ustar00rootroot00000000000000source "http://rubygems.org"

require "rubygems"

gem 'rack', '~> 2.0', '>= 2.0.4'
gem 'thin', '~> 1.7', '>= 1.7.2'
gem 'test-unit', '~> 3.2', '>= 3.2.7'
thrift-0.16.0/test/rb/Makefile.am000066400000000000000000000022021420101504100164740ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

stubs: $(THRIFT) ../ThriftTest.thrift ../SmallTest.thrift
	$(THRIFT) --gen rb ../ThriftTest.thrift
	$(THRIFT) --gen rb ../SmallTest.thrift
	$(THRIFT) --gen rb ../Recursive.thrift

precross: stubs

check: stubs
if HAVE_BUNDLER
	$(BUNDLER) install
	$(BUNDLER) exec $(RUBY) -I. test_suite.rb
endif

clean-local:
	$(RM) -r gen-rb/

dist-hook:
	$(RM) -r $(distdir)/gen-rb/
thrift-0.16.0/test/rb/benchmarks/000077500000000000000000000000001420101504100165615ustar00rootroot00000000000000thrift-0.16.0/test/rb/benchmarks/protocol_benchmark.rb000066400000000000000000000107511420101504100227650ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb lib])
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb ext])

require 'thrift'

require 'benchmark'
require 'rubygems'
require 'set'
require 'pp'

# require 'ruby-debug'
# require 'ruby-prof'

require File.join(File.dirname(__FILE__), '../fixtures/structs')

transport1 = Thrift::MemoryBuffer.new
ruby_binary_protocol = Thrift::BinaryProtocol.new(transport1)

transport2 = Thrift::MemoryBuffer.new
c_fast_binary_protocol = Thrift::BinaryProtocolAccelerated.new(transport2)


ooe = Fixtures::Structs::OneOfEach.new
ooe.im_true   = true
ooe.im_false  = false
ooe.a_bite    = -42
ooe.integer16 = 27000
ooe.integer32 = 1<<24
ooe.integer64 = 6000 * 1000 * 1000
ooe.double_precision = Math::PI
ooe.some_characters  = "Debug THIS!"
ooe.zomg_unicode     = "\xd7\n\a\t"

n1 = Fixtures::Structs::Nested1.new
n1.a_list = []
n1.a_list << ooe << ooe << ooe << ooe
n1.i32_map = {}
n1.i32_map[1234] = ooe
n1.i32_map[46345] = ooe
n1.i32_map[-34264] = ooe
n1.i64_map = {}
n1.i64_map[43534986783945] = ooe
n1.i64_map[-32434639875122] = ooe
n1.dbl_map = {}
n1.dbl_map[324.65469834] = ooe
n1.dbl_map[-9458672340.4986798345112] = ooe
n1.str_map = {}
n1.str_map['sdoperuix'] = ooe
n1.str_map['pwoerxclmn'] = ooe

n2 = Fixtures::Structs::Nested2.new
n2.a_list = []
n2.a_list << n1 << n1 << n1 << n1 << n1
n2.i32_map = {}
n2.i32_map[398345] = n1
n2.i32_map[-2345] = n1
n2.i32_map[12312] = n1
n2.i64_map = {}
n2.i64_map[2349843765934] = n1
n2.i64_map[-123234985495] = n1
n2.i64_map[0] = n1
n2.dbl_map = {}
n2.dbl_map[23345345.38927834] = n1
n2.dbl_map[-1232349.5489345] = n1
n2.dbl_map[-234984574.23498725] = n1
n2.str_map = {}
n2.str_map[''] = n1
n2.str_map['sdflkertpioux'] = n1
n2.str_map['sdfwepwdcjpoi'] = n1

n3 = Fixtures::Structs::Nested3.new
n3.a_list = []
n3.a_list << n2 << n2 << n2 << n2 << n2
n3.i32_map = {}
n3.i32_map[398345] = n2
n3.i32_map[-2345] = n2
n3.i32_map[12312] = n2
n3.i64_map = {}
n3.i64_map[2349843765934] = n2
n3.i64_map[-123234985495] = n2
n3.i64_map[0] = n2
n3.dbl_map = {}
n3.dbl_map[23345345.38927834] = n2
n3.dbl_map[-1232349.5489345] = n2
n3.dbl_map[-234984574.23498725] = n2
n3.str_map = {}
n3.str_map[''] = n2
n3.str_map['sdflkertpioux'] = n2
n3.str_map['sdfwepwdcjpoi'] = n2

n4 = Fixtures::Structs::Nested4.new
n4.a_list = []
n4.a_list << n3
n4.i32_map = {}
n4.i32_map[-2345] = n3
n4.i64_map = {}
n4.i64_map[2349843765934] = n3
n4.dbl_map = {}
n4.dbl_map[-1232349.5489345] = n3
n4.str_map = {}
n4.str_map[''] = n3


# prof = RubyProf.profile do
#   n4.write(c_fast_binary_protocol)
#   Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol)
# end
# 
# printer = RubyProf::GraphHtmlPrinter.new(prof)
# printer.print(STDOUT, :min_percent=>0)

Benchmark.bmbm do |x|
  x.report("ruby write large (1MB) structure once") do
    n4.write(ruby_binary_protocol)
  end
  
  x.report("ruby read large (1MB) structure once") do
    Fixtures::Structs::Nested4.new.read(ruby_binary_protocol)
  end
  
  x.report("c write large (1MB) structure once") do    
    n4.write(c_fast_binary_protocol)
  end
  
  x.report("c read large (1MB) structure once") do
    Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol)
  end
  
  
  
  x.report("ruby write 10_000 small structures") do
    10_000.times do
      ooe.write(ruby_binary_protocol)
    end
  end
  
  x.report("ruby read 10_000 small structures") do
    10_000.times do
      Fixtures::Structs::OneOfEach.new.read(ruby_binary_protocol)
    end
  end
  
  x.report("c write 10_000 small structures") do
    10_000.times do
      ooe.write(c_fast_binary_protocol)
    end
  end
  
  x.report("c read 10_000 small structures") do
    10_000.times do
      Fixtures::Structs::OneOfEach.new.read(c_fast_binary_protocol)
    end
  end
  
end
thrift-0.16.0/test/rb/core/000077500000000000000000000000001420101504100153745ustar00rootroot00000000000000thrift-0.16.0/test/rb/core/test_backwards_compatability.rb000066400000000000000000000020241420101504100236400ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

require File.join(File.dirname(__FILE__), '../test_helper')

require 'thrift'

class TestThriftException < Test::Unit::TestCase
  def test_has_accessible_message
    msg = "hi there thrift"
    assert_equal msg, Thrift::Exception.new(msg).message
  end
end

thrift-0.16.0/test/rb/core/test_exceptions.rb000066400000000000000000000020161420101504100211400ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

require File.join(File.dirname(__FILE__), '../test_helper')

require 'thrift'

class TestException < Test::Unit::TestCase
  def test_has_accessible_message
    msg = "hi there thrift"
    assert_equal msg, Thrift::Exception.new(msg).message
  end
end

thrift-0.16.0/test/rb/core/transport/000077500000000000000000000000001420101504100174305ustar00rootroot00000000000000thrift-0.16.0/test/rb/core/transport/test_transport.rb000066400000000000000000000035011420101504100230470ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

require File.join(File.dirname(__FILE__), '../../test_helper')

require 'thrift'

class DummyTransport < Thrift::BaseTransport
  def initialize(data)
    @data = data
  end
  
  def read(size)
    @data.slice!(0, size)
  end
end

# TTransport is basically an abstract class, but isn't raising NotImplementedError
class TestThriftTransport < Test::Unit::TestCase
  def setup
    @trans = Thrift::BaseTransport.new
  end
  
  def test_open?
    assert_nil @trans.open?
  end
  
  def test_open
    assert_nil @trans.open
  end
  
  def test_close
    assert_nil @trans.close
  end
  
  # TODO:
  # This doesn't necessarily test he right thing.
  # It _looks_ like read isn't guaranteed to return the length
  # you ask for and read_all is. This means our test needs to check
  # for blocking. -- Kevin Clark 3/27/08
  def test_read_all
    # Implements read
    t = DummyTransport.new("hello")
    assert_equal "hello", t.read_all(5)
  end
  
  def test_write
    assert_nil @trans.write(5) # arbitrary value
  end
  
  def test_flush
    assert_nil @trans.flush
  end
end
thrift-0.16.0/test/rb/fixtures/000077500000000000000000000000001420101504100163155ustar00rootroot00000000000000thrift-0.16.0/test/rb/fixtures/structs.rb000066400000000000000000000244131420101504100203550ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

require 'thrift'

module Fixtures
  module Structs
    class OneBool
      include Thrift::Struct
      attr_accessor :bool
      FIELDS = {
        1 => {:type => Thrift::Types::BOOL, :name => 'bool'}
      }

      def validate
      end
    end
    
    class OneByte
      include Thrift::Struct
      attr_accessor :byte
      FIELDS = {
        1 => {:type => Thrift::Types::BYTE, :name => 'byte'}
      }

      def validate
      end
    end
    
    class OneI16
      include Thrift::Struct
      attr_accessor :i16
      FIELDS = {
        1 => {:type => Thrift::Types::I16, :name => 'i16'}
      }

      def validate
      end
    end
    
    class OneI32
      include Thrift::Struct
      attr_accessor :i32
      FIELDS = {
        1 => {:type => Thrift::Types::I32, :name => 'i32'}
      }

      def validate
      end
    end
    
    class OneI64
      include Thrift::Struct
      attr_accessor :i64
      FIELDS = {
        1 => {:type => Thrift::Types::I64, :name => 'i64'}
      }

      def validate
      end
    end
    
    class OneDouble
      include Thrift::Struct
      attr_accessor :double
      FIELDS = {
        1 => {:type => Thrift::Types::DOUBLE, :name => 'double'}
      }

      def validate
      end
    end
    
    class OneString
      include Thrift::Struct
      attr_accessor :string
      FIELDS = {
        1 => {:type => Thrift::Types::STRING, :name => 'string'}
      }

      def validate
      end
    end
    
    class OneMap
      include Thrift::Struct
      attr_accessor :map
      FIELDS = {
        1 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRING}}
      }

      def validate
      end
    end
    
    class NestedMap
      include Thrift::Struct
      attr_accessor :map
      FIELDS = {
        0 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::I32}}}
      }

      def validate
      end
    end
    
    class OneList
      include Thrift::Struct
      attr_accessor :list
      FIELDS = {
        1 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::STRING}}
      }

      def validate
      end
    end
    
    class NestedList
      include Thrift::Struct
      attr_accessor :list
      FIELDS = {
        0 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::LIST, :element => { :type => Thrift::Types::I32 } } }
      }

      def validate
      end
    end
    
    class OneSet
      include Thrift::Struct
      attr_accessor :set
      FIELDS = {
        1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::STRING}}
      }

      def validate
      end
    end
    
    class NestedSet
      include Thrift::Struct
      attr_accessor :set
      FIELDS = {
        1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::SET, :element => { :type => Thrift::Types::STRING } }}
      }

      def validate
      end
    end
    
    # struct OneOfEach {
    #   1: bool im_true,
    #   2: bool im_false,
    #   3: byte a_bite,
    #   4: i16 integer16,
    #   5: i32 integer32,
    #   6: i64 integer64,
    #   7: double double_precision,
    #   8: string some_characters,
    #   9: string zomg_unicode,
    #   10: bool what_who,
    #   11: binary base64,
    # }
    class OneOfEach
      include Thrift::Struct
      attr_accessor :im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64
      FIELDS = {
        1 => {:type => Thrift::Types::BOOL, :name => 'im_true'},
        2 => {:type => Thrift::Types::BOOL, :name => 'im_false'},
        3 => {:type => Thrift::Types::BYTE, :name => 'a_bite'},
        4 => {:type => Thrift::Types::I16, :name => 'integer16'},
        5 => {:type => Thrift::Types::I32, :name => 'integer32'},
        6 => {:type => Thrift::Types::I64, :name => 'integer64'},
        7 => {:type => Thrift::Types::DOUBLE, :name => 'double_precision'},
        8 => {:type => Thrift::Types::STRING, :name => 'some_characters'},
        9 => {:type => Thrift::Types::STRING, :name => 'zomg_unicode'},
        10 => {:type => Thrift::Types::BOOL, :name => 'what_who'},
        11 => {:type => Thrift::Types::STRING, :name => 'base64'}
      }

      # Added for assert_equal
      def ==(other)
        [:im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64].each do |f|
          var = "@#{f}"
          return false if instance_variable_get(var) != other.instance_variable_get(var)
        end
        true
      end

      def validate
      end
    end

    # struct Nested1 {
    #   1: list a_list
    #   2: map i32_map
    #   3: map i64_map
    #   4: map dbl_map
    #   5: map str_map
    # }
    class Nested1
      include Thrift::Struct
      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
      FIELDS = {
        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}}
      }

      def validate
      end
    end

    # struct Nested2 {
    #   1: list a_list
    #   2: map i32_map
    #   3: map i64_map
    #   4: map dbl_map
    #   5: map str_map
    # }
    class Nested2
      include Thrift::Struct
      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
      FIELDS = {
        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested1}},
        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}}
      }

      def validate
      end
    end

    # struct Nested3 {
    #   1: list a_list
    #   2: map i32_map
    #   3: map i64_map
    #   4: map dbl_map
    #   5: map str_map
    # }
    class Nested3
      include Thrift::Struct
      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
      FIELDS = {
        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested2}},
        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}}
      }

      def validate
      end
    end

    # struct Nested4 {
    #   1: list a_list
    #   2: map i32_map
    #   3: map i64_map
    #   4: map dbl_map
    #   5: map str_map
    # }
    class Nested4
      include Thrift::Struct
      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
      FIELDS = {
        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested3}},
        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}}
      }

      def validate
      end
    end
  end
end
thrift-0.16.0/test/rb/generation/000077500000000000000000000000001420101504100165775ustar00rootroot00000000000000thrift-0.16.0/test/rb/generation/test_enum.rb000066400000000000000000000023751420101504100211360ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

require File.join(File.dirname(__FILE__), '../test_helper')
require 'thrift_test'

class TestEnumGeneration < Test::Unit::TestCase
  include Thrift::Test
  def test_enum_valid_values
    assert_equal(Numberz::VALID_VALUES, Set.new([Numberz::ONE, Numberz::TWO, Numberz::THREE, Numberz::FIVE, Numberz::SIX, Numberz::EIGHT]))
  end
  
  def test_enum_hash
    Numberz::VALID_VALUES.each do |value|
      assert_equal(Numberz.const_get(Numberz::VALUE_MAP[value].to_sym), value)
    end
  end
endthrift-0.16.0/test/rb/generation/test_recursive.rb000066400000000000000000000026051420101504100221750ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

require File.join(File.dirname(__FILE__), '../test_helper')
require 'recursive_types'

class TestRecursiveGeneration < Test::Unit::TestCase
  CHILD_ITEM = "child item"
  PARENT_ITEM = "parent item"

  def test_can_create_recursive_tree

    child_tree = RecTree.new
    child_tree.item = CHILD_ITEM

    parent_tree = RecTree.new
    parent_tree.item = PARENT_ITEM
    parent_tree.children = [child_tree]

    assert_equal(PARENT_ITEM, parent_tree.item)
    assert_equal(1, parent_tree.children.length)
    assert_equal(CHILD_ITEM, parent_tree.children.first.item)
    assert_nil(parent_tree.children.first.children)
  end
end
thrift-0.16.0/test/rb/generation/test_struct.rb000066400000000000000000000030261420101504100215100ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

require File.join(File.dirname(__FILE__), '../test_helper')
require 'small_service'

class TestStructGeneration < Test::Unit::TestCase

  def test_default_values
    hello = TestNamespace::Hello.new

    assert_kind_of(TestNamespace::Hello, hello)
    assert_nil(hello.complexer)

    assert_equal(hello.simple, 53)
    assert_equal(hello.words, 'words')

    assert_kind_of(TestNamespace::Goodbyez, hello.thinz)
    assert_equal(hello.thinz.val, 36632)

    assert_kind_of(Hash, hello.complex)
    assert_equal(hello.complex, { 6243 => 632, 2355 => 532, 23 => 532})
    
    bool_passer = TestNamespace::BoolPasser.new(:value => false)
    assert_equal false, bool_passer.value
  end

  def test_goodbyez
    assert_equal(TestNamespace::Goodbyez.new.val, 325)
  end

end
thrift-0.16.0/test/rb/integration/000077500000000000000000000000001420101504100167675ustar00rootroot00000000000000thrift-0.16.0/test/rb/integration/TestClient.rb000077500000000000000000000302551420101504100214020ustar00rootroot00000000000000#!/usr/bin/env ruby
# encoding: utf-8

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

$:.push File.dirname(__FILE__) + '/..'

require 'test_helper'
require 'thrift'
require 'thrift_test'

$domain_socket = nil
$host = "localhost"
$port = 9090
$protocolType = "binary"
$ssl = false
$transport = "buffered"

ARGV.each do|a|
  if a == "--help"
    puts "Allowed options:"
    puts "\t -h [ --help ] \t produce help message"
    puts "\t--domain-socket arg (=) \t Unix domain socket path"
    puts "\t--host arg (=localhost) \t Host to connect \t not valid with domain-socket"
    puts "\t--port arg (=9090) \t Port number to listen \t not valid with domain-socket"
    puts "\t--protocol arg (=binary) \t protocol: accel, binary, compact, json"
    puts "\t--ssl \t use ssl \t not valid with domain-socket"
    puts "\t--transport arg (=buffered) transport: buffered, framed, http"
    exit
  elsif a.start_with?("--domain-socket")
    $domain_socket = a.split("=")[1]
  elsif a.start_with?("--host")
    $host = a.split("=")[1]
  elsif a.start_with?("--protocol")
    $protocolType = a.split("=")[1]
  elsif a == "--ssl"
    $ssl = true
  elsif a.start_with?("--transport")
    $transport = a.split("=")[1]
  elsif a.start_with?("--port")
    $port = a.split("=")[1].to_i
  end
end

class SimpleClientTest < Test::Unit::TestCase
  def setup
    unless @socket
      if $domain_socket.to_s.strip.empty?
        if $ssl
          # the working directory for ruby crosstest is test/rb/gen-rb
          keysDir = File.join(File.dirname(File.dirname(Dir.pwd)), "keys")
          ctx = OpenSSL::SSL::SSLContext.new
          ctx.ca_file = File.join(keysDir, "CA.pem")
          ctx.cert = OpenSSL::X509::Certificate.new(File.open(File.join(keysDir, "client.crt")))
          ctx.cert_store = OpenSSL::X509::Store.new
          ctx.cert_store.add_file(File.join(keysDir, 'server.pem'))
          ctx.key = OpenSSL::PKey::RSA.new(File.open(File.join(keysDir, "client.key")))
          ctx.options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
          ctx.ssl_version = :SSLv23
          ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
          @socket = Thrift::SSLSocket.new($host, $port, nil, ctx)
        else
          @socket = Thrift::Socket.new($host, $port)
        end
      else
        @socket = Thrift::UNIXSocket.new($domain_socket)
      end
      
      if $transport == "buffered"
        transportFactory = Thrift::BufferedTransport.new(@socket)
      elsif $transport == "framed"
        transportFactory = Thrift::FramedTransport.new(@socket)
      else
        raise 'Unknown transport type'
      end

      if $protocolType == "binary"
        @protocol = Thrift::BinaryProtocol.new(transportFactory)
      elsif $protocolType == "compact"
        @protocol = Thrift::CompactProtocol.new(transportFactory)
      elsif $protocolType == "json"
        @protocol = Thrift::JsonProtocol.new(transportFactory)
      elsif $protocolType == "accel"
        @protocol = Thrift::BinaryProtocolAccelerated.new(transportFactory)
      else
        raise 'Unknown protocol type'
      end
      @client = Thrift::Test::ThriftTest::Client.new(@protocol)
      @socket.open
    end
  end

  def teardown
    @socket.close
  end

  def test_void
    p 'test_void'
    @client.testVoid()
  end

  def test_string
    p 'test_string'
    test_string =
      'quote: \" backslash:' +
      ' forwardslash-escaped: \/ ' +
      ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
      ' now-all-of-them-together: "\\\/\b\n\r\t' +
      ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' +
      ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ '
    test_string = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
      "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
      "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " +
      "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " +
      "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " +
      "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " +
      "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " +
      "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " +
      "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " +
      "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " +
      "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " +
      "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " +
      "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " +
      "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " +
      "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " +
      "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" +
      "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " +
      "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " +
      "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " +
      "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " +
      "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " +
      "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " +
      "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " +
      "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " +
      "Bân-lâm-gú, 粵語"

    result_string = @client.testString(test_string)
    assert_equal(test_string, result_string.force_encoding(Encoding::UTF_8))
  end

  def test_bool
    p 'test_bool'
    assert_equal(@client.testBool(true), true)
    assert_equal(@client.testBool(false), false)
  end

  def test_byte
    p 'test_byte'
    val = 120
    assert_equal(@client.testByte(val), val)
    assert_equal(@client.testByte(-val), -val)
  end

  def test_i32
    p 'test_i32'
    val = 2000000032
    assert_equal(@client.testI32(val), val)
    assert_equal(@client.testI32(-val), -val)
  end

  def test_i64
    p 'test_i64'
    val = 9000000000000000064
    assert_equal(@client.testI64(val), val)
    assert_equal(@client.testI64(-val), -val)
  end

  def test_double
    p 'test_double'
    val = 3.14159265358979323846
    assert_equal(@client.testDouble(val), val)
    assert_equal(@client.testDouble(-val), -val)
    assert_kind_of(Float, @client.testDouble(val))
  end

  def test_binary
    p 'test_binary'
    val = (0...256).reverse_each.to_a
    ret = @client.testBinary(val.pack('C*'))
    assert_equal(val, ret.bytes.to_a)
  end

  def test_map
    p 'test_map'
    val = {1 => 1, 2 => 2, 3 => 3}
    assert_equal(@client.testMap(val), val)
    assert_kind_of(Hash, @client.testMap(val))
  end

  def test_string_map
    p 'test_string_map'
    val = {'a' => '2', 'b' => 'blah', 'some' => 'thing'}
    ret = @client.testStringMap(val)
    assert_equal(val, ret)
    assert_kind_of(Hash, ret)
  end

  def test_list
    p 'test_list'
    val = [1,2,3,4,5]
    assert_equal(@client.testList(val), val)
    assert_kind_of(Array, @client.testList(val))
  end

  def test_enum
    p 'test_enum'
    val = Thrift::Test::Numberz::SIX
    ret = @client.testEnum(val)

    assert_equal(ret, 6)
    assert_kind_of(Fixnum, ret)
  end

  def test_typedef
    p 'test_typedef'
    #UserId  testTypedef(1: UserId thing),
    assert_equal(@client.testTypedef(309858235082523), 309858235082523)
    assert_kind_of(Fixnum, @client.testTypedef(309858235082523))
    true
  end

  def test_set
    p 'test_set'
    val = Set.new([1,2,3])
    assert_equal(@client.testSet(val), val)
    assert_kind_of(Set, @client.testSet(val))
  end

  def get_struct
    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
  end

  def test_struct
    p 'test_struct'
    ret = @client.testStruct(get_struct)

    # TODO: not sure what unspecified "default" requiredness values should be
    assert(ret.byte_thing == nil || ret.byte_thing == 0)
    assert(ret.i64_thing == nil || ret.i64_thing == 0)

    assert_equal(ret.string_thing, 'hi!')
    assert_equal(ret.i32_thing, 4)
    assert_kind_of(Thrift::Test::Xtruct, ret)
  end

  def test_nest
    p 'test_nest'
    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})

    ret = @client.testNest(struct2)

    # TODO: not sure what unspecified "default" requiredness values should be
    assert(ret.struct_thing.byte_thing == nil || ret.struct_thing.byte_thing == 0)
    assert(ret.struct_thing.i64_thing == nil || ret.struct_thing.i64_thing == 0)

    assert_equal(ret.struct_thing.string_thing, 'hi!')
    assert_equal(ret.struct_thing.i32_thing, 4)
    assert_equal(ret.i32_thing, 10)

    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
    assert_kind_of(Thrift::Test::Xtruct2, ret)
  end

  def test_insanity
    p 'test_insanity'
    insane = Thrift::Test::Insanity.new({
      'userMap' => {
        Thrift::Test::Numberz::FIVE => 5,
        Thrift::Test::Numberz::EIGHT => 8,
      },
      'xtructs' => [
        Thrift::Test::Xtruct.new({
          'string_thing' => 'Goodbye4',
          'byte_thing' => 4,
          'i32_thing' => 4,
          'i64_thing' => 4,
        }),
        Thrift::Test::Xtruct.new({
          'string_thing' => 'Hello2',
          'byte_thing' => 2,
          'i32_thing' => 2,
          'i64_thing' => 2,
        })
      ]
    })

    ret = @client.testInsanity(insane)

    assert_equal(insane, ret[1][2])
    assert_equal(insane, ret[1][3])

    assert(ret[2][6].userMap == nil || ret[2][6].userMap.length == 0)
    assert(ret[2][6].xtructs == nil || ret[2][6].xtructs.length == 0)
  end

  def test_map_map
    p 'test_map_map'
    ret = @client.testMapMap(4)
    assert_kind_of(Hash, ret)
    expected = {
      -4 => {
        -4 => -4,
        -3 => -3,
        -2 => -2,
        -1 => -1,
      },
      4 => {
        4 => 4,
        3 => 3,
        2 => 2,
        1 => 1,
      }
    }
    assert_equal(expected, ret)
  end

  def test_multi
    p 'test_multi'
    ret = @client.testMulti(42, 4242, 424242, {1 => 'blah', 2 => 'thing'}, Thrift::Test::Numberz::EIGHT, 24)
    expected = Thrift::Test::Xtruct.new({
      :string_thing => 'Hello2',
      :byte_thing =>   42,
      :i32_thing =>    4242,
      :i64_thing =>    424242
    })
    assert_equal(expected, ret)
  end

  def test_exception
    p 'test_exception'
    assert_raise Thrift::Test::Xception do
      @client.testException('Xception')
    end
    begin
      @client.testException('TException')
    rescue => e
      assert e.class.ancestors.include?(Thrift::Exception)
    end
    assert_nothing_raised do
      @client.testException('test')
    end
  end

  def test_multi_exception
    p 'test_multi_exception'
    assert_raise Thrift::Test::Xception do
      @client.testMultiException("Xception", "test 1")
    end
    assert_raise Thrift::Test::Xception2 do
      @client.testMultiException("Xception2", "test 2")
    end
    assert_equal( @client.testMultiException("Success", "test 3").string_thing, "test 3")
  end

  def test_oneway
    p 'test_oneway'
    time1 = Time.now.to_f
    @client.testOneway(1)
    time2 = Time.now.to_f
    assert_operator (time2-time1), :<, 0.1
  end

end

thrift-0.16.0/test/rb/integration/TestServer.rb000077500000000000000000000125021420101504100214250ustar00rootroot00000000000000#!/usr/bin/env ruby

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

$:.push File.dirname(__FILE__) + '/..'

require 'test_helper'
require 'thrift'
require 'thrift_test'
require 'thrift_test_types'

class SimpleHandler
  [:testVoid, :testString, :testBool, :testByte, :testI32, :testI64, :testDouble, :testBinary,
   :testStruct, :testMap, :testStringMap, :testSet, :testList, :testNest, :testEnum, :testTypedef,
   :testEnum, :testTypedef, :testMultiException].each do |meth|

    define_method(meth) do |thing|
      p meth
      p thing
      thing
    end

  end

  def testVoid()
  end

  def testInsanity(thing)
    return {
      1 => {
        2 => thing,
        3 => thing
      },
      2 => {
        6 => Thrift::Test::Insanity::new()
      }
    }
  end

  def testMapMap(thing)
    return {
      -4 => {
        -4 => -4,
        -3 => -3,
        -2 => -2,
        -1 => -1,
      },
      4 => {
        4 => 4,
        3 => 3,
        2 => 2,
        1 => 1,
      }
    }
  end

  def testMulti(arg0, arg1, arg2, arg3, arg4, arg5)
    return Thrift::Test::Xtruct.new({
      'string_thing' => 'Hello2',
      'byte_thing' => arg0,
      'i32_thing' => arg1,
      'i64_thing' => arg2,
    })
  end

  def testException(thing)
    if thing == "Xception"
      raise Thrift::Test::Xception, :errorCode => 1001, :message => thing
    elsif thing == "TException"
      raise Thrift::Exception, :message => thing
    else
      # no-op
    end
  end

  def testMultiException(arg0, arg1)
    if arg0 == "Xception2"
      raise Thrift::Test::Xception2, :errorCode => 2002, :struct_thing => ::Thrift::Test::Xtruct.new({ :string_thing => 'This is an Xception2' })
    elsif arg0 == "Xception"
      raise Thrift::Test::Xception, :errorCode => 1001, :message => 'This is an Xception'
    else
      return ::Thrift::Test::Xtruct.new({'string_thing' => arg1})
    end
  end

  def testOneway(arg0)
    sleep(arg0)
  end

end

domain_socket = nil
port = 9090
protocol = "binary"
@protocolFactory = nil
ssl = false
transport = "buffered"
@transportFactory = nil

ARGV.each do|a|
  if a == "--help"
    puts "Allowed options:"
    puts "\t -h [ --help ] \t produce help message"
    puts "\t--domain-socket arg (=) \t Unix domain socket path"
    puts "\t--port arg (=9090) \t Port number to listen \t not valid with domain-socket"
    puts "\t--protocol arg (=binary) \t protocol: accel, binary, compact, json"
    puts "\t--ssl \t use ssl \t not valid with domain-socket"
    puts "\t--transport arg (=buffered) transport: buffered, framed, http"
    exit
  elsif a.start_with?("--domain-socket")
    domain_socket = a.split("=")[1]
  elsif a.start_with?("--protocol")
    protocol = a.split("=")[1]
  elsif a == "--ssl"
    ssl = true
  elsif a.start_with?("--transport")
    transport = a.split("=")[1]
  elsif a.start_with?("--port")
    port = a.split("=")[1].to_i 
  end
end

if protocol == "binary" || protocol.to_s.strip.empty?
  @protocolFactory = Thrift::BinaryProtocolFactory.new
elsif protocol == "compact"
  @protocolFactory = Thrift::CompactProtocolFactory.new
elsif protocol == "json"
  @protocolFactory = Thrift::JsonProtocolFactory.new
elsif protocol == "accel"
  @protocolFactory = Thrift::BinaryProtocolAcceleratedFactory.new
else
  raise 'Unknown protocol type'
end

if transport == "buffered" || transport.to_s.strip.empty?
  @transportFactory = Thrift::BufferedTransportFactory.new
elsif transport == "framed"
  @transportFactory = Thrift::FramedTransportFactory.new
else
  raise 'Unknown transport type'
end

@handler = SimpleHandler.new
@processor = Thrift::Test::ThriftTest::Processor.new(@handler)
@transport = nil
if domain_socket.to_s.strip.empty?
  if ssl
    # the working directory for ruby crosstest is test/rb/gen-rb
    keysDir = File.join(File.dirname(File.dirname(Dir.pwd)), "keys")
    ctx = OpenSSL::SSL::SSLContext.new
    ctx.ca_file = File.join(keysDir, "CA.pem")
    ctx.cert = OpenSSL::X509::Certificate.new(File.open(File.join(keysDir, "server.crt")))
    ctx.cert_store = OpenSSL::X509::Store.new
    ctx.cert_store.add_file(File.join(keysDir, 'client.pem'))
    ctx.key = OpenSSL::PKey::RSA.new(File.open(File.join(keysDir, "server.key")))
    ctx.options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
    ctx.ssl_version = :SSLv23
    ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
    @transport = Thrift::SSLServerSocket.new(nil, port, ctx)
  else
    @transport = Thrift::ServerSocket.new(port)
  end
else
  @transport = Thrift::UNIXServerSocket.new(domain_socket)
end

@server = Thrift::ThreadedServer.new(@processor, @transport, @transportFactory, @protocolFactory)

puts "Starting TestServer #{@server.to_s}"
@server.serve
puts "done."
thrift-0.16.0/test/rb/test_helper.rb000066400000000000000000000023251420101504100173110ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

$:.unshift File.dirname(__FILE__) + '/gen-rb'
$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/lib')
$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/ext')

require 'test/unit'

module Thrift
  module Struct
    def ==(other)
      return false unless other.is_a? self.class
      self.class.const_get(:FIELDS).collect {|fid, data| data[:name] }.all? do |field|
        send(field) == other.send(field)
      end
    end
  end
end
thrift-0.16.0/test/rb/test_suite.rb000066400000000000000000000015101420101504100171560ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

Dir["{core,generation}/**/*.rb"].each {|f| require f }thrift-0.16.0/test/rebuild_known_failures.sh000066400000000000000000000010621420101504100211300ustar00rootroot00000000000000#!/bin/bash

if [ -z $1 ]; then
  echo Usage: $0 LANGUAGE
  echo Re-list all failures of a specific LANGUAGE into known_failures_Linux.json
  echo LANGUAGE should be library name like cpp, java, py etc
  exit 1
fi

if [ -z $PYTHON]; then
  PYTHON=python
fi

TARGET_LANG=$1
OUT_FILE=known_failures_Linux.json
echo Rebuilding known failures for $TARGET_LANG

TMPFILE=.__tmp__rebuild__
grep -v -e "\"$1-" -e "\-$1_" $OUT_FILE > $TMPFILE
mv $TMPFILE $OUT_FILE
$PYTHON test.py --client $1
$PYTHON test.py -U merge
$PYTHON test.py --server $1
$PYTHON test.py -U merge
thrift-0.16.0/test/result.js000066400000000000000000000047251420101504100157250ustar00rootroot00000000000000/*
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements. See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership. The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License. You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied. See the License for the
 specific language governing permissions and limitations
 under the License.

*/

$.getJSON('results.json', function(results) {
    $(document).ready(function() {
        var transport = 3;
        var socket = 4;
        var success = 5;
        var expected = 6;
        var returnCode = 7;
        var logFile = 8;
        testTable = $('#test_results').DataTable({
            data: results['results'],
            columnDefs: [
                {
                    targets: 3,
                    render: function(data, type, row) {
                        return row[transport] + '-' + row[socket];
                    },
                },
                {
                    targets: 4,
                    render: function(data, type, row) {
                        return (row[success] ? 'success' : 'failure')
                                + '(' + (row[returnCode] == 128 ? 'timeout' : row[returnCode]) + ')'
                                + '(Server, '
                                + 'Client)';
                    },
                },
                {
                    targets: 5,
                    render: function(data, type, row) {
                        // 'yes' rather than 'expected' to ease search
                        return row[expected] ? 'yes' : 'unexpected';
                    },
                }
            ],
        });
        $('#test_results_filter label input').focus().val('unexpected failure');
        $('#test_info').text(
            "Test Date:     " + results['date'] + "\n" +
            "Revision:      " + results['revision'] + "\n" +
            "Platform:      " + results['platform'] + "\n" +
            "Test duration: " + results['duration']) + " seconds";
    });
});

thrift-0.16.0/test/rs/000077500000000000000000000000001420101504100144655ustar00rootroot00000000000000thrift-0.16.0/test/rs/Cargo.toml000066400000000000000000000004461420101504100164210ustar00rootroot00000000000000[package]
name = "thrift-test"
version = "0.1.0"
edition = "2018"
license = "Apache-2.0"
authors = ["Apache Thrift Developers "]
publish = false

[dependencies]
clap = "~2.33"
bitflags = "=1.2"
env_logger = "0.8"
log = "0.4"

[dependencies.thrift]
path = "../../lib/rs"

thrift-0.16.0/test/rs/Makefile.am000066400000000000000000000024001420101504100165150ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

stubs: ../ThriftTest.thrift
	$(THRIFT) -I ./thrifts -out src --gen rs ../ThriftTest.thrift

precross: stubs
	$(CARGO) build
	$(CARGO) fmt --all -- --check
	$(CARGO) clippy --all -- -D warnings
	[ -d bin ] || mkdir bin
	cp target/debug/test_server bin/test_server
	cp target/debug/test_client bin/test_client

clean-local:
	$(CARGO) clean
	-$(RM) Cargo.lock
	-$(RM) src/thrift_test.rs
	-$(RM) -r bin

EXTRA_DIST = \
	Cargo.toml \
	src/lib.rs \
	src/bin/test_server.rs \
	src/bin/test_client.rs

thrift-0.16.0/test/rs/src/000077500000000000000000000000001420101504100152545ustar00rootroot00000000000000thrift-0.16.0/test/rs/src/bin/000077500000000000000000000000001420101504100160245ustar00rootroot00000000000000thrift-0.16.0/test/rs/src/bin/test_client.rs000066400000000000000000000474551420101504100207260ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use clap::{clap_app, value_t};
use env_logger;
use log::*;

use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Debug;
use std::net::TcpStream;

use thrift;
use thrift::protocol::{
    TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, TCompactOutputProtocol,
    TInputProtocol, TMultiplexedOutputProtocol, TOutputProtocol,
};
use thrift::transport::{
    TBufferedReadTransport, TBufferedWriteTransport, TFramedReadTransport, TFramedWriteTransport,
    TIoChannel, TReadTransport, TTcpChannel, TWriteTransport,
};
use thrift::OrderedFloat;
use thrift_test::*;

fn main() {
    env_logger::init();

    debug!("initialized logger - running cross-test client");

    match run() {
        Ok(()) => info!("cross-test client succeeded"),
        Err(e) => {
            info!("cross-test client failed with error {:?}", e);
            std::process::exit(1);
        }
    }
}

fn run() -> thrift::Result<()> {
    // unsupported options:
    // --domain-socket
    // --pipe
    // --anon-pipes
    // --ssl
    // --threads
    let matches = clap_app!(rust_test_client =>
        (version: "1.0")
        (author: "Apache Thrift Developers ")
        (about: "Rust Thrift test client")
        (@arg host: --host +takes_value "Host on which the Thrift test server is located")
        (@arg port: --port +takes_value "Port on which the Thrift test server is listening")
        (@arg transport: --transport +takes_value "Thrift transport implementation to use (\"buffered\", \"framed\")")
        (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\", \"multi\", \"multic\")")
        (@arg testloops: -n --testloops +takes_value "Number of times to run tests")
    )
        .get_matches();

    let host = matches.value_of("host").unwrap_or("127.0.0.1");
    let port = value_t!(matches, "port", u16).unwrap_or(9090);
    let testloops = value_t!(matches, "testloops", u8).unwrap_or(1);
    let transport = matches.value_of("transport").unwrap_or("buffered");
    let protocol = matches.value_of("protocol").unwrap_or("binary");

    // create a TCPStream that will be shared by all Thrift clients
    // service calls from multiple Thrift clients will be interleaved over the same connection
    // this isn't a problem for us because we're single-threaded and all calls block to completion
    let shared_stream = TcpStream::connect(format!("{}:{}", host, port))?;

    let mut second_service_client = if protocol.starts_with("multi") {
        let shared_stream_clone = shared_stream.try_clone()?;
        let (i_prot, o_prot) = build(shared_stream_clone, transport, protocol, "SecondService")?;
        Some(SecondServiceSyncClient::new(i_prot, o_prot))
    } else {
        None
    };

    let mut thrift_test_client = {
        let (i_prot, o_prot) = build(shared_stream, transport, protocol, "ThriftTest")?;
        ThriftTestSyncClient::new(i_prot, o_prot)
    };

    info!(
        "connecting to {}:{} with {}+{} stack",
        host, port, protocol, transport
    );

    for _ in 0..testloops {
        make_thrift_calls(&mut thrift_test_client, &mut second_service_client)?
    }

    Ok(())
}

fn build(
    stream: TcpStream,
    transport: &str,
    protocol: &str,
    service_name: &str,
) -> thrift::Result<(Box, Box)> {
    let c = TTcpChannel::with_stream(stream);
    let (i_chan, o_chan) = c.split()?;

    let (i_tran, o_tran): (Box, Box) = match transport {
        "buffered" => (
            Box::new(TBufferedReadTransport::new(i_chan)),
            Box::new(TBufferedWriteTransport::new(o_chan)),
        ),
        "framed" => (
            Box::new(TFramedReadTransport::new(i_chan)),
            Box::new(TFramedWriteTransport::new(o_chan)),
        ),
        unmatched => return Err(format!("unsupported transport {}", unmatched).into()),
    };

    let (i_prot, o_prot): (Box, Box) = match protocol {
        "binary" => (
            Box::new(TBinaryInputProtocol::new(i_tran, true)),
            Box::new(TBinaryOutputProtocol::new(o_tran, true)),
        ),
        "multi" => (
            Box::new(TBinaryInputProtocol::new(i_tran, true)),
            Box::new(TMultiplexedOutputProtocol::new(
                service_name,
                TBinaryOutputProtocol::new(o_tran, true),
            )),
        ),
        "compact" => (
            Box::new(TCompactInputProtocol::new(i_tran)),
            Box::new(TCompactOutputProtocol::new(o_tran)),
        ),
        "multic" => (
            Box::new(TCompactInputProtocol::new(i_tran)),
            Box::new(TMultiplexedOutputProtocol::new(
                service_name,
                TCompactOutputProtocol::new(o_tran),
            )),
        ),
        unmatched => return Err(format!("unsupported protocol {}", unmatched).into()),
    };

    Ok((i_prot, o_prot))
}

type BuildThriftTestClient =
    ThriftTestSyncClient, Box>;
type BuiltSecondServiceClient =
    SecondServiceSyncClient, Box>;

#[allow(clippy::cognitive_complexity)]
fn make_thrift_calls(
    thrift_test_client: &mut BuildThriftTestClient,
    second_service_client: &mut Option,
) -> Result<(), thrift::Error> {
    info!("testVoid");
    thrift_test_client.test_void()?;

    info!("testString");
    verify_expected_result(
        thrift_test_client.test_string("thing".to_owned()),
        "thing".to_owned(),
    )?;

    info!("testBool");
    verify_expected_result(thrift_test_client.test_bool(true), true)?;

    info!("testBool");
    verify_expected_result(thrift_test_client.test_bool(false), false)?;

    info!("testByte");
    verify_expected_result(thrift_test_client.test_byte(42), 42)?;

    info!("testi32");
    verify_expected_result(thrift_test_client.test_i32(1_159_348_374), 1_159_348_374)?;

    info!("testi64");
    // try!(verify_expected_result(thrift_test_client.test_i64(-8651829879438294565),
    // -8651829879438294565));
    verify_expected_result(
        thrift_test_client.test_i64(i64::min_value()),
        i64::min_value(),
    )?;

    info!("testDouble");
    verify_expected_result(
        thrift_test_client.test_double(OrderedFloat::from(42.42)),
        OrderedFloat::from(42.42),
    )?;

    info!("testTypedef");
    {
        let u_snd: UserId = 2348;
        let u_cmp: UserId = 2348;
        verify_expected_result(thrift_test_client.test_typedef(u_snd), u_cmp)?;
    }

    info!("testEnum");
    {
        verify_expected_result(thrift_test_client.test_enum(Numberz::TWO), Numberz::TWO)?;
    }

    info!("testBinary");
    {
        let b_snd = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
        let b_cmp = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
        verify_expected_result(thrift_test_client.test_binary(b_snd), b_cmp)?;
    }

    info!("testStruct");
    {
        let x_snd = Xtruct {
            string_thing: Some("foo".to_owned()),
            byte_thing: Some(12),
            i32_thing: Some(219_129),
            i64_thing: Some(12_938_492_818),
        };
        let x_cmp = Xtruct {
            string_thing: Some("foo".to_owned()),
            byte_thing: Some(12),
            i32_thing: Some(219_129),
            i64_thing: Some(12_938_492_818),
        };
        verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp)?;
    }

    // Xtruct again, with optional values
    // FIXME: apparently the erlang thrift server does not like opt-in-req-out
    // parameters that are undefined. Joy.
    // {
    // let x_snd = Xtruct { string_thing: Some("foo".to_owned()), byte_thing: None,
    // i32_thing: None, i64_thing: Some(12938492818) };
    // let x_cmp = Xtruct { string_thing: Some("foo".to_owned()), byte_thing:
    // Some(0), i32_thing: Some(0), i64_thing: Some(12938492818) }; // the C++
    // server is responding correctly
    // try!(verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp));
    // }
    //

    info!("testNest"); // (FIXME: try Xtruct2 with optional values)
    {
        let x_snd = Xtruct2 {
            byte_thing: Some(32),
            struct_thing: Some(Xtruct {
                string_thing: Some("foo".to_owned()),
                byte_thing: Some(1),
                i32_thing: Some(324_382_098),
                i64_thing: Some(12_938_492_818),
            }),
            i32_thing: Some(293_481_098),
        };
        let x_cmp = Xtruct2 {
            byte_thing: Some(32),
            struct_thing: Some(Xtruct {
                string_thing: Some("foo".to_owned()),
                byte_thing: Some(1),
                i32_thing: Some(324_382_098),
                i64_thing: Some(12_938_492_818),
            }),
            i32_thing: Some(293_481_098),
        };
        verify_expected_result(thrift_test_client.test_nest(x_snd), x_cmp)?;
    }

    // do the multiplexed calls while making the main ThriftTest calls
    if let Some(ref mut client) = second_service_client.as_mut() {
        info!("SecondService secondtestString");
        {
            verify_expected_result(
                client.secondtest_string("test_string".to_owned()),
                "testString(\"test_string\")".to_owned(),
            )?;
        }
    }

    info!("testList");
    {
        let mut v_snd: Vec = Vec::new();
        v_snd.push(29384);
        v_snd.push(238);
        v_snd.push(32498);

        let mut v_cmp: Vec = Vec::new();
        v_cmp.push(29384);
        v_cmp.push(238);
        v_cmp.push(32498);

        verify_expected_result(thrift_test_client.test_list(v_snd), v_cmp)?;
    }

    info!("testSet");
    {
        let mut s_snd: BTreeSet = BTreeSet::new();
        s_snd.insert(293_481);
        s_snd.insert(23);
        s_snd.insert(3234);

        let mut s_cmp: BTreeSet = BTreeSet::new();
        s_cmp.insert(293_481);
        s_cmp.insert(23);
        s_cmp.insert(3234);

        verify_expected_result(thrift_test_client.test_set(s_snd), s_cmp)?;
    }

    info!("testMap");
    {
        let mut m_snd: BTreeMap = BTreeMap::new();
        m_snd.insert(2, 4);
        m_snd.insert(4, 6);
        m_snd.insert(8, 7);

        let mut m_cmp: BTreeMap = BTreeMap::new();
        m_cmp.insert(2, 4);
        m_cmp.insert(4, 6);
        m_cmp.insert(8, 7);

        verify_expected_result(thrift_test_client.test_map(m_snd), m_cmp)?;
    }

    info!("testStringMap");
    {
        let mut m_snd: BTreeMap = BTreeMap::new();
        m_snd.insert("2".to_owned(), "4_string".to_owned());
        m_snd.insert("4".to_owned(), "6_string".to_owned());
        m_snd.insert("8".to_owned(), "7_string".to_owned());

        let mut m_rcv: BTreeMap = BTreeMap::new();
        m_rcv.insert("2".to_owned(), "4_string".to_owned());
        m_rcv.insert("4".to_owned(), "6_string".to_owned());
        m_rcv.insert("8".to_owned(), "7_string".to_owned());

        verify_expected_result(thrift_test_client.test_string_map(m_snd), m_rcv)?;
    }

    // nested map
    // expect : {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2
    // => 2, 3 => 3, 4 => 4, }, }
    info!("testMapMap");
    {
        let mut m_cmp_nested_0: BTreeMap = BTreeMap::new();
        for i in (-4 as i32)..0 {
            m_cmp_nested_0.insert(i, i);
        }
        let mut m_cmp_nested_1: BTreeMap = BTreeMap::new();
        for i in 1..5 {
            m_cmp_nested_1.insert(i, i);
        }

        let mut m_cmp: BTreeMap> = BTreeMap::new();
        m_cmp.insert(-4, m_cmp_nested_0);
        m_cmp.insert(4, m_cmp_nested_1);

        verify_expected_result(thrift_test_client.test_map_map(42), m_cmp)?;
    }

    info!("testMulti");
    {
        let mut m_snd: BTreeMap = BTreeMap::new();
        m_snd.insert(1298, "fizz".to_owned());
        m_snd.insert(-148, "buzz".to_owned());

        let s_cmp = Xtruct {
            string_thing: Some("Hello2".to_owned()),
            byte_thing: Some(1),
            i32_thing: Some(-123_948),
            i64_thing: Some(-19_234_123_981),
        };

        verify_expected_result(
            thrift_test_client.test_multi(1, -123_948, -19_234_123_981, m_snd, Numberz::EIGHT, 81),
            s_cmp,
        )?;
    }

    // Insanity
    // returns:
    // { 1 => { 2 => argument,
    //          3 => argument,
    //        },
    //   2 => { 6 => , },
    // }
    {
        let mut arg_map_usermap: BTreeMap = BTreeMap::new();
        arg_map_usermap.insert(Numberz::ONE, 4289);
        arg_map_usermap.insert(Numberz::EIGHT, 19);

        let mut arg_vec_xtructs: Vec = Vec::new();
        arg_vec_xtructs.push(Xtruct {
            string_thing: Some("foo".to_owned()),
            byte_thing: Some(8),
            i32_thing: Some(29),
            i64_thing: Some(92384),
        });
        arg_vec_xtructs.push(Xtruct {
            string_thing: Some("bar".to_owned()),
            byte_thing: Some(28),
            i32_thing: Some(2),
            i64_thing: Some(-1281),
        });
        arg_vec_xtructs.push(Xtruct {
            string_thing: Some("baz".to_owned()),
            byte_thing: Some(0),
            i32_thing: Some(3_948_539),
            i64_thing: Some(-12_938_492),
        });

        let mut s_cmp_nested_1: BTreeMap = BTreeMap::new();
        let insanity = Insanity {
            user_map: Some(arg_map_usermap),
            xtructs: Some(arg_vec_xtructs),
        };
        s_cmp_nested_1.insert(Numberz::TWO, insanity.clone());
        s_cmp_nested_1.insert(Numberz::THREE, insanity.clone());

        let mut s_cmp_nested_2: BTreeMap = BTreeMap::new();
        let empty_insanity = Insanity {
            user_map: Some(BTreeMap::new()),
            xtructs: Some(Vec::new()),
        };
        s_cmp_nested_2.insert(Numberz::SIX, empty_insanity);

        let mut s_cmp: BTreeMap> = BTreeMap::new();
        s_cmp.insert(1 as UserId, s_cmp_nested_1);
        s_cmp.insert(2 as UserId, s_cmp_nested_2);

        verify_expected_result(thrift_test_client.test_insanity(insanity), s_cmp)?;
    }

    info!("testException - remote throws Xception");
    {
        let r = thrift_test_client.test_exception("Xception".to_owned());
        let x = match r {
            Err(thrift::Error::User(ref e)) => match e.downcast_ref::() {
                Some(x) => Ok(x),
                None => Err(thrift::Error::User(
                    "did not get expected Xception struct".into(),
                )),
            },
            _ => Err(thrift::Error::User("did not get exception".into())),
        }?;

        let x_cmp = Xception {
            error_code: Some(1001),
            message: Some("Xception".to_owned()),
        };

        verify_expected_result(Ok(x), &x_cmp)?;
    }

    info!("testException - remote throws TApplicationException");
    {
        let r = thrift_test_client.test_exception("TException".to_owned());
        match r {
            Err(thrift::Error::Application(ref e)) => {
                info!("received an {:?}", e);
                Ok(())
            }
            _ => Err(thrift::Error::User("did not get exception".into())),
        }?;
    }

    info!("testException - remote succeeds");
    {
        let r = thrift_test_client.test_exception("foo".to_owned());
        match r {
            Ok(_) => Ok(()),
            _ => Err(thrift::Error::User("received an exception".into())),
        }?;
    }

    info!("testMultiException - remote throws Xception");
    {
        let r =
            thrift_test_client.test_multi_exception("Xception".to_owned(), "ignored".to_owned());
        let x = match r {
            Err(thrift::Error::User(ref e)) => match e.downcast_ref::() {
                Some(x) => Ok(x),
                None => Err(thrift::Error::User(
                    "did not get expected Xception struct".into(),
                )),
            },
            _ => Err(thrift::Error::User("did not get exception".into())),
        }?;

        let x_cmp = Xception {
            error_code: Some(1001),
            message: Some("This is an Xception".to_owned()),
        };

        verify_expected_result(Ok(x), &x_cmp)?;
    }

    info!("testMultiException - remote throws Xception2");
    {
        let r =
            thrift_test_client.test_multi_exception("Xception2".to_owned(), "ignored".to_owned());
        let x = match r {
            Err(thrift::Error::User(ref e)) => match e.downcast_ref::() {
                Some(x) => Ok(x),
                None => Err(thrift::Error::User(
                    "did not get expected Xception struct".into(),
                )),
            },
            _ => Err(thrift::Error::User("did not get exception".into())),
        }?;

        let x_cmp = Xception2 {
            error_code: Some(2002),
            struct_thing: Some(Xtruct {
                string_thing: Some("This is an Xception2".to_owned()),
                // since this is an OPT_IN_REQ_OUT field the sender sets a default
                byte_thing: Some(0),
                // since this is an OPT_IN_REQ_OUT field the sender sets a default
                i32_thing: Some(0),
                // since this is an OPT_IN_REQ_OUT field the sender sets a default
                i64_thing: Some(0),
            }),
        };

        verify_expected_result(Ok(x), &x_cmp)?;
    }

    info!("testMultiException - remote succeeds");
    {
        let r = thrift_test_client.test_multi_exception("haha".to_owned(), "RETURNED".to_owned());
        let x = match r {
            Err(e) => Err(thrift::Error::User(
                format!("received an unexpected exception {:?}", e).into(),
            )),
            _ => r,
        }?;

        let x_cmp = Xtruct {
            string_thing: Some("RETURNED".to_owned()),
            // since this is an OPT_IN_REQ_OUT field the sender sets a default
            byte_thing: Some(0),
            // since this is an OPT_IN_REQ_OUT field the sender sets a default
            i32_thing: Some(0),
            // since this is an OPT_IN_REQ_OUT field the sender sets a default
            i64_thing: Some(0),
        };

        verify_expected_result(Ok(x), x_cmp)?;
    }

    info!("testOneWay - remote sleeps for 1 second");
    {
        thrift_test_client.test_oneway(1)?;
    }

    // final test to verify that the connection is still writable after the one-way
    // call
    thrift_test_client.test_void()
}

fn verify_expected_result(
    actual: Result,
    expected: T,
) -> Result<(), thrift::Error> {
    info!("*** EXPECTED: Ok({:?})", expected);
    info!("*** ACTUAL  : {:?}", actual);
    match actual {
        Ok(v) => {
            if v == expected {
                info!("*** OK ***");
                Ok(())
            } else {
                info!("*** FAILED ***");
                Err(thrift::Error::User(
                    format!("expected {:?} but got {:?}", &expected, &v).into(),
                ))
            }
        }
        Err(e) => Err(e),
    }
}
thrift-0.16.0/test/rs/src/bin/test_server.rs000066400000000000000000000312461420101504100207450ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use clap::{clap_app, value_t};
use env_logger;
use log::*;

use std::collections::{BTreeMap, BTreeSet};
use std::thread;
use std::time::Duration;

use thrift;
use thrift::protocol::{
    TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory,
    TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory,
};
use thrift::server::{TMultiplexedProcessor, TServer};
use thrift::transport::{
    TBufferedReadTransportFactory, TBufferedWriteTransportFactory, TFramedReadTransportFactory,
    TFramedWriteTransportFactory, TReadTransportFactory, TWriteTransportFactory,
};
use thrift::OrderedFloat;
use thrift_test::*;

fn main() {
    env_logger::init();

    debug!("initialized logger - running cross-test server");

    match run() {
        Ok(()) => info!("cross-test server succeeded"),
        Err(e) => {
            info!("cross-test server failed with error {:?}", e);
            std::process::exit(1);
        }
    }
}

fn run() -> thrift::Result<()> {
    // unsupported options:
    // --domain-socket
    // --pipe
    // --ssl
    let matches = clap_app!(rust_test_client =>
        (version: "1.0")
        (author: "Apache Thrift Developers ")
        (about: "Rust Thrift test server")
        (@arg port: --port +takes_value "port on which the test server listens")
        (@arg transport: --transport +takes_value "transport implementation to use (\"buffered\", \"framed\")")
        (@arg protocol: --protocol +takes_value "protocol implementation to use (\"binary\", \"compact\")")
        (@arg server_type: --server_type +takes_value "type of server instantiated (\"simple\", \"thread-pool\")")
        (@arg workers: -n --workers +takes_value "number of thread-pool workers (\"4\")")
    )
            .get_matches();

    let port = value_t!(matches, "port", u16).unwrap_or(9090);
    let transport = matches.value_of("transport").unwrap_or("buffered");
    let protocol = matches.value_of("protocol").unwrap_or("binary");
    let server_type = matches.value_of("server_type").unwrap_or("thread-pool");
    let workers = value_t!(matches, "workers", usize).unwrap_or(4);
    let listen_address = format!("127.0.0.1:{}", port);

    info!("binding to {}", listen_address);

    let (i_transport_factory, o_transport_factory): (
        Box,
        Box,
    ) = match &*transport {
        "buffered" => (
            Box::new(TBufferedReadTransportFactory::new()),
            Box::new(TBufferedWriteTransportFactory::new()),
        ),
        "framed" => (
            Box::new(TFramedReadTransportFactory::new()),
            Box::new(TFramedWriteTransportFactory::new()),
        ),
        unknown => {
            return Err(format!("unsupported transport type {}", unknown).into());
        }
    };

    let (i_protocol_factory, o_protocol_factory): (
        Box,
        Box,
    ) = match &*protocol {
        "binary" | "multi" | "multi:binary" => (
            Box::new(TBinaryInputProtocolFactory::new()),
            Box::new(TBinaryOutputProtocolFactory::new()),
        ),
        "compact" | "multic" | "multi:compact" => (
            Box::new(TCompactInputProtocolFactory::new()),
            Box::new(TCompactOutputProtocolFactory::new()),
        ),
        unknown => {
            return Err(format!("unsupported transport type {}", unknown).into());
        }
    };

    let test_processor = ThriftTestSyncProcessor::new(ThriftTestSyncHandlerImpl {});

    match &*server_type {
        "simple" | "thread-pool" => {
            if protocol == "multi" || protocol == "multic" {
                let second_service_processor =
                    SecondServiceSyncProcessor::new(SecondServiceSyncHandlerImpl {});

                let mut multiplexed_processor = TMultiplexedProcessor::new();
                multiplexed_processor.register("ThriftTest", Box::new(test_processor), true)?;
                multiplexed_processor.register(
                    "SecondService",
                    Box::new(second_service_processor),
                    false,
                )?;

                let mut server = TServer::new(
                    i_transport_factory,
                    i_protocol_factory,
                    o_transport_factory,
                    o_protocol_factory,
                    multiplexed_processor,
                    workers,
                );

                server.listen(&listen_address)
            } else {
                let mut server = TServer::new(
                    i_transport_factory,
                    i_protocol_factory,
                    o_transport_factory,
                    o_protocol_factory,
                    test_processor,
                    workers,
                );

                server.listen(&listen_address)
            }
        }
        unknown => Err(format!("unsupported server type {}", unknown).into()),
    }
}

struct ThriftTestSyncHandlerImpl;
impl ThriftTestSyncHandler for ThriftTestSyncHandlerImpl {
    fn handle_test_void(&self) -> thrift::Result<()> {
        info!("testVoid()");
        Ok(())
    }

    fn handle_test_string(&self, thing: String) -> thrift::Result {
        info!("testString({})", &thing);
        Ok(thing)
    }

    fn handle_test_bool(&self, thing: bool) -> thrift::Result {
        info!("testBool({})", thing);
        Ok(thing)
    }

    fn handle_test_byte(&self, thing: i8) -> thrift::Result {
        info!("testByte({})", thing);
        Ok(thing)
    }

    fn handle_test_i32(&self, thing: i32) -> thrift::Result {
        info!("testi32({})", thing);
        Ok(thing)
    }

    fn handle_test_i64(&self, thing: i64) -> thrift::Result {
        info!("testi64({})", thing);
        Ok(thing)
    }

    fn handle_test_double(&self, thing: OrderedFloat) -> thrift::Result> {
        info!("testDouble({})", thing);
        Ok(thing)
    }

    fn handle_test_binary(&self, thing: Vec) -> thrift::Result> {
        info!("testBinary({:?})", thing);
        Ok(thing)
    }

    fn handle_test_struct(&self, thing: Xtruct) -> thrift::Result {
        info!("testStruct({:?})", thing);
        Ok(thing)
    }

    fn handle_test_nest(&self, thing: Xtruct2) -> thrift::Result {
        info!("testNest({:?})", thing);
        Ok(thing)
    }

    fn handle_test_map(&self, thing: BTreeMap) -> thrift::Result> {
        info!("testMap({:?})", thing);
        Ok(thing)
    }

    fn handle_test_string_map(
        &self,
        thing: BTreeMap,
    ) -> thrift::Result> {
        info!("testStringMap({:?})", thing);
        Ok(thing)
    }

    fn handle_test_set(&self, thing: BTreeSet) -> thrift::Result> {
        info!("testSet({:?})", thing);
        Ok(thing)
    }

    fn handle_test_list(&self, thing: Vec) -> thrift::Result> {
        info!("testList({:?})", thing);
        Ok(thing)
    }

    fn handle_test_enum(&self, thing: Numberz) -> thrift::Result {
        info!("testEnum({:?})", thing);
        Ok(thing)
    }

    fn handle_test_typedef(&self, thing: UserId) -> thrift::Result {
        info!("testTypedef({})", thing);
        Ok(thing)
    }

    /// @return map> - returns a dictionary with these values:
    /// {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 =>
    /// 2, 3 => 3, 4 => 4, }, }
    fn handle_test_map_map(&self, hello: i32) -> thrift::Result>> {
        info!("testMapMap({})", hello);

        let mut inner_map_0: BTreeMap = BTreeMap::new();
        for i in -4..(0 as i32) {
            inner_map_0.insert(i, i);
        }

        let mut inner_map_1: BTreeMap = BTreeMap::new();
        for i in 1..5 {
            inner_map_1.insert(i, i);
        }

        let mut ret_map: BTreeMap> = BTreeMap::new();
        ret_map.insert(-4, inner_map_0);
        ret_map.insert(4, inner_map_1);

        Ok(ret_map)
    }

    /// Creates a the returned map with these values and prints it out:
    ///     { 1 => { 2 => argument,
    ///              3 => argument,
    ///            },
    ///       2 => { 6 => , },
    ///     }
    /// return map> - a map with the above values
    fn handle_test_insanity(
        &self,
        argument: Insanity,
    ) -> thrift::Result>> {
        info!("testInsanity({:?})", argument);
        let mut map_0: BTreeMap = BTreeMap::new();
        map_0.insert(Numberz::TWO, argument.clone());
        map_0.insert(Numberz::THREE, argument);

        let mut map_1: BTreeMap = BTreeMap::new();
        let insanity = Insanity {
            user_map: None,
            xtructs: None,
        };
        map_1.insert(Numberz::SIX, insanity);

        let mut ret: BTreeMap> = BTreeMap::new();
        ret.insert(1, map_0);
        ret.insert(2, map_1);

        Ok(ret)
    }

    /// returns an Xtruct with:
    /// string_thing = "Hello2", byte_thing = arg0, i32_thing = arg1 and
    /// i64_thing = arg2
    fn handle_test_multi(
        &self,
        arg0: i8,
        arg1: i32,
        arg2: i64,
        _: BTreeMap,
        _: Numberz,
        _: UserId,
    ) -> thrift::Result {
        let x_ret = Xtruct {
            string_thing: Some("Hello2".to_owned()),
            byte_thing: Some(arg0),
            i32_thing: Some(arg1),
            i64_thing: Some(arg2),
        };

        Ok(x_ret)
    }

    /// if arg == "Xception" throw Xception with errorCode = 1001 and message =
    /// arg
    /// else if arg == "TException" throw TException
    /// else do not throw anything
    fn handle_test_exception(&self, arg: String) -> thrift::Result<()> {
        info!("testException({})", arg);

        match &*arg {
            "Xception" => Err((Xception {
                error_code: Some(1001),
                message: Some(arg),
            })
            .into()),
            "TException" => Err("this is a random error".into()),
            _ => Ok(()),
        }
    }

    /// if arg0 == "Xception":
    /// throw Xception with errorCode = 1001 and message = "This is an
    /// Xception"
    /// else if arg0 == "Xception2":
    /// throw Xception2 with errorCode = 2002 and struct_thing.string_thing =
    /// "This is an Xception2"
    // else:
    //   do not throw anything and return Xtruct with string_thing = arg1
    fn handle_test_multi_exception(&self, arg0: String, arg1: String) -> thrift::Result {
        match &*arg0 {
            "Xception" => Err((Xception {
                error_code: Some(1001),
                message: Some("This is an Xception".to_owned()),
            })
            .into()),
            "Xception2" => Err((Xception2 {
                error_code: Some(2002),
                struct_thing: Some(Xtruct {
                    string_thing: Some("This is an Xception2".to_owned()),
                    byte_thing: None,
                    i32_thing: None,
                    i64_thing: None,
                }),
            })
            .into()),
            _ => Ok(Xtruct {
                string_thing: Some(arg1),
                byte_thing: None,
                i32_thing: None,
                i64_thing: None,
            }),
        }
    }

    fn handle_test_oneway(&self, seconds_to_sleep: i32) -> thrift::Result<()> {
        thread::sleep(Duration::from_secs(seconds_to_sleep as u64));
        Ok(())
    }
}

struct SecondServiceSyncHandlerImpl;
impl SecondServiceSyncHandler for SecondServiceSyncHandlerImpl {
    fn handle_secondtest_string(&self, thing: String) -> thrift::Result {
        info!("(second)testString({})", &thing);
        let ret = format!("testString(\"{}\")", &thing);
        Ok(ret)
    }
}
thrift-0.16.0/test/rs/src/lib.rs000066400000000000000000000015221420101504100163700ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.





mod thrift_test;
pub use crate::thrift_test::*;
thrift-0.16.0/test/test.py000077500000000000000000000205271420101504100154030ustar00rootroot00000000000000#!/usr/bin/env python3
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

#
# Apache Thrift - integration (cross) test suite
#
# tests different server-client, protocol and transport combinations
#
# This script requires python 3.x due to the improvements in
# subprocess management that are needed for reliability.
#

from __future__ import print_function
from itertools import chain
import json
import logging
import multiprocessing
import argparse
import os
import sys

import crossrunner
from crossrunner.compat import path_join

# 3.3 introduced subprocess timeouts on waiting for child
req_version = (3, 3)
cur_version = sys.version_info
assert (cur_version >= req_version), "Python 3.3 or later is required for proper operation."


ROOT_DIR = os.path.dirname(os.path.realpath(os.path.dirname(__file__)))
TEST_DIR_RELATIVE = 'test'
TEST_DIR = path_join(ROOT_DIR, TEST_DIR_RELATIVE)
FEATURE_DIR_RELATIVE = path_join(TEST_DIR_RELATIVE, 'features')
CONFIG_FILE = 'tests.json'


def run_cross_tests(server_match, client_match, jobs, skip_known_failures, only_known_failures, retry_count, regex):
    logger = multiprocessing.get_logger()
    logger.debug('Collecting tests')
    with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp:
        j = json.load(fp)
    tests = crossrunner.collect_cross_tests(j, server_match, client_match, regex)
    if not tests:
        print('No test found that matches the criteria', file=sys.stderr)
        print('  servers: %s' % server_match, file=sys.stderr)
        print('  clients: %s' % client_match, file=sys.stderr)
        return False
    if only_known_failures:
        logger.debug('Only running known failures')
        known = crossrunner.load_known_failures(TEST_DIR)
        tests = list(filter(lambda t: crossrunner.test_name(**t) in known, tests))
    if skip_known_failures:
        logger.debug('Skipping known failures')
        known = crossrunner.load_known_failures(TEST_DIR)
        tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))

    dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, TEST_DIR_RELATIVE, jobs)
    logger.debug('Executing %d tests' % len(tests))
    try:
        for r in [dispatcher.dispatch(test, retry_count) for test in tests]:
            r.wait()
        logger.debug('Waiting for completion')
        return dispatcher.wait()
    except (KeyboardInterrupt, SystemExit):
        logger.debug('Interrupted, shutting down')
        dispatcher.terminate()
        return False


def run_feature_tests(server_match, feature_match, jobs, skip_known_failures, only_known_failures, retry_count, regex):
    basedir = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE)
    logger = multiprocessing.get_logger()
    logger.debug('Collecting tests')
    with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp:
        j = json.load(fp)
    with open(path_join(basedir, CONFIG_FILE), 'r') as fp:
        j2 = json.load(fp)
    tests = crossrunner.collect_feature_tests(j, j2, server_match, feature_match, regex)
    if not tests:
        print('No test found that matches the criteria', file=sys.stderr)
        print('  servers: %s' % server_match, file=sys.stderr)
        print('  features: %s' % feature_match, file=sys.stderr)
        return False
    if only_known_failures:
        logger.debug('Only running known failures')
        known = crossrunner.load_known_failures(basedir)
        tests = list(filter(lambda t: crossrunner.test_name(**t) in known, tests))
    if skip_known_failures:
        logger.debug('Skipping known failures')
        known = crossrunner.load_known_failures(basedir)
        tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))

    dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, FEATURE_DIR_RELATIVE, jobs)
    logger.debug('Executing %d tests' % len(tests))
    try:
        for r in [dispatcher.dispatch(test, retry_count) for test in tests]:
            r.wait()
        logger.debug('Waiting for completion')
        return dispatcher.wait()
    except (KeyboardInterrupt, SystemExit):
        logger.debug('Interrupted, shutting down')
        dispatcher.terminate()
        return False


def default_concurrenty():
    try:
        return int(os.environ.get('THRIFT_CROSSTEST_CONCURRENCY'))
    except (TypeError, ValueError):
        # Since much time is spent sleeping, use many threads
        return int(multiprocessing.cpu_count() * 1.25) + 1


def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument('--server', default='', nargs='*',
                        help='list of servers to test')
    parser.add_argument('--client', default='', nargs='*',
                        help='list of clients to test')
    parser.add_argument('-F', '--features', nargs='*', default=None,
                        help='run server feature tests instead of cross language tests')
    parser.add_argument('-R', '--regex', help='test name pattern to run')
    parser.add_argument('-o', '--only-known_failures', action='store_true', dest='only_known_failures',
                        help='only execute tests that are known to fail')
    parser.add_argument('-s', '--skip-known-failures', action='store_true', dest='skip_known_failures',
                        help='do not execute tests that are known to fail')
    parser.add_argument('-r', '--retry-count', type=int,
                        default=0, help='maximum retry on failure')
    parser.add_argument('-j', '--jobs', type=int,
                        default=default_concurrenty(),
                        help='number of concurrent test executions')

    g = parser.add_argument_group(title='Advanced')
    g.add_argument('-v', '--verbose', action='store_const',
                   dest='log_level', const=logging.DEBUG, default=logging.WARNING,
                   help='show debug output for test runner')
    g.add_argument('-P', '--print-expected-failures', choices=['merge', 'overwrite'],
                   dest='print_failures',
                   help="generate expected failures based on last result and print to stdout")
    g.add_argument('-U', '--update-expected-failures', choices=['merge', 'overwrite'],
                   dest='update_failures',
                   help="generate expected failures based on last result and save to default file location")
    options = parser.parse_args(argv)

    logger = multiprocessing.log_to_stderr()
    logger.setLevel(options.log_level)

    if options.features is not None and options.client:
        print('Cannot specify both --features and --client ', file=sys.stderr)
        return 1

    # Allow multiple args separated with ',' for backward compatibility
    server_match = list(chain(*[x.split(',') for x in options.server]))
    client_match = list(chain(*[x.split(',') for x in options.client]))

    if options.update_failures or options.print_failures:
        dire = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE) if options.features is not None else TEST_DIR
        res = crossrunner.generate_known_failures(
            dire, options.update_failures == 'overwrite',
            options.update_failures, options.print_failures)
    elif options.features is not None:
        features = options.features or ['.*']
        res = run_feature_tests(server_match, features, options.jobs,
                                options.skip_known_failures, options.only_known_failures,
                                options.retry_count, options.regex)
    else:
        res = run_cross_tests(server_match, client_match, options.jobs,
                              options.skip_known_failures, options.only_known_failures,
                              options.retry_count, options.regex)
    return 0 if res else 1


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
thrift-0.16.0/test/tests.json000066400000000000000000000273101420101504100161010ustar00rootroot00000000000000[
  {
    "name": "c_glib",
    "platforms": [
      "Linux"
    ],
    "server": {
      "command": [
        "test_server",
        "--lt-debug"
      ],
      "protocols": [
        "binary:multi",
        "compact:multic"
      ]
    },
    "client": {
      "command": [
        "test_client",
        "--lt-debug"
      ],
      "protocols": [
        "multi:binary",
        "multic:compact"
      ],
      "sockets": [
        "ip-ssl"
      ]
    },
    "transports": [
      "buffered",
      "framed"
    ],
    "sockets": [
      "ip",
      "domain"
    ],
    "protocols": [
      "binary",
      "compact",
      "multi",
      "multic"
    ],
    "workdir": "c_glib"
  },
  {
    "name": "cl",
    "server": {
      "command": ["TestServer"],
      "workdir": "cl",
      "protocols": ["binary", "multi"],
      "transports": ["buffered", "framed"],
      "sockets": ["ip"]
    },
    "client": {
      "command": ["TestClient"],
      "workdir": "cl",
      "protocols": ["binary", "multi"],
      "transports": ["buffered", "framed"],
      "sockets": ["ip"]
    }
  },
  {
    "name": "d",
    "server": {
      "command": [
        "thrift_test_server",
        "--trace"
      ]
    },
    "client": {
      "command": [
        "thrift_test_client"
      ]
    },
    "transports": [
      "http",
      "buffered",
      "framed",
      "zlib"
    ],
    "sockets": [
      "ip",
      "ip-ssl"
    ],
    "protocols": [
      "binary",
      "compact",
      "json"
    ],
    "workdir": "../lib/d/test"
  },
  {
    "name": "go",
    "server": {
      "command": [
        "testserver",
        "--certPath=../../keys"
      ]
    },
    "client": {
      "timeout": 6,
      "command": [
        "testclient"
      ]
    },
    "transports": [
      "buffered",
      "framed",
      "http",
      "zlib"
    ],
    "sockets": [
      "ip",
      "ip-ssl"
    ],
    "protocols": [
      "binary",
      "compact",
      "json",
      "header"
    ],
    "workdir": "go/bin"
  },
  {
    "name": "java",
    "join_args": false,
    "server": {
      "delay": 15,
      "command": [
        "build/runserver"
      ],
      "protocols": [
        "binary:multi",
        "compact:multic",
        "json:multij"
      ]
    },
    "client": {
      "timeout": 13,
      "command": [
        "build/runclient"
      ],
      "transports": [
        "http"
      ],
      "protocols": [
        "multi:binary",
        "multic:compact",
        "multij:json"
      ]
    },
    "transports": [
      "buffered",
      "framed",
      "framed:fastframed",
      "zlib"
    ],
    "sockets": [
      "ip",
      "ip-ssl"
    ],
    "protocols": [
      "binary",
      "compact",
      "json",
      "multi",
      "multic",
      "multij"
    ],
    "workdir": "../lib/java"
  },
  {
    "name": "nodejs",
    "env": {
      "NODE_PATH": "../lib"
    },
    "server": {
      "command": [
        "node",
        "server.js",
        "--type=tcp"
      ]
    },
    "client": {
      "timeout": 6,
      "command": [
        "node",
        "client.js",
        "--type=tcp"
      ]
    },
    "transports": [
      "buffered",
      "framed",
      "http",
      "websocket"
    ],
    "sockets": [
      "ip",
      "ip-ssl",
      "domain"
    ],
    "protocols": [
      "compact",
      "binary",
      "json",
      "header"
    ],
    "workdir": "../lib/nodejs/test"
  },
  {
    "name": "hs",
    "server": {
      "command": [
        "TestServer"
      ]
    },
    "client": {
      "timeout": 6,
      "transports": [
        "http"
      ],
      "command": [
        "TestClient"
      ]
    },
    "transports": [
      "buffered",
      "framed"
    ],
    "sockets": [
      "ip"
    ],
    "protocols": [
      "header",
      "compact",
      "binary",
      "json"
    ],
    "workdir": "hs"
  },
  {
    "name": "py",
    "server": {
      "extra_args": ["TSimpleServer"],
      "command": [
        "TestServer.py",
        "--verbose",
        "--genpydir=gen-py"
      ]
    },
    "client": {
      "timeout": 10,
      "command": [
        "TestClient.py",
        "--verbose",
        "--host=localhost",
        "--genpydir=gen-py"
      ]
    },
    "transports": [
      "buffered",
      "framed",
      "http",
      "zlib"
    ],
    "sockets": [
      "ip",
      "ip-ssl",
      "domain"
    ],
    "protocols": [
      "binary",
      "binary:accel",
      "compact",
      "compact:accelc",
      "header",
      "json",
      "multi",
      "multi:multia",
      "multia",
      "multiac",
      "multic",
      "multic:multiac",
      "multih",
      "multij"
    ],
    "workdir": "py"
  },
  {
    "comment": "Using 'python3' executable to test py2 and 3 at once",
    "name": "py3",
    "server": {
      "extra_args": ["TSimpleServer"],
      "command": [
        "python3",
        "TestServer.py",
        "--verbose",
        "--genpydir=gen-py"
      ]
    },
    "client": {
      "timeout": 10,
      "command": [
        "python3",
        "TestClient.py",
        "--host=localhost",
        "--genpydir=gen-py"
      ]
    },
    "transports": [
      "buffered",
      "framed",
      "http",
      "zlib"
    ],
    "sockets": [
      "ip",
      "ip-ssl",
      "domain"
    ],
    "protocols": [
      "binary",
      "binary:accel",
      "compact",
      "compact:accelc",
      "header",
      "json",
      "multi",
      "multi:multia",
      "multia",
      "multiac",
      "multic",
      "multic:multiac",
      "multih",
      "multij"
    ],
    "workdir": "py"
  },
  {
    "name": "cpp",
    "server": {
      "command": [
        "TestServer"
      ],
      "protocols": [
        "binary:multi",
        "compact:multic",
        "header:multih",
        "json:multij"
      ]
    },
    "client": {
      "timeout": 8,
      "command": [
        "TestClient"
      ],
      "protocols": [
        "multi:binary",
        "multic:compact",
        "multih:header",
        "multij:json"
      ]
    },
    "transports": [
      "buffered",
      "http",
      "framed",
      "zlib",
      "websocket"
    ],
    "sockets": [
      "ip",
      "ip-ssl",
      "domain"
    ],
    "protocols": [
      "compact",
      "binary",
      "json",
      "header",
      "multi",
      "multic",
      "multih",
      "multij"
    ],
    "workdir": "cpp"
  },
  {
    "name": "rb",
    "server": {
      "command": [
        "ruby",
        "../integration/TestServer.rb"
      ]
    },
    "client": {
      "timeout": 10,
      "command": [
        "ruby",
        "../integration/TestClient.rb",
        "--"
      ]
    },
    "transports": [
      "buffered",
      "framed"
    ],
    "sockets": [
      "domain",
      "ip",
      "ip-ssl"
    ],
    "protocols": [
      "binary",
      "binary:accel",
      "compact",
      "json"
    ],
    "workdir": "rb/gen-rb"
  },
  {
    "name": "netstd",
    "transports": [
      "buffered",
      "framed"
    ],
    "sockets": [
      "ip",
      "ip-ssl"
    ],
    "protocols": [
      "binary",
      "compact",
      "json"
    ],
    "server": {
      "command": [
        "dotnet",
        "run",
        "--no-build",
        "--project=Server/Server.csproj",
        "server"
      ]
    },
    "client": {
      "timeout": 10,
      "command": [
        "dotnet",
        "run",
        "--no-build",
        "--project=Client/Client.csproj",
        "client"
      ]
    },
        "workdir": "netstd"
  },
  {
    "name": "perl",
    "transports": [
      "buffered",
      "framed"
    ],
    "sockets": [
      "ip",
      "ip-ssl",
      "domain"
    ],
    "protocols": [
      "binary",
      "multi"
    ],
    "client": {
      "command": [
        "perl",
        "-Igen-perl/",
        "-I../../lib/perl/lib/",
        "TestClient.pl",
        "--ca=../keys/CA.pem",
        "--cert=../keys/client.crt",
        "--key=../keys/client.key"
      ],
      "protocols": [
        "multi:binary"
      ]
    },
    "server": {
      "command": [
        "perl",
        "-Igen-perl/",
        "-I../../lib/perl/lib/",
        "TestServer.pl",
        "--cert=../keys/server.crt",
        "--key=../keys/server.key"
      ],
      "protocols": [
        "binary:multi"
      ]
    },
    "workdir": "perl"
  },
  {
    "name": "php",
    "client": {
      "timeout": 6,
      "transports": [
        "buffered",
        "framed"
      ],
      "sockets": [
        "ip"
      ],
      "protocols": [
        "binary",
        "binary:accel",
        "compact",
        "json"
      ],
      "command": [
        "php",
        "-dextension_dir=php_ext_dir",
        "--php-ini=test_php.ini",
        "--no-php-ini",
        "-ddisplay_errors=stderr",
        "-dlog_errors=0",
        "-derror_reporting=E_ALL",
        "TestClient.php"
      ]
    },
    "workdir": "php"
  },
  {
    "name": "dart",
    "client": {
      "timeout": 30,
      "transports": [
        "buffered",
        "framed",
        "http"
      ],
      "sockets": [
        "ip"
      ],
      "protocols": [
        "binary",
        "compact",
        "json"
      ],
      "command": [
        "dart",
	    "--enable-asserts",
        "test_client/bin/main.dart",
	    "--verbose"
      ]
    },
    "workdir": "dart"
  },
  {
    "name": "erl",
    "transports": [
      "buffered",
      "framed"
    ],
    "sockets": [
      "ip",
      "ip-ssl"
    ],
    "protocols": [
      "binary",
      "compact"
    ],
    "client": {
      "command": [
        "erl",
        "+K",
        "true",
        "-noshell",
        "-pa",
        "../../lib/erl/_build/default/lib/thrift/ebin/",
        "-pa",
        "./_build/default/lib/thrift_test/ebin",
        "-s",
        "test_client",
        "-s",
        "init",
        "stop",
        "-extra"
      ]
    },
    "server": {
      "command": [
        "erl",
        "+K",
        "true",
        "-noshell",
        "-pa",
        "../../lib/erl/_build/default/lib/thrift/ebin/",
        "-pa",
        "./_build/default/lib/thrift_test/ebin",
        "-s",
        "test_thrift_server",
        "-extra"
      ]
    },
    "workdir": "erl"
  },
  {
    "name": "js",
    "transports": [
      "http"
    ],
    "sockets": [
      "ip"
    ],
    "protocols": [
      "json"
    ],
    "client": {
      "command": [
        "phantomjs",
        "test/phantom-client.js"
      ]
    },
    "workdir": "../lib/js"
  },
  {
    "name": "lua",
    "TODO": "Add dll to LUA_CPATH",
    "env": {
      "LUA_PATH": ";;gen-lua/?.lua;../../lib/lua/?.lua",
      "LUA_CPATH": ";;../../lib/lua/.libs/?.so"
    },
    "client": {
      "timeout": 5,
      "transports": [
        "buffered",
        "framed",
        "http"
      ],
      "sockets": [
        "ip"
      ],
      "protocols": [
        "binary",
        "compact",
        "json"
      ],
      "command": [
        "lua",
        "test_basic_client.lua"
      ]
    },
    "workdir": "lua"
  },
  {
    "name": "rs",
    "env": {
      "RUST_BACKTRACE": "1",
      "RUST_LOG": "info"
    },
    "server": {
      "command": [
        "test_server"
      ],
      "protocols": [
        "binary:multi",
        "compact:multic"
      ]
    },
    "client": {
      "timeout": 6,
      "command": [
        "test_client"
      ],
      "protocols": [
        "multi:binary",
        "multic:compact"
      ]
    },
    "sockets": [
      "ip"
    ],
    "transports": [
      "buffered",
      "framed"
    ],
    "protocols": [
      "binary",
      "compact",
      "multi",
      "multic"
    ],
    "workdir": "rs/bin"
  },
  {
    "name": "nodets",
    "env": {
      "NODE_PATH": "../lib"
    },
    "server": {
      "command": [
        "runServer.sh"
      ]
    },
    "client": {
      "timeout": 6,
      "command": [
        "runClient.sh"
      ]
    },
    "protocols": [
      "binary"
    ],
    "sockets": [
      "ip"
    ],
    "transports": [
      "buffered"
    ],
    "workdir": "../lib/nodets/test"
  }
]
thrift-0.16.0/test/threads/000077500000000000000000000000001420101504100154735ustar00rootroot00000000000000thrift-0.16.0/test/threads/Makefile000066400000000000000000000033141420101504100171340ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

# Default target is everything

ifndef thrift_home
thrift_home=../../
endif #thrift_home

target: all

ifndef boost_home
boost_home=/usr/local/include/boost-1_33_1
endif #boost_home
target: all

include_paths = $(thrift_home)/lib/cpp/src \
		$(boost_home)

include_flags = $(patsubst %,-I%, $(include_paths))

# Tools
ifndef THRIFT
THRIFT = ../../compiler/cpp/thrift
endif # THRIFT

CC     = g++
LD     = g++

# Compiler flags
LFL   =  -L$(thrift_home)/lib/cpp/.libs -lthrift
CCFL  = -Wall -O3 -g -I./gen-cpp $(include_flags)
CFL   = $(CCFL) $(LFL)

all: server client

stubs: ThreadsTest.thrift
	$(THRIFT) --gen cpp --gen py ThreadsTest.thrift

server: stubs
	$(CC) -o ThreadsServer $(CFL) ThreadsServer.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp

client: stubs
	$(CC) -o ThreadsClient $(CFL) ThreadsClient.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp

clean:
	$(RM) -r *.o ThreadsServer ThreadsClient gen-cpp gen-py
thrift-0.16.0/test/threads/ThreadsClient.cpp000066400000000000000000000041651420101504100207360ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "ThreadsTest.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#if _WIN32
   #include 
#endif

using boost::shared_ptr;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using namespace apache::thrift::concurrency;

int main(int argc, char **argv) {
#if _WIN32
  transport::TWinsockSingleton::create();
#endif
  int port = 9090;
  std::string host = "localhost";

  shared_ptr transport(new TSocket(host, port));
  shared_ptr protocol(new TBinaryProtocol(transport));

  transport->open();

  ThreadsTestClient client(protocol);
  int val;
  val = client.threadOne(5);
  fprintf(stderr, "%d\n", val);
  val = client.stop();
  fprintf(stderr, "%d\n", val);
  val = client.threadTwo(5);
  fprintf(stderr, "%d\n", val);

  transport->close();

  fprintf(stderr, "done.\n");

  return 0;
}

thrift-0.16.0/test/threads/ThreadsServer.cpp000066400000000000000000000104341420101504100207620ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "ThreadsTest.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#if _WIN32
   #include 
#endif

using boost::shared_ptr;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using namespace apache::thrift::concurrency;


class ThreadsTestHandler : virtual public ThreadsTestIf {
 public:
  ThreadsTestHandler() {
    // Your initialization goes here
  }

  int32_t threadOne(const int32_t sleep) {
    // Your implementation goes here
    printf("threadOne\n");
    go2sleep(1, sleep);
    return 1;
  }

  int32_t threadTwo(const int32_t sleep) {
    // Your implementation goes here
    printf("threadTwo\n");
    go2sleep(2, sleep);
    return 1;
  }

  int32_t threadThree(const int32_t sleep) {
    // Your implementation goes here
    printf("threadThree\n");
    go2sleep(3, sleep);
    return 1;
  }

  int32_t threadFour(const int32_t sleep) {
    // Your implementation goes here
    printf("threadFour\n");
    go2sleep(4, sleep);
    return 1;
  }

  int32_t stop() {
    printf("stop\n");
    server_->stop();
    return 1;
  }

  void setServer(boost::shared_ptr server) {
    server_ = server;
  }

protected:
  void go2sleep(int thread, int seconds) {
    Monitor m;
    Synchronized s(m);
    for (int i = 0; i < seconds; ++i) {
      fprintf(stderr, "Thread %d: sleep %d\n", thread, i);
      try {
        m.wait(1000);
      } catch(const TimedOutException&) {
      }
    }
    fprintf(stderr, "THREAD %d DONE\n", thread);
  }

private:
  boost::shared_ptr server_;

};

int main(int argc, char **argv) {
#if _WIN32
  transport::TWinsockSingleton::create();
#endif
  int port = 9090;
  shared_ptr handler(new ThreadsTestHandler());
  shared_ptr processor(new ThreadsTestProcessor(handler));
  shared_ptr serverTransport(new TServerSocket(port));
  shared_ptr transportFactory(new TBufferedTransportFactory());
  shared_ptr protocolFactory(new TBinaryProtocolFactory());

  /*
  shared_ptr threadManager =
    ThreadManager::newSimpleThreadManager(10);
  shared_ptr threadFactory =
    shared_ptr(new ThreadFactory());
  threadManager->threadFactory(threadFactory);
  threadManager->start();

  shared_ptr server =
    shared_ptr(new TThreadPoolServer(processor,
                                              serverTransport,
                                              transportFactory,
                                              protocolFactory,
                                              threadManager));
  */

  shared_ptr server =
    shared_ptr(new TThreadedServer(processor,
                                            serverTransport,
                                            transportFactory,
                                            protocolFactory));

  handler->setServer(server);

  server->serve();

  fprintf(stderr, "done.\n");

  return 0;
}

thrift-0.16.0/test/threads/ThreadsTest.thrift000066400000000000000000000017271420101504100211560ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

service ThreadsTest {
  i32 threadOne(1: i32 sleep=15),
  i32 threadTwo(2: i32 sleep=15),
  i32 threadThree(3: i32 sleep=15),
  i32 threadFour(4: i32 sleep=15)

  i32 stop();

}
thrift-0.16.0/test/valgrind.suppress000066400000000000000000000034461420101504100174640ustar00rootroot00000000000000{
   boost/get_once_per_thread_epoch/ignore
   Memcheck:Leak
   match-leak-kinds: reachable
   fun:malloc
   fun:_ZN5boost6detail25get_once_per_thread_epochEv
}
{
   boostthreads/once/ignore
   Helgrind:Race
   fun:_ZN5boost13thread_detail17enter_once_regionERNS_9once_flagE
   fun:_ZN5boost6detail23get_current_thread_dataEv
   fun:_ZN5boost6detail20interruption_checkerC1EP15pthread_mutex_tP14pthread_cond_t
   fun:_ZN5boost22condition_variable_any4waitINS_11unique_lockINS_11timed_mutexEEEEEvRT_
   fun:_ZN6apache6thrift11concurrency7Monitor4Impl11waitForeverEv
   fun:_ZN6apache6thrift11concurrency7Monitor4Impl19waitForTimeRelativeEl
   fun:_ZN6apache6thrift11concurrency7Monitor4Impl4waitEl
   fun:_ZNK6apache6thrift11concurrency7Monitor4waitEl
   fun:_ZN6apache6thrift11concurrency11BoostThread5startEv
   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
   fun:main
}
{
   pthread/creation-tls/ignore
   Helgrind:Race
   fun:mempcpy
   fun:_dl_allocate_tls_init
   fun:get_cached_stack
   fun:allocate_stack
   fun:pthread_create@@GLIBC_2.2*
   obj:/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so
   fun:_ZN6apache6thrift11concurrency13PthreadThread5startEv
   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
   fun:main
}
{
   boost-thread/creation-tls/ignore
   Helgrind:Race
   fun:mempcpy
   fun:_dl_allocate_tls_init
   fun:get_cached_stack
   fun:allocate_stack
   fun:pthread_create@@GLIBC_2.2.5
   obj:/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so
   fun:_ZN5boost6thread21start_thread_noexceptEv
   fun:_ZN5boost6thread12start_threadEv
   fun:_ZN5boost6threadC1ISt5_BindIFPFPvS3_ES3_EEEEOT_
   fun:_ZN6apache6thrift11concurrency11BoostThread5startEv
   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
   fun:main
}


thrift-0.16.0/tutorial/000077500000000000000000000000001420101504100147255ustar00rootroot00000000000000thrift-0.16.0/tutorial/Makefile.am000077500000000000000000000035111420101504100167640ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

SUBDIRS =

if MINGW
# do nothing, just build the compiler
else

if WITH_C_GLIB
SUBDIRS += c_glib
endif

if WITH_CPP
SUBDIRS += cpp
endif

if WITH_D
SUBDIRS += d
endif

if WITH_JAVA
SUBDIRS += java
SUBDIRS += js
endif

if WITH_PYTHON
SUBDIRS += py
SUBDIRS += py.twisted
SUBDIRS += py.tornado
endif

if WITH_RUBY
SUBDIRS += rb
endif

if WITH_HAXE
SUBDIRS += haxe
endif

if WITH_DOTNET
SUBDIRS += netstd
endif

if WITH_GO
SUBDIRS += go
endif

if WITH_NODEJS
SUBDIRS += nodejs
endif

if WITH_DART
SUBDIRS += dart
endif

if WITH_RS
SUBDIRS += rs
endif

if WITH_CL
SUBDIRS += cl
endif

if WITH_PERL
SUBDIRS += perl
endif

if WITH_PHP
SUBDIRS += php
endif

#
# generate html for ThriftTest.thrift
#
all-local:
	$(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/tutorial/tutorial.thrift

clean-local:
	rm -rf $(top_srcdir)/tutorial/gen-html

endif

# Any folders or files not listed above being added to SUBDIR need to be placed here in
# EXTRA_DIST to be included in the release
EXTRA_DIST = \
	d \
	delphi \
	erl \
	ocaml \
	shared.thrift \
	tutorial.thrift \
	README.md
thrift-0.16.0/tutorial/README.md000066400000000000000000000026051420101504100162070ustar00rootroot00000000000000Thrift Tutorial

License
=======

Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.

Tutorial
========

1) First things first, you'll need to install the Thrift compiler and the
   language libraries. Do that using the instructions in the top level
   README.md file.

2) Read tutorial.thrift to learn about the syntax of a Thrift file

3) Compile the code for the language of your choice:
```
     $ thrift
     $ thrift -r --gen cpp tutorial.thrift
```
4) Take a look at the generated code.

5) Look in the language directories for sample client/server code.

6) That's about it for now. This tutorial is intentionally brief. It should be
   just enough to get you started and ready to build your own project.
thrift-0.16.0/tutorial/c_glib/000077500000000000000000000000001420101504100161445ustar00rootroot00000000000000thrift-0.16.0/tutorial/c_glib/Makefile.am000077500000000000000000000050421420101504100202040ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
AUTOMAKE_OPTIONS = subdir-objects serial-tests nostdinc

BUILT_SOURCES = \
	gen-c_glib/calculator.h \
	gen-c_glib/shared_service.h \
	gen-c_glib/shared_types.h \
	gen-c_glib/tutorial_types.h

AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES) @GCOV_CFLAGS@ -I$(top_builddir)/lib/c_glib/src/thrift
AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib
AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS) @GCOV_LDFLAGS@

noinst_LTLIBRARIES = \
	libtutorialgencglib.la

nodist_libtutorialgencglib_la_SOURCES = \
	gen-c_glib/calculator.c \
	gen-c_glib/calculator.h \
	gen-c_glib/shared_service.c \
	gen-c_glib/shared_service.h \
	gen-c_glib/shared_types.c \
	gen-c_glib/shared_types.h \
	gen-c_glib/tutorial_types.c \
	gen-c_glib/tutorial_types.h

libtutorialgencglib_la_LIBADD = \
	$(top_builddir)/lib/c_glib/libthrift_c_glib.la

libtutorialgencglib_la_CFLAGS = \
	$(AM_CFLAGS) -Wno-unused-function

noinst_PROGRAMS = \
	tutorial_server \
	tutorial_client

tutorial_server_SOURCES = \
	c_glib_server.c
tutorial_server_LDFLAGS = $(OPENSSL_LIBS)

tutorial_server_LDADD = \
	libtutorialgencglib.la \
	$(top_builddir)/lib/c_glib/libthrift_c_glib.la

tutorial_client_SOURCES = \
	c_glib_client.c

tutorial_client_LDADD = \
	libtutorialgencglib.la \
	$(top_builddir)/lib/c_glib/libthrift_c_glib.la


gen-c_glib/calculator.c gen-c_glib/calculator.h gen-c_glib/shared_service.c gen-c_glib/shared_service.h gen-c_glib/shared_types.c gen-c_glib/shared_types.h gen-c_glib/tutorial_types.c gen-c_glib/tutorial_types.h: $(top_srcdir)/tutorial/tutorial.thrift
	$(THRIFT) --gen c_glib -r $<

clean-local:
	$(RM) gen-c_glib/*

tutorialserver: all
	./tutorial_server

tutorialclient: all
	./tutorial_client

EXTRA_DIST = \
	c_glib_server.c \
	c_glib_client.c
thrift-0.16.0/tutorial/c_glib/c_glib_client.c000066400000000000000000000134551420101504100210750ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include 
#include 

#include 
#include 
#include 

#include "gen-c_glib/calculator.h"

int main (void)
{
  ThriftSocket *socket;
  ThriftTransport *transport;
  ThriftProtocol *protocol;
  CalculatorIf *client;

  GError *error = NULL;
  InvalidOperation *invalid_operation = NULL;

  Work *work;

  gint32 sum;
  gint32 diff;

  int exit_status = 0;

#if (!GLIB_CHECK_VERSION (2, 36, 0))
  g_type_init ();
#endif

  socket    = g_object_new (THRIFT_TYPE_SOCKET,
                            "hostname",  "localhost",
                            "port",      9090,
                            NULL);
  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
                            "transport", socket,
                            NULL);
  protocol  = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
                            "transport", transport,
                            NULL);

  thrift_transport_open (transport, &error);


  /* In the C (GLib) implementation of Thrift, service methods on the
     server are accessed via a generated client class that implements
     the service interface. In this tutorial, we access a Calculator
     service through an instance of CalculatorClient, which implements
     CalculatorIf. */
  client = g_object_new (TYPE_CALCULATOR_CLIENT,
                         "input_protocol",  protocol,
                         "output_protocol", protocol,
                         NULL);

  /* Each of the client methods requires at least two parameters: A
     pointer to the client-interface implementation (the client
     object), and a handle to a GError structure to receive
     information about any error that occurs.

     On success, client methods return TRUE. A return value of FALSE
     indicates an error occurred and the error parameter has been
     set. */
  if (!error && calculator_if_ping (client, &error)) {
    puts ("ping()");
  }

  /* Service methods that return a value do so by passing the result
     back via an output parameter (here, "sum"). */
  if (!error && calculator_if_add (client, &sum, 1, 1, &error)) {
    printf ("1+1=%d\n", sum);
  }

  /* Thrift structs are implemented as GObjects, with each of the
     struct's members exposed as an object property. */
  work = g_object_new (TYPE_WORK, NULL);

  if (!error) {
    g_object_set (work,
                  "num1", 1,
                  "num2", 0,
                  "op",   OPERATION_DIVIDE,
                  NULL);

    /* Exceptions are passed back from service methods in a manner
       similar to return values. */
    if (calculator_if_calculate (client,
                                 NULL,
                                 1,
                                 work,
                                 &invalid_operation,
                                 &error)) {
      puts ("Whoa? We can divide by zero!");
    }
    else {
      if (invalid_operation) {
        gchar *why;

        /* Like structs, exceptions are implemented as objects with
           properties. */
        g_object_get (invalid_operation, "why", &why, NULL);

        printf ("InvalidOperation: %s\n", why);

        if (why != NULL)
          g_free (why);
        g_object_unref (invalid_operation);
        invalid_operation = NULL;
      }

      g_clear_error (&error);
    }
  }

  if (!error) {
    /* Struct objects can be reused across method invocations. */
    g_object_set (work,
                  "num1", 15,
                  "num2", 10,
                  "op",   OPERATION_SUBTRACT,
                  NULL);

    if (calculator_if_calculate (client,
                                 &diff,
                                 1,
                                 work,
                                 &invalid_operation,
                                 &error)) {
      printf ("15-10=%d\n", diff);
    }
  }

  g_object_unref (work);

  if (!error) {
    SharedStruct *shared_struct;
    gchar *value;

    shared_struct = g_object_new (TYPE_SHARED_STRUCT, NULL);

    /* As defined in the Thrift file, the Calculator service extends
       the SharedService service. Correspondingly, in the generated
       code CalculatorIf inherits from SharedServiceIf, and the parent
       service's methods are accessible through a simple cast. */
    if (shared_service_client_get_struct (SHARED_SERVICE_IF (client),
                                          &shared_struct,
                                          1,
                                          &error)) {
      g_object_get (shared_struct, "value", &value, NULL);
      printf ("Check log: %s\n", value);
      g_free (value);
    }

    g_object_unref (shared_struct);
  }

  if (error) {
    printf ("ERROR: %s\n", error->message);
    g_clear_error (&error);

    exit_status = 1;
  }

  thrift_transport_close (transport, NULL);

  g_object_unref (client);
  g_object_unref (protocol);
  g_object_unref (transport);
  g_object_unref (socket);

  return exit_status;
}
thrift-0.16.0/tutorial/c_glib/c_glib_server.c000066400000000000000000000444341420101504100211260ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "gen-c_glib/calculator.h"

G_BEGIN_DECLS

/* In the C (GLib) implementation of Thrift, the actual work done by a
   server---that is, the code that runs when a client invokes a
   service method---is defined in a separate "handler" class that
   implements the service interface. Here we define the
   TutorialCalculatorHandler class, which implements the CalculatorIf
   interface and provides the behavior expected by tutorial clients.
   (Typically this code would be placed in its own module but for
   clarity this tutorial is presented entirely in a single file.)

   For each service the Thrift compiler generates an abstract base
   class from which handler implementations should inherit. In our
   case TutorialCalculatorHandler inherits from CalculatorHandler,
   defined in gen-c_glib/calculator.h.

   If you're new to GObject, try not to be intimidated by the quantity
   of code here---much of it is boilerplate and can mostly be
   copied-and-pasted from existing work. For more information refer to
   the GObject Reference Manual, available online at
   https://developer.gnome.org/gobject/. */

#define TYPE_TUTORIAL_CALCULATOR_HANDLER \
  (tutorial_calculator_handler_get_type ())

#define TUTORIAL_CALCULATOR_HANDLER(obj)                                \
  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
                               TYPE_TUTORIAL_CALCULATOR_HANDLER,        \
                               TutorialCalculatorHandler))
#define TUTORIAL_CALCULATOR_HANDLER_CLASS(c)                    \
  (G_TYPE_CHECK_CLASS_CAST ((c),                                \
                            TYPE_TUTORIAL_CALCULATOR_HANDLER,   \
                            TutorialCalculatorHandlerClass))
#define IS_TUTORIAL_CALCULATOR_HANDLER(obj)                             \
  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
                               TYPE_TUTORIAL_CALCULATOR_HANDLER))
#define IS_TUTORIAL_CALCULATOR_HANDLER_CLASS(c)                 \
  (G_TYPE_CHECK_CLASS_TYPE ((c),                                \
                            TYPE_TUTORIAL_CALCULATOR_HANDLER))
#define TUTORIAL_CALCULATOR_HANDLER_GET_CLASS(obj)              \
  (G_TYPE_INSTANCE_GET_CLASS ((obj),                            \
                              TYPE_TUTORIAL_CALCULATOR_HANDLER, \
                              TutorialCalculatorHandlerClass))

struct _TutorialCalculatorHandler {
  CalculatorHandler parent_instance;

  /* private */
  GHashTable *log;
};
typedef struct _TutorialCalculatorHandler TutorialCalculatorHandler;

struct _TutorialCalculatorHandlerClass {
  CalculatorHandlerClass parent_class;
};
typedef struct _TutorialCalculatorHandlerClass TutorialCalculatorHandlerClass;

GType tutorial_calculator_handler_get_type (void);

G_END_DECLS

/* ---------------------------------------------------------------- */

/* The implementation of TutorialCalculatorHandler follows. */

G_DEFINE_TYPE (TutorialCalculatorHandler,
               tutorial_calculator_handler,
               TYPE_CALCULATOR_HANDLER)

/* Each of a handler's methods accepts at least two parameters: A
   pointer to the service-interface implementation (the handler object
   itself) and a handle to a GError structure to receive information
   about any error that occurs.

   On success, a handler method returns TRUE. A return value of FALSE
   indicates an error occurred and the error parameter has been
   set. (Methods should not return FALSE without first setting the
   error parameter.) */
static gboolean
tutorial_calculator_handler_ping (CalculatorIf  *iface,
                                  GError       **error)
{
  THRIFT_UNUSED_VAR (iface);
  THRIFT_UNUSED_VAR (error);

  puts ("ping()");

  return TRUE;
}

/* Service-method parameters are passed through as parameters to the
   handler method.

   If the service method returns a value an output parameter, _return,
   is additionally passed to the handler method. This parameter should
   be set appropriately before the method returns, whenever it
   succeeds.

   The return value from this method happens to be of a base type,
   i32, but note if a method returns a complex type such as a map or
   list *_return will point to a pre-allocated data structure that
   does not need to be re-allocated and should not be destroyed. */
static gboolean
tutorial_calculator_handler_add (CalculatorIf  *iface,
                                 gint32        *_return,
                                 const gint32   num1,
                                 const gint32   num2,
                                 GError       **error)
{
  THRIFT_UNUSED_VAR (iface);
  THRIFT_UNUSED_VAR (error);

  printf ("add(%d,%d)\n", num1, num2);
  *_return = num1 + num2;

  return TRUE;
}

/* Any handler method can return a ThriftApplicationException to the
   client by setting its error parameter appropriately and returning
   FALSE. See the ThriftApplicationExceptionError enumeration defined
   in thrift_application_exception.h for a list of recognized
   exception types (GError codes).

   If a service method can also throw a custom exception (that is, one
   defined in the .thrift file) an additional output parameter will be
   provided (here, "ouch") to hold an instance of the exception, when
   necessary. Note there will be a separate parameter added for each
   type of exception the method can throw.

   Unlike return values, exception objects are never pre-created; this
   is always the responsibility of the handler method. */
static gboolean
tutorial_calculator_handler_calculate (CalculatorIf      *iface,
                                       gint32            *_return,
                                       const gint32       logid,
                                       const Work        *w,
                                       InvalidOperation **ouch,
                                       GError           **error)
{
  TutorialCalculatorHandler *self;

  gint *log_key;
  gchar log_value[12];
  SharedStruct *log_struct;

  gint num1;
  gint num2;
  Operation op;
  gboolean result = TRUE;

  THRIFT_UNUSED_VAR (error);

  g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
                        FALSE);
  self = TUTORIAL_CALCULATOR_HANDLER (iface);

  /* Remember: Exception objects are never pre-created */
  g_assert (*ouch == NULL);

  /* Fetch the contents of our Work parameter.

     Note that integer properties of thirty-two bits or fewer in width
     are _always_ of type gint, regardless of the range of values they
     hold. A common error is trying to retrieve, say, a structure
     member defined in the .thrift file as type i16 into a variable of
     type gint16, which will clobber variables adjacent on the
     stack. Remember: If you're retrieving an integer property the
     receiving variable must be of either type gint or gint64, as
     appropriate. */
  g_object_get ((Work *)w,
                "num1", &num1,
                "num2", &num2,
                "op",   &op,
                NULL);

  printf ("calculate(%d,{%d,%d,%d})\n", logid, op, num1, num2);

  switch (op) {
  case OPERATION_ADD:
    *_return = num1 + num2;
    break;

  case OPERATION_SUBTRACT:
    *_return = num1 - num2;
    break;

  case OPERATION_MULTIPLY:
    *_return = num1 * num2;
    break;

  case OPERATION_DIVIDE:
    if (num2 == 0) {
      /* For each custom exception type a subclass of ThriftStruct is
         generated by the Thrift compiler. Throw an exception by
         setting the corresponding output parameter to a new instance
         of its type and returning FALSE. */
      *ouch = g_object_new (TYPE_INVALID_OPERATION,
                            "whatOp", op,
                            "why",  g_strdup ("Cannot divide by 0"),
                            NULL);
      result = FALSE;

      /* Note the call to g_strdup above: All the memory used by a
         ThriftStruct's properties belongs to the object itself and
         will be freed on destruction. Removing this call to g_strdup
         will lead to a segmentation fault as the object tries to
         release memory allocated statically to the program. */
    }
    else {
      *_return = num1 / num2;
    }
    break;

  default:
    *ouch = g_object_new (TYPE_INVALID_OPERATION,
                          "whatOp", op,
                          "why",  g_strdup ("Invalid Operation"),
                          NULL);
    result = FALSE;
  }

  /* On success, log a record of the result to our hash table */
  if (result) {
    log_key = g_malloc (sizeof *log_key);
    *log_key = logid;

    snprintf (log_value, sizeof log_value, "%d", *_return);

    log_struct = g_object_new (TYPE_SHARED_STRUCT,
                               "key",   *log_key,
                               "value",  g_strdup (log_value),
                               NULL);
    g_hash_table_replace (self->log, log_key, log_struct);
  }

  return result;
}

/* A one-way method has the same signature as an equivalent, regular
   method that returns no value. */
static gboolean
tutorial_calculator_handler_zip (CalculatorIf  *iface,
                                 GError       **error)
{
  THRIFT_UNUSED_VAR (iface);
  THRIFT_UNUSED_VAR (error);

  puts ("zip()");

  return TRUE;
}

/* As specified in the .thrift file (tutorial.thrift), the Calculator
   service extends the SharedService service. Correspondingly, in the
   generated code the Calculator interface, CalculatorIf, extends the
   SharedService interface, SharedServiceIf, and subclasses of
   CalculatorHandler should implement its methods as well.

   Here we provide an implementation for the getStruct method from the
   parent service. */
static gboolean
tutorial_calculator_handler_get_struct (SharedServiceIf  *iface,
                                        SharedStruct    **_return,
                                        const gint32      key32,
                                        GError          **error)
{
  gint key = (gint)key32;
  TutorialCalculatorHandler *self;
  SharedStruct *log_struct;
  gint log_key;
  gchar *log_value;

  THRIFT_UNUSED_VAR (error);

  g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
                        FALSE);
  self = TUTORIAL_CALCULATOR_HANDLER (iface);

  /* Remember: Complex return types are always pre-created and need
     only be populated */
  g_assert (*_return != NULL);

  printf ("getStruct(%d)\n", key);

  /* If the key exists in our log, return the corresponding logged
     data (or an empty SharedStruct structure if it does not).

     Incidentally, note we _must_ here copy the values from the hash
     table into the return structure. All memory used by the return
     structure belongs to the structure itself and will be freed once
     a response is sent to the client. If we merely freed *_return and
     set it to point to our hash-table entry, that would mean memory
     would be released (effectively, data erased) out of the hash
     table! */
  log_struct = g_hash_table_lookup (self->log, &key);
  if (log_struct != NULL) {
    g_object_get (log_struct,
                  "key",   &log_key,
                  "value", &log_value,
                  NULL);
    g_object_set (*_return,
                  "key",   log_key,
                  "value", g_strdup (log_value),
                  NULL);
  }

  return TRUE;
}

/* TutorialCalculatorHandler's instance finalizer (destructor) */
static void
tutorial_calculator_handler_finalize (GObject *object)
{
  TutorialCalculatorHandler *self =
    TUTORIAL_CALCULATOR_HANDLER (object);

  /* Free our calculation-log hash table */
  g_hash_table_unref (self->log);
  self->log = NULL;

  /* Chain up to the parent class */
  G_OBJECT_CLASS (tutorial_calculator_handler_parent_class)->
    finalize (object);
}

/* TutorialCalculatorHandler's instance initializer (constructor) */
static void
tutorial_calculator_handler_init (TutorialCalculatorHandler *self)
{
  /* Create our calculation-log hash table */
  self->log = g_hash_table_new_full (g_int_hash,
                                     g_int_equal,
                                     g_free,
                                     g_object_unref);
}

/* TutorialCalculatorHandler's class initializer */
static void
tutorial_calculator_handler_class_init (TutorialCalculatorHandlerClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  SharedServiceHandlerClass *shared_service_handler_class =
    SHARED_SERVICE_HANDLER_CLASS (klass);
  CalculatorHandlerClass *calculator_handler_class =
    CALCULATOR_HANDLER_CLASS (klass);

  /* Register our destructor */
  gobject_class->finalize = tutorial_calculator_handler_finalize;

  /* Register our implementations of CalculatorHandler's methods */
  calculator_handler_class->ping =
    tutorial_calculator_handler_ping;
  calculator_handler_class->add =
    tutorial_calculator_handler_add;
  calculator_handler_class->calculate =
    tutorial_calculator_handler_calculate;
  calculator_handler_class->zip =
    tutorial_calculator_handler_zip;

  /* Register our implementation of SharedServiceHandler's method */
  shared_service_handler_class->get_struct =
    tutorial_calculator_handler_get_struct;
}

/* ---------------------------------------------------------------- */

/* That ends the implementation of TutorialCalculatorHandler.
   Everything below is fairly generic code that sets up a minimal
   Thrift server for tutorial clients. */


/* Our server object, declared globally so it is accessible within the
   SIGINT signal handler */
ThriftServer *server = NULL;

/* A flag that indicates whether the server was interrupted with
   SIGINT (i.e. Ctrl-C) so we can tell whether its termination was
   abnormal */
gboolean sigint_received = FALSE;

/* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the
   server */
static void
sigint_handler (int signal_number)
{
  THRIFT_UNUSED_VAR (signal_number);

  /* Take note we were called */
  sigint_received = TRUE;

  /* Shut down the server gracefully */
  if (server != NULL)
    thrift_server_stop (server);
}

int main (void)
{
  TutorialCalculatorHandler *handler;
  CalculatorProcessor *processor;

  ThriftServerTransport *server_transport;
  ThriftTransportFactory *transport_factory;
  ThriftProtocolFactory *protocol_factory;

  struct sigaction sigint_action;

  GError *error = NULL;
  int exit_status = 0;

#if (!GLIB_CHECK_VERSION (2, 36, 0))
  g_type_init ();
#endif

  /* Create an instance of our handler, which provides the service's
     methods' implementation */
  handler =
    g_object_new (TYPE_TUTORIAL_CALCULATOR_HANDLER,
                  NULL);

  /* Create an instance of the service's processor, automatically
     generated by the Thrift compiler, which parses incoming messages
     and dispatches them to the appropriate method in the handler */
  processor =
    g_object_new (TYPE_CALCULATOR_PROCESSOR,
                  "handler", handler,
                  NULL);

  /* Create our server socket, which binds to the specified port and
     listens for client connections */
  server_transport =
    g_object_new (THRIFT_TYPE_SERVER_SOCKET,
                  "port", 9090,
                  NULL);

  /* Create our transport factory, used by the server to wrap "raw"
     incoming connections from the client (in this case with a
     ThriftBufferedTransport to improve performance) */
  transport_factory =
    g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,
                  NULL);

  /* Create our protocol factory, which determines which wire protocol
     the server will use (in this case, Thrift's binary protocol) */
  protocol_factory =
    g_object_new (THRIFT_TYPE_BINARY_PROTOCOL_FACTORY,
                  NULL);

  /* Create the server itself */
  server =
    g_object_new (THRIFT_TYPE_SIMPLE_SERVER,
                  "processor",                processor,
                  "server_transport",         server_transport,
                  "input_transport_factory",  transport_factory,
                  "output_transport_factory", transport_factory,
                  "input_protocol_factory",   protocol_factory,
                  "output_protocol_factory",  protocol_factory,
                  NULL);

  /* Install our SIGINT handler, which handles Ctrl-C being pressed by
     stopping the server gracefully (not strictly necessary, but a
     nice touch) */
  memset (&sigint_action, 0, sizeof (sigint_action));
  sigint_action.sa_handler = sigint_handler;
  sigint_action.sa_flags = SA_RESETHAND;
  sigaction (SIGINT, &sigint_action, NULL);

  /* Start the server, which will run until its stop method is invoked
     (from within the SIGINT handler, in this case) */
  puts ("Starting the server...");
  thrift_server_serve (server, &error);

  /* If the server stopped for any reason other than having been
     interrupted by the user, report the error */
  if (!sigint_received) {
    g_message ("thrift_server_serve: %s",
               error != NULL ? error->message : "(null)");
    g_clear_error (&error);
  }

  puts ("done.");

  g_object_unref (server);
  g_object_unref (transport_factory);
  g_object_unref (protocol_factory);
  g_object_unref (server_transport);

  g_object_unref (processor);
  g_object_unref (handler);

  return exit_status;
}
thrift-0.16.0/tutorial/cl/000077500000000000000000000000001420101504100153235ustar00rootroot00000000000000thrift-0.16.0/tutorial/cl/Makefile.am000077500000000000000000000041661420101504100173710ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

setup-local-lisp-env: ../../lib/cl/ensure-externals.sh
	bash ../../lib/cl/ensure-externals.sh

gen-cl: $(top_srcdir)/tutorial/tutorial.thrift
	$(THRIFT) --gen cl -r $<

ALL_FILE_PREREQS = \
		   load-locally.lisp \
		   make-tutorial-server.lisp \
		   make-tutorial-client.lisp \
		   shared-implementation.lisp \
		   thrift-tutorial.asd \
		   tutorial-implementation.lisp

# NOTE: the server and client cannot be built in parallel
# because on loading the make-tutorial-* scripts SBCL will
# attempt to compile their dependencies. Unfortunately,
# because their dependencies are shared, parallel jobs can
# end up overwriting or corrupting the compiled files
all-local: gen-cl setup-local-lisp-env $(ALL_FILE_PREREQS)
	@echo 'cl broken, commented out due to deprecation'
	## $(SBCL) --script make-tutorial-server.lisp
	## $(SBCL) --script make-tutorial-client.lisp

tutorialserver: all
	./TutorialServer

tutorialclient: all
	./TutorialClient

clean-local:
	-$(RM) -r gen-*
	-$(RM) -r externals
	-$(RM) -r quicklisp
	-$(RM) -r lib
	-$(RM) quicklisp.lisp
	-$(RM) backport-update.zip
	-$(RM) shared-implementation.fasl
	-$(RM) tutorial-implementation.fasl
	-$(RM) TutorialServer
	-$(RM) TutorialClient

EXTRA_DIST = \
	tutorial-implementation.lisp \
	shared-implementation.lisp \
	thrift-tutorial.asd \
	make-tutorial-server.lisp \
	make-tutorial-client.lisp \
	load-locally.lisp
thrift-0.16.0/tutorial/cl/load-locally.lisp000066400000000000000000000016601420101504100205730ustar00rootroot00000000000000(in-package #:cl-user)

;;;; 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.

;;;; Just a script for loading the library itself, using bundled dependencies.
;;;; This is an identical copy of the file in lib/cl.

(require "asdf")

(load (merge-pathnames "externals/bundle.lisp" *load-truename*))
(asdf:load-asd (merge-pathnames "lib/de.setf.thrift-backport-update/thrift.asd" *load-truename*))
(asdf:load-system :thrift)
thrift-0.16.0/tutorial/cl/make-tutorial-client.lisp000066400000000000000000000047321420101504100222540ustar00rootroot00000000000000(in-package #:cl-user)

;;;; 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.

(require "asdf")
(load (merge-pathnames "load-locally.lisp" *load-truename*))
(asdf:load-system :net.didierverna.clon)
(asdf:load-asd (merge-pathnames "gen-cl/shared/thrift-gen-shared.asd" *load-truename*))
(asdf:load-asd (merge-pathnames "gen-cl/tutorial/thrift-gen-tutorial.asd" *load-truename*))
(asdf:load-asd (merge-pathnames "thrift-tutorial.asd" *load-truename*))
(asdf:load-system :thrift-tutorial)

(net.didierverna.clon:nickname-package)

(defun main ()
  "Entry point for the binary."
  (thrift:with-client (prot #u"thrift://127.0.0.1:9090")
    (tutorial.calculator:ping prot)
    (format t "ping()~%")
    (format t "1 + 1 = ~a~%" (tutorial.calculator:add prot 1 1))
    (let ((work-instance (tutorial:make-work :num1 5
                                             :num2 0
                                             :op tutorial:operation.divide
                                             :comment "Booya!")))
      (handler-case (format t
                            "5 / 0 = ~a - Oh, really? An exception should have been thrown here.~%"
                            (tutorial.calculator:calculate prot 1 work-instance))
        (tutorial:invalidoperation (e)
          (format t "---~%(Expected) Invalid Operation caught: ~%~a~%---~%" e))))
    (let ((work-instance (tutorial:make-work :num1 15
                                             :num2 10
                                             :op tutorial:operation.subtract
                                             :comment "Playing nice this time.")))
      (handler-case (format t
                            "15 - 10 = ~a~%"
                            (tutorial.calculator:calculate prot 1 work-instance))
        (tutorial:invalidoperation (e)
          (format t "---~%(Unexpected) Invalid Operation caught: ~%~a~%---~%" e))))
    (format t "Check log: ~a~%" (shared.shared-service:get-struct prot 1))))

(clon:dump "TutorialClient" main)
thrift-0.16.0/tutorial/cl/make-tutorial-server.lisp000066400000000000000000000022571420101504100223040ustar00rootroot00000000000000(in-package #:cl-user)

;;;; 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.

(require "asdf")
(load (merge-pathnames "load-locally.lisp" *load-truename*))
(asdf:load-system :net.didierverna.clon)
(asdf:load-asd (merge-pathnames "gen-cl/shared/thrift-gen-shared.asd" *load-truename*))
(asdf:load-asd (merge-pathnames "gen-cl/tutorial/thrift-gen-tutorial.asd" *load-truename*))
(asdf:load-asd (merge-pathnames "thrift-tutorial.asd" *load-truename*))
(asdf:load-system :thrift-tutorial)

(net.didierverna.clon:nickname-package)

(defun main ()
  "Entry point for the binary."
  (thrift:serve #u"thrift://127.0.0.1:9090" tutorial:calculator))

(clon:dump "TutorialServer" main)
thrift-0.16.0/tutorial/cl/shared-implementation.lisp000066400000000000000000000017121420101504100225060ustar00rootroot00000000000000(in-package #:shared-implementation)

;;;; 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.

(defvar *structs* (make-hash-table))

(defun shared.shared-service-implementation:get-struct (key)
  (format t "getStruct(~a)~%" key)
  (gethash key *structs*))

(defun add-log (key value)
  (setf (gethash key *structs*)
        (make-instance 'shared:sharedstruct
                       :key key
                       :value (write-to-string value))))
thrift-0.16.0/tutorial/cl/thrift-tutorial.asd000066400000000000000000000013701420101504100211560ustar00rootroot00000000000000;;;; 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.

(asdf:defsystem #:thrift-tutorial
  :depends-on (#:thrift-gen-tutorial)
  :serial t
  :components ((:file "shared-implementation")
               (:file "tutorial-implementation")))
thrift-0.16.0/tutorial/cl/tutorial-implementation.lisp000066400000000000000000000032501420101504100231020ustar00rootroot00000000000000(in-package #:tutorial-implementation)

;;;; 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.

(defun tutorial.calculator-implementation:ping ()
  (format t "ping()~%"))

(defun tutorial.calculator-implementation:add (num1 num2)
  (format t "add(~a, ~a)~%" num1 num2)
  (+ num1 num2))

(defun tutorial.calculator-implementation:calculate (logid work)
  (format t "calculate(~a, ~a)~%" logid work)
  (handler-case
      (let* ((num1 (tutorial:work-num1 work))
             (num2 (tutorial:work-num2 work))
             (op (tutorial:work-op work))
             (result
              (cond
                ((= op tutorial:operation.add) (+ num1 num2))
                ((= op tutorial:operation.subtract) (- num1 num2))
                ((= op tutorial:operation.multiply) (* num1 num2))
                ((= op tutorial:operation.divide) (/ num1 num2)))))
        (shared-implementation::add-log logid result)
        result)
    (division-by-zero () (error 'tutorial:invalidoperation
                                :why "Division by zero."
                                :what-op (tutorial:work-op work)))))

(defun tutorial.calculator-implementation:zip ()
  (format t "zip()~%"))
thrift-0.16.0/tutorial/cpp/000077500000000000000000000000001420101504100155075ustar00rootroot00000000000000thrift-0.16.0/tutorial/cpp/CMakeLists.txt000066400000000000000000000040111420101504100202430ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

include(BoostMacros)
REQUIRE_BOOST_HEADERS()

#Make sure gen-cpp files can be included
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")

include(ThriftMacros)

set(tutorialgencpp_SOURCES
    gen-cpp/Calculator.cpp
    gen-cpp/SharedService.cpp
    gen-cpp/shared_types.cpp
    gen-cpp/tutorial_constants.cpp
    gen-cpp/tutorial_types.cpp
)
add_library(tutorialgencpp STATIC ${tutorialgencpp_SOURCES})
target_link_libraries(tutorialgencpp thrift)

add_custom_command(OUTPUT gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp
    COMMAND ${THRIFT_COMPILER} --gen cpp -r ${PROJECT_SOURCE_DIR}/tutorial/tutorial.thrift
)

add_executable(TutorialServer CppServer.cpp)
target_link_libraries(TutorialServer tutorialgencpp)
target_link_libraries(TutorialServer thrift)
if (ZLIB_FOUND)
  target_link_libraries(TutorialServer ${ZLIB_LIBRARIES})
endif ()

add_executable(TutorialClient CppClient.cpp)
target_link_libraries(TutorialClient tutorialgencpp)
target_link_libraries(TutorialClient thrift)
if (ZLIB_FOUND)
  target_link_libraries(TutorialClient ${ZLIB_LIBRARIES})
endif ()
thrift-0.16.0/tutorial/cpp/CppClient.cpp000066400000000000000000000046541420101504100201050ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include 

#include 
#include 
#include 

#include "../gen-cpp/Calculator.h"

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using namespace tutorial;
using namespace shared;

int main() {
  std::shared_ptr socket(new TSocket("localhost", 9090));
  std::shared_ptr transport(new TBufferedTransport(socket));
  std::shared_ptr protocol(new TBinaryProtocol(transport));
  CalculatorClient client(protocol);

  try {
    transport->open();

    client.ping();
    cout << "ping()" << endl;

    cout << "1 + 1 = " << client.add(1, 1) << endl;

    Work work;
    work.op = Operation::DIVIDE;
    work.num1 = 1;
    work.num2 = 0;

    try {
      client.calculate(1, work);
      cout << "Whoa? We can divide by zero!" << endl;
    } catch (InvalidOperation& io) {
      cout << "InvalidOperation: " << io.why << endl;
      // or using generated operator<<: cout << io << endl;
      // or by using std::exception native method what(): cout << io.what() << endl;
    }

    work.op = Operation::SUBTRACT;
    work.num1 = 15;
    work.num2 = 10;
    int32_t diff = client.calculate(1, work);
    cout << "15 - 10 = " << diff << endl;

    // Note that C++ uses return by reference for complex types to avoid
    // costly copy construction
    SharedStruct ss;
    client.getStruct(ss, 1);
    cout << "Received log: " << ss << endl;

    transport->close();
  } catch (TException& tx) {
    cout << "ERROR: " << tx.what() << endl;
  }
}
thrift-0.16.0/tutorial/cpp/CppServer.cpp000066400000000000000000000131471420101504100201320ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 

#include "../gen-cpp/Calculator.h"

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::concurrency;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;

using namespace tutorial;
using namespace shared;

class CalculatorHandler : public CalculatorIf {
public:
  CalculatorHandler() = default;

  void ping() override { cout << "ping()" << endl; }

  int32_t add(const int32_t n1, const int32_t n2) override {
    cout << "add(" << n1 << ", " << n2 << ")" << endl;
    return n1 + n2;
  }

  int32_t calculate(const int32_t logid, const Work& work) override {
    cout << "calculate(" << logid << ", " << work << ")" << endl;
    int32_t val;

    switch (work.op) {
    case Operation::ADD:
      val = work.num1 + work.num2;
      break;
    case Operation::SUBTRACT:
      val = work.num1 - work.num2;
      break;
    case Operation::MULTIPLY:
      val = work.num1 * work.num2;
      break;
    case Operation::DIVIDE:
      if (work.num2 == 0) {
        InvalidOperation io;
        io.whatOp = work.op;
        io.why = "Cannot divide by 0";
        throw io;
      }
      val = work.num1 / work.num2;
      break;
    default:
      InvalidOperation io;
      io.whatOp = work.op;
      io.why = "Invalid Operation";
      throw io;
    }

    SharedStruct ss;
    ss.key = logid;
    ss.value = to_string(val);

    log[logid] = ss;

    return val;
  }

  void getStruct(SharedStruct& ret, const int32_t logid) override {
    cout << "getStruct(" << logid << ")" << endl;
    ret = log[logid];
  }

  void zip() override { cout << "zip()" << endl; }

protected:
  map log;
};

/*
  CalculatorIfFactory is code generated.
  CalculatorCloneFactory is useful for getting access to the server side of the
  transport.  It is also useful for making per-connection state.  Without this
  CloneFactory, all connections will end up sharing the same handler instance.
*/
class CalculatorCloneFactory : virtual public CalculatorIfFactory {
 public:
  ~CalculatorCloneFactory() override = default;
  CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) override
  {
    std::shared_ptr sock = std::dynamic_pointer_cast(connInfo.transport);
    cout << "Incoming connection\n";
    cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
    cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
    cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
    cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
    return new CalculatorHandler;
  }
  void releaseHandler( ::shared::SharedServiceIf* handler) override {
    delete handler;
  }
};

int main() {
  TThreadedServer server(
    std::make_shared(std::make_shared()),
    std::make_shared(9090), //port
    std::make_shared(),
    std::make_shared());

  /*
  // if you don't need per-connection state, do the following instead
  TThreadedServer server(
    std::make_shared(std::make_shared()),
    std::make_shared(9090), //port
    std::make_shared(),
    std::make_shared());
  */

  /**
   * Here are some alternate server types...

  // This server only allows one connection at a time, but spawns no threads
  TSimpleServer server(
    std::make_shared(std::make_shared()),
    std::make_shared(9090),
    std::make_shared(),
    std::make_shared());

  const int workerCount = 4;

  std::shared_ptr threadManager =
    ThreadManager::newSimpleThreadManager(workerCount);
  threadManager->threadFactory(
    std::make_shared());
  threadManager->start();

  // This server allows "workerCount" connection at a time, and reuses threads
  TThreadPoolServer server(
    std::make_shared(std::make_shared()),
    std::make_shared(9090),
    std::make_shared(),
    std::make_shared(),
    threadManager);
  */

  cout << "Starting the server..." << endl;
  server.serve();
  cout << "Done." << endl;
  return 0;
}
thrift-0.16.0/tutorial/cpp/Makefile.am000077500000000000000000000044041420101504100175500ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
AUTOMAKE_OPTIONS = subdir-objects serial-tests nostdinc

BUILT_SOURCES = gen-cpp/shared_types.cpp \
                gen-cpp/tutorial_types.cpp

noinst_LTLIBRARIES = libtutorialgencpp.la
nodist_libtutorialgencpp_la_SOURCES = \
	gen-cpp/Calculator.cpp \
	gen-cpp/Calculator.h \
	gen-cpp/SharedService.cpp \
	gen-cpp/SharedService.h \
	gen-cpp/shared_types.cpp \
	gen-cpp/shared_types.h \
	gen-cpp/tutorial_constants.cpp \
	gen-cpp/tutorial_constants.h \
	gen-cpp/tutorial_types.cpp \
	gen-cpp/tutorial_types.h



libtutorialgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la

noinst_PROGRAMS = \
	TutorialServer \
	TutorialClient

TutorialServer_SOURCES = \
	CppServer.cpp

TutorialServer_LDADD = \
	libtutorialgencpp.la \
	$(top_builddir)/lib/cpp/libthrift.la

TutorialClient_SOURCES = \
	CppClient.cpp

TutorialClient_LDADD = \
	libtutorialgencpp.la \
	$(top_builddir)/lib/cpp/libthrift.la

#
# Common thrift code generation rules
#
gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp: $(top_srcdir)/tutorial/tutorial.thrift
	$(THRIFT) --gen cpp -r $<

AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp
AM_CXXFLAGS = -Wall -Wextra -pedantic
AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS)

clean-local:
	$(RM) gen-cpp/*

tutorialserver: all
	./TutorialServer

tutorialclient: all
	./TutorialClient

style-local:
	$(CPPSTYLE_CMD)

EXTRA_DIST = \
	CMakeLists.txt \
	CppClient.cpp \
	CppServer.cpp
thrift-0.16.0/tutorial/d/000077500000000000000000000000001420101504100151505ustar00rootroot00000000000000thrift-0.16.0/tutorial/d/Makefile.am000066400000000000000000000032611420101504100172060ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

LIB_D_DIR = $(top_srcdir)/lib/d

GEN_SRC = gen-d/share/SharedService.d gen-d/share/shared_types.d \
	gen-d/tutorial/tutorial_types.d gen-d/tutorial/Calculator.d

$(GEN_SRC): $(top_srcdir)/tutorial/tutorial.thrift
	$(top_builddir)/compiler/cpp/thrift --gen d -r $<

server: server.d $(GEN_SRC)
	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd server.d ${GEN_SRC}

client: client.d $(GEN_SRC)
	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd client.d ${GEN_SRC}

PROGS = server client

if WITH_D_EVENT_TESTS
async_client: async_client.d $(GEN_SRC)
	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd-event -L-lthriftd -L-levent async_client.d ${GEN_SRC}

PROGS += async_client
endif

all-local: $(PROGS)

clean:
	$(RM) -f $(PROGS)
	$(RM) -r gen-d/
	find . -type f -name '*.o' | xargs rm -f

dist-hook:
	$(RM) -f $(distdir)/$(PROGS)
	$(RM) -r $(distdir)/gen-d/
	find $(destdir) -type f -name '*.o' | xargs rm -f
thrift-0.16.0/tutorial/d/async_client.d000066400000000000000000000046541420101504100200010ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
module async_client;

import std.exception;
import std.stdio;
import thrift.async.libevent;
import thrift.async.socket;
import thrift.base;
import thrift.codegen.async_client;
import thrift.protocol.binary;
import thrift.transport.buffered;

import tutorial.Calculator;
import tutorial.tutorial_types;

void main() {
  auto asyncManager = new TLibeventAsyncManager;

  // If we are done, gracefully stop the async manager to avoid hanging on
  // appplication shutdown.
  scope (exit) asyncManager.stop();

  auto socket = new TAsyncSocket(asyncManager, "localhost", 9090);
  auto client = new TAsyncClient!Calculator(
    socket,
    new TBufferedTransportFactory,
    new TBinaryProtocolFactory!TBufferedTransport
  );

  socket.open();

  // Invoke all the methods.
  auto pingResult = client.ping();

  auto addResult = client.add(1, 1);

  auto work = Work();
  work.op = Operation.DIVIDE;
  work.num1 = 1;
  work.num2 = 0;
  auto quotientResult = client.calculate(1, work);

  work.op = Operation.SUBTRACT;
  work.num1 = 15;
  work.num2 = 10;
  auto diffResult = client.calculate(1, work);

  auto logResult = client.getStruct(1);

  // Await the responses.
  pingResult.waitGet();
  writeln("ping()");

  int sum = addResult.waitGet();
  writefln("1 + 1 = %s", sum);

  try {
    quotientResult.waitGet();
    writeln("Whoa we can divide by 0");
  } catch (InvalidOperation io) {
    writeln("Invalid operation: " ~ io.why);
  }

  writefln("15 - 10 = %s", diffResult.waitGet());

  // TFuture is implicitly convertible to the result type via »alias this«,
  // for which it (eagerly, of course) awaits completion.
  writefln("Check log: %s", logResult.value);
}
thrift-0.16.0/tutorial/d/client.d000066400000000000000000000035021420101504100165730ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
module client;

import std.stdio;
import thrift.base;
import thrift.codegen.client;
import thrift.protocol.binary;
import thrift.transport.buffered;
import thrift.transport.socket;

import tutorial.Calculator;
import tutorial.tutorial_types;

void main() {
  auto socket = new TSocket("localhost", 9090);
  auto transport = new TBufferedTransport(socket);
  auto protocol = tBinaryProtocol(transport);
  auto client = tClient!Calculator(protocol);

  transport.open();

  client.ping();
  writeln("ping()");

  int sum = client.add(1, 1);
  writefln("1 + 1 = %s", sum);

  auto work = Work();
  work.op = Operation.DIVIDE;
  work.num1 = 1;
  work.num2 = 0;
  try {
    int quotient = client.calculate(1, work);
    writeln("Whoa we can divide by 0");
  } catch (InvalidOperation io) {
    writeln("Invalid operation: " ~ io.why);
  }

  work.op = Operation.SUBTRACT;
  work.num1 = 15;
  work.num2 = 10;
  int diff = client.calculate(1, work);
  writefln("15 - 10 = %s", diff);

  auto log = client.getStruct(1);
  writefln("Check log: %s", log.value);
}
thrift-0.16.0/tutorial/d/server.d000066400000000000000000000056301420101504100166270ustar00rootroot00000000000000/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
module server;

import std.conv : to;
import std.stdio;
import thrift.codegen.processor;
import thrift.protocol.binary;
import thrift.server.simple;
import thrift.server.transport.socket;
import thrift.transport.buffered;

import share.SharedService;
import share.shared_types;
import tutorial.Calculator;
import tutorial.tutorial_types;

/**
 * The actual implementation of the Calculator interface that is called by
 * the server to answer the requests.
 */
class CalculatorHandler : Calculator {
  void ping() {
    writeln("ping()");
  }

  int add(int n1, int n2) {
    writefln("add(%s,%s)", n1, n2);
    return n1 + n2;
  }

  int calculate(int logid, ref const(Work) work) {
    writefln("calculate(%s, {%s, %s, %s})", logid, work.op, work.num1, work.num2);
    int val;

    switch (work.op) {
    case Operation.ADD:
      val = work.num1 + work.num2;
      break;
    case Operation.SUBTRACT:
      val = work.num1 - work.num2;
      break;
    case Operation.MULTIPLY:
      val = work.num1 * work.num2;
      break;
    case Operation.DIVIDE:
      if (work.num2 == 0) {
        auto io = new InvalidOperation();
        io.whatOp = work.op;
        io.why = "Cannot divide by 0";
        throw io;
      }
      val = work.num1 / work.num2;
      break;
    default:
      auto io = new InvalidOperation();
      io.whatOp = work.op;
      io.why = "Invalid Operation";
      throw io;
    }

    auto ss = SharedStruct();
    ss.key = logid;
    ss.value = to!string(val);
    log[logid] = ss;

    return val;
  }

  SharedStruct getStruct(int logid) {
    writefln("getStruct(%s)", logid);
    return log[logid];
  }

  void zip() {
    writeln("zip()");
  }

protected:
  SharedStruct[int] log;
}

void main() {
  auto protocolFactory = new TBinaryProtocolFactory!();
  auto processor = new TServiceProcessor!Calculator(new CalculatorHandler);
  auto serverTransport = new TServerSocket(9090);
  auto transportFactory = new TBufferedTransportFactory;

  auto server = new TSimpleServer(
    processor, serverTransport, transportFactory, protocolFactory);

  writeln("Starting the server on port 9090...");
  server.serve();
  writeln("done.");
}
thrift-0.16.0/tutorial/dart/000077500000000000000000000000001420101504100156575ustar00rootroot00000000000000thrift-0.16.0/tutorial/dart/Makefile.am000066400000000000000000000046661420101504100177270ustar00rootroot00000000000000#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

BUILT_SOURCES = gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart

gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart: $(top_srcdir)/tutorial/tutorial.thrift
	$(THRIFT) --gen dart -r $<

all-local: gen-dart/tutorial/lib/tutorial.dart pub-get

clean-local:
	$(RM) -r gen-*/
	find . -type d -name ".dart_tool" | xargs $(RM) -r
	find . -type d -name "packages" | xargs $(RM) -r
	find . -type f -name ".packages" | xargs $(RM)
	find . -type f -name "pubspec.lock" | xargs $(RM)

dist-hook:
	$(RM) -r $(distdir)/gen-*/
	find $(distdir) -type d -name ".dart_tool" | xargs $(RM) -r
	find $(distdir) -type d -name "packages" | xargs $(RM) -r
	find $(distdir) -type f -name ".packages" | xargs $(RM)
	find $(distdir) -type f -name "pubspec.lock" | xargs $(RM)

pub-get: pub-get-gen pub-get-client pub-get-console-client pub-get-server

pub-get-gen: pub-get-tutorial pub-get-shared

pub-get-tutorial: gen-dart/tutorial/lib/tutorial.dart
	cd gen-dart/tutorial; ${DARTPUB} get

pub-get-shared: gen-dart/shared/lib/shared.dart
	cd gen-dart/shared; ${DARTPUB} get

pub-get-client:
	cd client; ${DARTPUB} get

pub-get-console-client:
	cd console_client; ${DARTPUB} get

pub-get-server:
	cd server; ${DARTPUB} get

tutorialserver: pub-get-gen pub-get-server
	${DART} server/bin/main.dart

tutorialclient: pub-get-gen pub-get-client
	cd client; ${DARTPUB} serve

tutorialconsoleclient: pub-get-console-client
	${DART} console_client/bin/main.dart

EXTRA_DIST = \
	client/web/client.dart \
	client/web/index.html \
	client/web/styles.css \
	client/pubspec.yaml \
	console_client/bin/main.dart \
	console_client/pubspec.yaml \
	server/bin/main.dart \
	server/pubspec.yaml \
	build.sh
thrift-0.16.0/tutorial/dart/build.sh000066400000000000000000000026231420101504100173150ustar00rootroot00000000000000#!/bin/sh

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# 'License'); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

set -e;
rm -r gen-dart || true;

thrift --gen dart ../shared.thrift;
cd gen-dart/shared;
pub get;
cd ../..;

thrift --gen dart ../tutorial.thrift;
cd gen-dart/tutorial;
pub get;
cd ../..;

cd client;
pub get;
cd ..;

cd console_client;
pub get;
cd ..;

cd server;
pub get;
cd ..;

dartfmt -w gen-dart;

echo "\nEnjoy the Dart tutorial!";
echo "\nTo run the server:";
echo "> dart server/bin/main.dart";
echo "\nTo run the client:";
echo "# Serve the app from the client directory and view in a browser";
echo "> cd client;";
echo "> pub serve;";
echo "\nTo run the console client:";
echo "> dart console_client/bin/main.dart";
echo "";
thrift-0.16.0/tutorial/dart/client/000077500000000000000000000000001420101504100171355ustar00rootroot00000000000000thrift-0.16.0/tutorial/dart/client/pubspec.yaml000066400000000000000000000022041420101504100214600ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# 'License'); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

name: tutorial_client
version: 0.16.0
description: A Dart client implementation of the Apache Thrift tutorial
author: Apache Thrift Developers 
homepage: http://thrift.apache.org

environment:
  sdk: ">=1.13.0 <3.0.0"

dependencies:
  shared:
    path: ../gen-dart/shared
  thrift:
    path: ../../../lib/dart
  tutorial:
    path: ../gen-dart/tutorial
thrift-0.16.0/tutorial/dart/client/web/000077500000000000000000000000001420101504100177125ustar00rootroot00000000000000thrift-0.16.0/tutorial/dart/client/web/client.dart000066400000000000000000000200121420101504100220370ustar00rootroot00000000000000/// Licensed to the Apache Software Foundation (ASF) under one
/// or more contributor license agreements. See the NOTICE file
/// distributed with this work for additional information
/// regarding copyright ownership. The ASF licenses this file
/// to you under the Apache License, Version 2.0 (the
/// "License"); you may not use this file except in compliance
/// with the License. You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing,
/// software distributed under the License is distributed on an
/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
/// KIND, either express or implied. See the License for the
/// specific language governing permissions and limitations
/// under the License.

import 'dart:html';

import 'package:thrift/thrift.dart';
import 'package:thrift/thrift_browser.dart';
import 'package:shared/shared.dart';
import 'package:tutorial/tutorial.dart';

/// Adapted from the AS3 tutorial
void main() {
  new CalculatorUI(querySelector('#output')).start();
}

class CalculatorUI {
  final DivElement output;

  CalculatorUI(this.output);

  TTransport _transport;
  Calculator _calculatorClient;

  void start() {
    _buildInterface();
    _initConnection();
  }

  void _validate() {
    if (!_transport.isOpen) {
      window.alert("The transport is not open!");
    }
  }

  void _initConnection() {
    _transport = new TAsyncClientSocketTransport(
        new TWebSocket(Uri.parse('ws://127.0.0.1:9090/ws')),
        new TMessageReader(new TBinaryProtocolFactory()));
    TProtocol protocol = new TBinaryProtocol(_transport);
    _transport.open();

    _calculatorClient = new CalculatorClient(protocol);
  }

  void _buildInterface() {
    output.children.forEach((e) {
      e.remove();
    });

    _buildPingComponent();

    _buildAddComponent();

    _buildCalculatorComponent();

    _buildGetStructComponent();
  }

  void _buildPingComponent() {
    output.append(new HeadingElement.h3()..text = "Ping");
    ButtonElement pingButton = new ButtonElement()
      ..text = "PING"
      ..onClick.listen(_onPingClick);
    output.append(pingButton);
  }

  void _onPingClick(MouseEvent e) {
    _validate();

    _calculatorClient.ping();
  }

  void _buildAddComponent() {
    output.append(new HeadingElement.h3()..text = "Add");
    InputElement num1 = new InputElement()
      ..id = "add1"
      ..type = "number"
      ..style.fontSize = "14px"
      ..style.width = "50px";
    output.append(num1);
    SpanElement op = new SpanElement()
      ..text = "+"
      ..style.fontSize = "14px"
      ..style.marginLeft = "10px";
    output.append(op);
    InputElement num2 = new InputElement()
      ..id = "add2"
      ..type = "number"
      ..style.fontSize = "14px"
      ..style.width = "50px"
      ..style.marginLeft = "10px";
    output.append(num2);
    ButtonElement addButton = new ButtonElement()
      ..text = "="
      ..style.fontSize = "14px"
      ..style.marginLeft = "10px"
      ..onClick.listen(_onAddClick);
    output.append(addButton);
    SpanElement result = new SpanElement()
      ..id = "addResult"
      ..style.fontSize = "14px"
      ..style.marginLeft = "10px";
    output.append(result);
  }

  void _onAddClick(MouseEvent e) {
    _validate();

    InputElement num1 = querySelector("#add1");
    InputElement num2 = querySelector("#add2");
    SpanElement result = querySelector("#addResult");

    _calculatorClient
        .add(int.parse(num1.value), int.parse(num2.value))
        .then((int n) {
      result.text = "$n";
    });
  }

  void _buildCalculatorComponent() {
    output.append(new HeadingElement.h3()..text = "Calculator");
    InputElement num1 = new InputElement()
      ..id = "calc1"
      ..type = "number"
      ..style.fontSize = "14px"
      ..style.width = "50px";
    output.append(num1);
    SelectElement op = new SelectElement()
      ..id = "calcOp"
      ..multiple = false
      ..selectedIndex = 0
      ..style.fontSize = "16px"
      ..style.marginLeft = "10px"
      ..style.width = "50px";
    OptionElement addOp = new OptionElement()
      ..text = "+"
      ..value = Operation.ADD.toString();
    op.add(addOp, 0);
    OptionElement subtractOp = new OptionElement()
      ..text = "-"
      ..value = Operation.SUBTRACT.toString();
    op.add(subtractOp, 1);
    OptionElement multiplyOp = new OptionElement()
      ..text = "*"
      ..value = Operation.MULTIPLY.toString();
    op.add(multiplyOp, 2);
    OptionElement divideOp = new OptionElement()
      ..text = "/"
      ..value = Operation.DIVIDE.toString();
    op.add(divideOp, 3);
    output.append(op);
    InputElement num2 = new InputElement()
      ..id = "calc2"
      ..type = "number"
      ..style.fontSize = "14px"
      ..style.width = "50px"
      ..style.marginLeft = "10px";
    output.append(num2);
    ButtonElement calcButton = new ButtonElement()
      ..text = "="
      ..style.fontSize = "14px"
      ..style.marginLeft = "10px"
      ..onClick.listen(_onCalcClick);
    output.append(calcButton);
    SpanElement result = new SpanElement()
      ..id = "calcResult"
      ..style.fontSize = "14px"
      ..style.marginLeft = "10px";
    output.append(result);
    output.append(new BRElement());
    output.append(new BRElement());
    LabelElement logIdLabel = new LabelElement()
      ..text = "Log ID:"
      ..style.fontSize = "14px";
    output.append(logIdLabel);
    InputElement logId = new InputElement()
      ..id = "logId"
      ..type = "number"
      ..value = "1"
      ..style.fontSize = "14px"
      ..style.width = "50px"
      ..style.marginLeft = "10px";
    output.append(logId);
    LabelElement commentLabel = new LabelElement()
      ..text = "Comment:"
      ..style.fontSize = "14px"
      ..style.marginLeft = "10px";
    output.append(commentLabel);
    InputElement comment = new InputElement()
      ..id = "comment"
      ..style.fontSize = "14px"
      ..style.width = "100px"
      ..style.marginLeft = "10px";
    output.append(comment);
  }

  void _onCalcClick(MouseEvent e) {
    _validate();

    InputElement num1 = querySelector("#calc1");
    InputElement num2 = querySelector("#calc2");
    SelectElement op = querySelector("#calcOp");
    SpanElement result = querySelector("#calcResult");
    InputElement logId = querySelector("#logId");
    InputElement comment = querySelector("#comment");

    int logIdValue = int.parse(logId.value);
    logId.value = (logIdValue + 1).toString();

    Work work = new Work();
    work.num1 = int.parse(num1.value);
    work.num2 = int.parse(num2.value);
    work.op = int.parse(op.options[op.selectedIndex].value);
    work.comment = comment.value;

    _calculatorClient.calculate(logIdValue, work).then((int n) {
      result.text = "$n";
    });
  }

  void _buildGetStructComponent() {
    output.append(new HeadingElement.h3()..text = "Get Struct");
    LabelElement logIdLabel = new LabelElement()
      ..text = "Struct Key:"
      ..style.fontSize = "14px";
    output.append(logIdLabel);
    InputElement logId = new InputElement()
      ..id = "structKey"
      ..type = "number"
      ..value = "1"
      ..style.fontSize = "14px"
      ..style.width = "50px"
      ..style.marginLeft = "10px";
    output.append(logId);
    ButtonElement getStructButton = new ButtonElement()
      ..text = "GET"
      ..style.fontSize = "14px"
      ..style.marginLeft = "10px"
      ..onClick.listen(_onGetStructClick);
    output.append(getStructButton);
    output.append(new BRElement());
    output.append(new BRElement());
    TextAreaElement result = new TextAreaElement()
      ..id = "getStructResult"
      ..style.fontSize = "14px"
      ..style.width = "300px"
      ..style.height = "50px"
      ..style.marginLeft = "10px";
    output.append(result);
  }

  void _onGetStructClick(MouseEvent e) {
    _validate();

    InputElement structKey = querySelector("#structKey");
    TextAreaElement result = querySelector("#getStructResult");

    _calculatorClient
        .getStruct(int.parse(structKey.value))
        .then((SharedStruct s) {
      result.text = "${s.toString()}";
    });
  }
}
thrift-0.16.0/tutorial/dart/client/web/index.html000066400000000000000000000022401420101504100217050ustar00rootroot00000000000000



    
    
    
    Thrift Tutorial
    
  




  
thrift-0.16.0/tutorial/dart/client/web/styles.css000066400000000000000000000020561420101504100217520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ @import url(https://fonts.googleapis.com/css?family=Roboto); html, body { width: 100%; height: 100%; margin: 0; padding: 10px; font-family: 'Roboto', sans-serif; } h3 { border-bottom: solid; border-width: thin; padding-top: 20px; } thrift-0.16.0/tutorial/dart/console_client/000077500000000000000000000000001420101504100206575ustar00rootroot00000000000000thrift-0.16.0/tutorial/dart/console_client/bin/000077500000000000000000000000001420101504100214275ustar00rootroot00000000000000thrift-0.16.0/tutorial/dart/console_client/bin/main.dart000066400000000000000000000074111420101504100232320ustar00rootroot00000000000000/// Licensed to the Apache Software Foundation (ASF) under one /// or more contributor license agreements. See the NOTICE file /// distributed with this work for additional information /// regarding copyright ownership. The ASF licenses this file /// to you under the Apache License, Version 2.0 (the /// "License"); you may not use this file except in compliance /// with the License. You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, /// software distributed under the License is distributed on an /// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY /// KIND, either express or implied. See the License for the /// specific language governing permissions and limitations /// under the License. import 'dart:async'; import 'dart:io'; import 'package:args/args.dart'; import 'package:logging/logging.dart'; import 'package:thrift/thrift.dart'; import 'package:thrift/thrift_console.dart'; import 'package:tutorial/tutorial.dart'; TTransport _transport; Calculator _calculator; int logid = 0; const Map operationLookup = const { '+': Operation.ADD, '-': Operation.SUBTRACT, '*': Operation.MULTIPLY, '/': Operation.DIVIDE }; main(List args) { Logger.root.level = Level.ALL; Logger.root.onRecord.listen((LogRecord rec) { print('${rec.level.name}: ${rec.time}: ${rec.message}'); }); var parser = new ArgParser(); parser.addOption('port', defaultsTo: '9090', help: 'The port to connect to'); ArgResults results; try { results = parser.parse(args); } catch (e) { results = null; } if (results == null) { print(parser.usage); exit(0); } int port = int.parse(results['port']); _initConnection(port).then((_) => _run()); } Future _initConnection(int port) async { var socket = await Socket.connect('127.0.0.1', port); _transport = new TAsyncClientSocketTransport( new TTcpSocket(socket), new TMessageReader(new TBinaryProtocolFactory())); TProtocol protocol = new TBinaryProtocol(_transport); await _transport.open(); _calculator = new CalculatorClient(protocol); } Future _run() async { _help(); while (true) { stdout.write("> "); var input = stdin.readLineSync(); var parts = input.split(' '); var command = parts[0]; var args = parts.length > 1 ? parts.sublist(1) : []; switch (command) { case 'ping': await _ping(); break; case 'add': await _add(int.parse(args[0]), int.parse(args[1])); break; case 'calc': int op = operationLookup[args[1]]; if (!Operation.VALID_VALUES.contains(op)) { stdout.writeln('Unknown operator ${args[1]}'); break; } var work = new Work() ..num1 = int.parse(args[0]) ..op = op ..num2 = int.parse(args[2]) ..comment = args.length > 3 ? args[3] : ''; await _calc(work); break; case 'struct': await _struct(int.parse(args[0])); break; case 'help': default: _help(); break; } } } void _help() { stdout.writeln('Commands:'); stdout.writeln(' help'); stdout.writeln(' ping'); stdout.writeln(' add x y'); stdout.writeln(' calc x op y [comment]'); stdout.writeln(' struct id'); stdout.writeln(''); } Future _ping() async { await _calculator.ping(); stdout.writeln('ping succeeded'); } Future _add(int x, int y) async { int result = await _calculator.add(x, y); stdout.writeln('= $result'); } Future _calc(Work work) async { int result = await _calculator.calculate(logid++, work); stdout.writeln('= $result'); } Future _struct(int key) async { var struct = await _calculator.getStruct(key); stdout.writeln(struct.toString()); } thrift-0.16.0/tutorial/dart/console_client/pubspec.yaml000066400000000000000000000023121420101504100232020ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # 'License'); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. name: tutorial_console_client version: 0.16.0 description: > A Dart console client to implementation of the Apache Thrift tutorial author: Apache Thrift Developers homepage: http://thrift.apache.org environment: sdk: ">=1.13.0 <3.0.0" dependencies: args: ">=0.13.0 <2.0.0" collection: ^1.1.0 shared: path: ../gen-dart/shared thrift: path: ../../../lib/dart tutorial: path: ../gen-dart/tutorial thrift-0.16.0/tutorial/dart/server/000077500000000000000000000000001420101504100171655ustar00rootroot00000000000000thrift-0.16.0/tutorial/dart/server/bin/000077500000000000000000000000001420101504100177355ustar00rootroot00000000000000thrift-0.16.0/tutorial/dart/server/bin/main.dart000066400000000000000000000103571420101504100215430ustar00rootroot00000000000000/// Licensed to the Apache Software Foundation (ASF) under one /// or more contributor license agreements. See the NOTICE file /// distributed with this work for additional information /// regarding copyright ownership. The ASF licenses this file /// to you under the Apache License, Version 2.0 (the /// "License"); you may not use this file except in compliance /// with the License. You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, /// software distributed under the License is distributed on an /// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY /// KIND, either express or implied. See the License for the /// specific language governing permissions and limitations /// under the License. import 'dart:async'; import 'dart:io'; import 'package:args/args.dart'; import 'package:logging/logging.dart'; import 'package:thrift/thrift.dart'; import 'package:thrift/thrift_console.dart'; import 'package:tutorial/tutorial.dart'; import 'package:shared/shared.dart'; TProtocol _protocol; TProcessor _processor; WebSocket _webSocket; main(List args) { Logger.root.level = Level.ALL; Logger.root.onRecord.listen((LogRecord rec) { print('${rec.level.name}: ${rec.time}: ${rec.message}'); }); var parser = new ArgParser(); parser.addOption('port', defaultsTo: '9090', help: 'The port to listen on'); parser.addOption('type', defaultsTo: 'ws', allowed: ['ws', 'tcp'], help: 'The type of socket', allowedHelp: {'ws': 'WebSocket', 'tcp': 'TCP Socket'}); ArgResults results; try { results = parser.parse(args); } catch (e) { results = null; } if (results == null) { print(parser.usage); exit(0); } int port = int.parse(results['port']); String socketType = results['type']; if (socketType == 'tcp') { _runTcpServer(port); } else if (socketType == 'ws') { _runWebSocketServer(port); } } Future _runWebSocketServer(int port) async { var httpServer = await HttpServer.bind('127.0.0.1', port); print('listening for WebSocket connections on $port'); httpServer.listen((HttpRequest request) async { if (request.uri.path == '/ws') { _webSocket = await WebSocketTransformer.upgrade(request); await _initProcessor(new TWebSocket(_webSocket)); } else { print('Invalid path: ${request.uri.path}'); } }); } Future _runTcpServer(int port) async { var serverSocket = await ServerSocket.bind('127.0.0.1', port); print('listening for TCP connections on $port'); Socket socket = await serverSocket.first; await _initProcessor(new TTcpSocket(socket)); } Future _initProcessor(TSocket socket) async { TServerSocketTransport transport = new TServerSocketTransport(socket); transport.onIncomingMessage.listen(_processMessage); _processor = new CalculatorProcessor(new CalculatorServer()); _protocol = new TBinaryProtocol(transport); await _protocol.transport.open(); print('connected'); } Future _processMessage(_) async { _processor.process(_protocol, _protocol); } class CalculatorServer implements Calculator { final Map _log = {}; Future ping() async { print('ping()'); } Future add(int num1, int num2) async { print('add($num1, $num2)'); return num1 + num2; } Future calculate(int logid, Work work) async { print('calulate($logid, ${work.toString()})'); int val; switch (work.op) { case Operation.ADD: val = work.num1 + work.num2; break; case Operation.SUBTRACT: val = work.num1 - work.num2; break; case Operation.MULTIPLY: val = work.num1 * work.num2; break; case Operation.DIVIDE: if (work.num2 == 0) { var x = new InvalidOperation(); x.whatOp = work.op; x.why = 'Cannot divide by 0'; throw x; } val = (work.num1 / work.num2).floor(); break; } var log = new SharedStruct(); log.key = logid; log.value = '$val "${work.comment}"'; this._log[logid] = log; return val; } Future zip() async { print('zip()'); } Future getStruct(int key) async { print('getStruct($key)'); return _log[key]; } } thrift-0.16.0/tutorial/dart/server/pubspec.yaml000066400000000000000000000022271420101504100215150ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # 'License'); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. name: tutorial_server version: 0.16.0 description: A Dart server to support the Apache Thrift tutorial author: Apache Thrift Developers homepage: http://thrift.apache.org environment: sdk: ">=1.13.0 <3.0.0" dependencies: args: ">=0.13.0 <2.0.0" shared: path: ../gen-dart/shared thrift: path: ../../../lib/dart tutorial: path: ../gen-dart/tutorial thrift-0.16.0/tutorial/delphi/000077500000000000000000000000001420101504100161725ustar00rootroot00000000000000thrift-0.16.0/tutorial/delphi/DelphiClient/000077500000000000000000000000001420101504100205365ustar00rootroot00000000000000thrift-0.16.0/tutorial/delphi/DelphiClient/DelphiClient.dpr000066400000000000000000000066751420101504100236270ustar00rootroot00000000000000(* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *) program DelphiClient; {$APPTYPE CONSOLE} {$D 'Copyright (c) 2012 The Apache Software Foundation'} uses SysUtils, Generics.Collections, Thrift in '..\..\..\lib\delphi\src\Thrift.pas', Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas', Thrift.Configuration in '..\..\..\lib\delphi\src\Thrift.Configuration.pas', Thrift.Exception in '..\..\..\lib\delphi\src\Thrift.Exception.pas', Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas', Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas', Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas', Thrift.Server in '..\..\..\lib\delphi\src\Thrift.Server.pas', Thrift.Transport in '..\..\..\lib\delphi\src\Thrift.Transport.pas', Thrift.Transport.WinHTTP in '..\..\..\lib\delphi\src\Thrift.Transport.WinHTTP.pas', Thrift.Transport.MsxmlHTTP in '..\..\..\lib\delphi\src\Thrift.Transport.MsxmlHTTP.pas', Thrift.WinHTTP in '..\..\..\lib\delphi\src\Thrift.WinHTTP.pas', Shared in '..\gen-delphi\Shared.pas', Tutorial in '..\gen-delphi\Tutorial.pas'; type DelphiTutorialClient = class public class procedure Main; end; //--- DelphiTutorialClient --------------------------------------- class procedure DelphiTutorialClient.Main; var transport : ITransport; protocol : IProtocol; client : TCalculator.Iface; work : IWork; sum, quotient, diff : Integer; log : ISharedStruct; begin try transport := TSocketImpl.Create( 'localhost', 9090); protocol := TBinaryProtocolImpl.Create( transport); client := TCalculator.TClient.Create( protocol); transport.Open; client.ping; WriteLn('ping()'); sum := client.add( 1, 1); WriteLn( Format( '1+1=%d', [sum])); work := TWorkImpl.Create; work.Op := TOperation.DIVIDE; work.Num1 := 1; work.Num2 := 0; try quotient := client.calculate(1, work); WriteLn( 'Whoa we can divide by 0'); WriteLn( Format('1/0=%d',[quotient])); except on io: TInvalidOperation do WriteLn( 'Invalid operation: ' + io.Why); end; work.Op := TOperation.SUBTRACT; work.Num1 := 15; work.Num2 := 10; try diff := client.calculate( 1, work); WriteLn( Format('15-10=%d', [diff])); except on io: TInvalidOperation do WriteLn( 'Invalid operation: ' + io.Why); end; log := client.getStruct(1); WriteLn( Format( 'Check log: %s', [log.Value])); transport.Close(); except on e : Exception do WriteLn( e.ClassName+': '+e.Message); end; end; begin try DelphiTutorialClient.Main; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. thrift-0.16.0/tutorial/delphi/DelphiClient/DelphiClient.dproj000066400000000000000000000150551420101504100241500ustar00rootroot00000000000000 {2B8FB3A1-2F9E-4883-8C53-0F56220B34F6} DelphiClient.dpr 12.3 True Debug Win32 Console None DCC32 true true Base true true Base true ..\..\..\lib\delphi\src;$(DCC_UnitSearchPath) 00400000 .\dcu\$(Config)\$(Platform) WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;$(DCC_UnitAlias) ..\bin\$(Config)\$(Platform) false false false false false DEBUG;$(DCC_Define) false true false RELEASE;$(DCC_Define) 0 false MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 True False 0 12 0 0 False False False False False 1033 1252 Thrift Tutorial 0.16.0.0 DelphiClient Copyright © 2012 The Apache Software Foundation DelphiClient.exe Thrift 0.16.0.0 DelphiClient.dpr --transport framed --http http://example.org True 12 thrift-0.16.0/tutorial/delphi/DelphiServer/000077500000000000000000000000001420101504100205665ustar00rootroot00000000000000thrift-0.16.0/tutorial/delphi/DelphiServer/DelphiServer.dpr000066400000000000000000000112131420101504100236670ustar00rootroot00000000000000(* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *) program DelphiServer; {$APPTYPE CONSOLE} {$D 'Copyright (c) 2012 The Apache Software Foundation'} {$Q+} // throws exceptions on numeric overflows uses SysUtils, Generics.Collections, Thrift in '..\..\..\lib\delphi\src\Thrift.pas', Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas', Thrift.Configuration in '..\..\..\lib\delphi\src\Thrift.Configuration.pas', Thrift.Exception in '..\..\..\lib\delphi\src\Thrift.Exception.pas', Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas', Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas', Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas', Thrift.Server in '..\..\..\lib\delphi\src\Thrift.Server.pas', Thrift.Transport in '..\..\..\lib\delphi\src\Thrift.Transport.pas', Thrift.WinHTTP in '..\..\..\lib\delphi\src\Thrift.WinHTTP.pas', Shared in '..\gen-delphi\Shared.pas', Tutorial in '..\gen-delphi\Tutorial.pas'; type TCalculatorHandler = class( TInterfacedObject, TCalculator.Iface) protected FLog : TDictionary< Integer, ISharedStruct>; // TSharedService.Iface function getStruct(key: Integer): ISharedStruct; // TCalculator.Iface procedure ping(); function add(num1: Integer; num2: Integer): Integer; function calculate(logid: Integer; const w: IWork): Integer; procedure zip(); public constructor Create; destructor Destroy; override; end; DelphiTutorialServer = class public class procedure Main; end; //--- TCalculatorHandler --------------------------------------------------- constructor TCalculatorHandler.Create; begin inherited Create; FLog := TDictionary< Integer, ISharedStruct>.Create(); end; destructor TCalculatorHandler.Destroy; begin try FreeAndNil( FLog); finally inherited Destroy; end; end; procedure TCalculatorHandler.ping; begin WriteLn( 'ping()'); end; function TCalculatorHandler.add(num1: Integer; num2: Integer): Integer; begin WriteLn( Format( 'add( %d, %d)', [num1, num2])); result := num1 + num2; end; function TCalculatorHandler.calculate(logid: Integer; const w: IWork): Integer; var entry : ISharedStruct; begin try WriteLn( Format('calculate( %d, [%d,%d,%d])', [logid, Ord(w.Op), w.Num1, w.Num2])); case w.Op of TOperation.ADD : result := w.Num1 + w.Num2; TOperation.SUBTRACT : result := w.Num1 - w.Num2; TOperation.MULTIPLY : result := w.Num1 * w.Num2; TOperation.DIVIDE : result := Round( w.Num1 / w.Num2); else raise TInvalidOperation.Create( Ord(w.Op), 'Unknown operation'); end; except on e:Thrift.TException do raise; // let Thrift Exceptions pass through on e:Exception do raise TInvalidOperation.Create( Ord(w.Op), e.Message); // repackage all other end; entry := TSharedStructImpl.Create; entry.Key := logid; entry.Value := IntToStr( result); FLog.AddOrSetValue( logid, entry); end; function TCalculatorHandler.getStruct(key: Integer): ISharedStruct; begin WriteLn( Format( 'getStruct(%d)', [key])); result := FLog[key]; end; procedure TCalculatorHandler.zip; begin WriteLn( 'zip()'); end; //--- DelphiTutorialServer ---------------------------------------------------------------------- class procedure DelphiTutorialServer.Main; var handler : TCalculator.Iface; processor : IProcessor; transport : IServerTransport; server : IServer; begin try handler := TCalculatorHandler.Create; processor := TCalculator.TProcessorImpl.Create( handler); transport := TServerSocketImpl.Create( 9090); server := TSimpleServer.Create( processor, transport); WriteLn( 'Starting the server...'); server.Serve(); except on e: Exception do WriteLn( e.Message); end; WriteLn('done.'); end; begin try DelphiTutorialServer.Main; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. thrift-0.16.0/tutorial/delphi/DelphiServer/DelphiServer.dproj000066400000000000000000000142531420101504100242270ustar00rootroot00000000000000 {2B8FB3A1-2F9E-4883-8C53-0F56220B34F6} DelphiServer.dpr 12.3 True Debug Win32 Console None DCC32 true true Base true true Base true 00400000 .\dcu\$(Config)\$(Platform) WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;$(DCC_UnitAlias) ..\bin\$(Config)\$(Platform) false false false false false DEBUG;$(DCC_Define) false true false RELEASE;$(DCC_Define) 0 false MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 True False 0 12 0 0 False False False False False 1033 1252 Thrift Tutorial 0.16.0.0 DelphiServer Copyright © 2012 The Apache Software Foundation DelphiServer.exe Thrift 0.16.0.0 DelphiServer.dpr True 12 thrift-0.16.0/tutorial/delphi/Tutorial.groupproj000066400000000000000000000040011420101504100217410ustar00rootroot00000000000000 {3D042C7F-3EF2-4574-8304-AB7FB79F814C} Default.Personality.12 thrift-0.16.0/tutorial/erl/000077500000000000000000000000001420101504100155075ustar00rootroot00000000000000thrift-0.16.0/tutorial/erl/README.md000066400000000000000000000003171420101504100167670ustar00rootroot00000000000000To try things out, run % ./server.sh Erlang R14B (erts-5.8.1) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.8.1 (abort with ^G) > server:start(). > client:t(). thrift-0.16.0/tutorial/erl/client.erl000066400000000000000000000047331420101504100175000ustar00rootroot00000000000000%% %% Licensed to the Apache Software Foundation (ASF) under one %% or more contributor license agreements. See the NOTICE file %% distributed with this work for additional information %% regarding copyright ownership. The ASF licenses this file %% to you under the Apache License, Version 2.0 (the %% "License"); you may not use this file except in compliance %% with the License. You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, %% software distributed under the License is distributed on an %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. %% -module(client). -include("calculator_thrift.hrl"). -export([t/0]). p(X) -> io:format("~p~n", [X]), ok. t() -> Port = 9090, {ok, Client0} = thrift_client_util:new("127.0.0.1", Port, calculator_thrift, []), {Client1, {ok, ok}} = thrift_client:call(Client0, ping, []), io:format("ping~n", []), {Client2, {ok, Sum}} = thrift_client:call(Client1, add, [1, 1]), io:format("1+1=~p~n", [Sum]), {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]), io:format("1+4=~p~n", [Sum1]), Work = #'Work'{op=?TUTORIAL_OPERATION_SUBTRACT, num1=15, num2=10}, {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]), io:format("15-10=~p~n", [Diff]), {Client5, {ok, Log}} = thrift_client:call(Client4, getStruct, [1]), io:format("Log: ~p~n", [Log]), Client6 = try Work1 = #'Work'{op=?TUTORIAL_OPERATION_DIVIDE, num1=1, num2=0}, {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]), io:format("LAME: exception handling is broken~n", []), ClientS1 catch throw:{ClientS2, Z} -> io:format("Got exception where expecting - the " ++ "following is NOT a problem!!!~n"), p(Z), ClientS2 end, {Client7, {ok, ok}} = thrift_client:call(Client6, zip, []), io:format("zip~n", []), {_Client8, ok} = thrift_client:close(Client7), ok. thrift-0.16.0/tutorial/erl/client.sh000077500000000000000000000023341420101504100173260ustar00rootroot00000000000000#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ERL_THRIFT=../../lib/erl if ! [ -d ${ERL_THRIFT}/ebin ]; then echo "Please build the Thrift library by running \`make' in ${ERL_THRIFT}" exit 1 fi if ! [ -d gen-erl ]; then ../../compiler/cpp/thrift -r --gen erl ../tutorial.thrift fi erlc -I ${ERL_THRIFT}/include -I ${ERL_THRIFT}/ebin \ -I gen-erl -o gen-erl gen-erl/*.erl && erlc -I ${ERL_THRIFT}/include -I gen-erl *.erl && erl +K true -pa ${ERL_THRIFT}/ebin -pa gen-erl thrift-0.16.0/tutorial/erl/json_client.erl000066400000000000000000000061461420101504100205310ustar00rootroot00000000000000%% %% Licensed to the Apache Software Foundation (ASF) under one %% or more contributor license agreements. See the NOTICE file %% distributed with this work for additional information %% regarding copyright ownership. The ASF licenses this file %% to you under the Apache License, Version 2.0 (the %% "License"); you may not use this file except in compliance %% with the License. You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, %% software distributed under the License is distributed on an %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. %% %% The JSON protocol over HTTP implementation was created by %% Peter Neumark based on %% the binary protocol + socket tutorial. Use with the same server %% that the Javascript tutorial uses! -module(json_client). -include("calculator_thrift.hrl"). -export([t/0]). %% Client constructor for the http transports %% with the json protocol new_client(Host, Path, Service, _Options) -> {ProtoOpts, TransOpts} = {[],[]}, TransportFactory = fun() -> thrift_http_transport:new(Host, Path, TransOpts) end, {ok, ProtocolFactory} = thrift_json_protocol:new_protocol_factory( TransportFactory, ProtoOpts), {ok, Protocol} = ProtocolFactory(), thrift_client:new(Protocol, Service). p(X) -> io:format("~p~n", [X]), ok. t() -> inets:start(), {ok, Client0} = new_client("127.0.0.1:8088", "/thrift/service/tutorial/", calculator_thrift, []), {Client1, {ok, ok}} = thrift_client:call(Client0, ping, []), io:format("ping~n", []), {Client2, {ok, Sum}} = thrift_client:call(Client1, add, [1, 1]), io:format("1+1=~p~n", [Sum]), {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]), io:format("1+4=~p~n", [Sum1]), Work = #'Work'{op=?TUTORIAL_OPERATION_SUBTRACT, num1=15, num2=10}, {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]), io:format("15-10=~p~n", [Diff]), {Client5, {ok, Log}} = thrift_client:call(Client4, getStruct, [1]), io:format("Log: ~p~n", [Log]), Client6 = try Work1 = #'Work'{op=?TUTORIAL_OPERATION_DIVIDE, num1=1, num2=0}, {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]), io:format("LAME: exception handling is broken~n", []), ClientS1 catch throw:{ClientS2, Z} -> io:format("Got exception where expecting - the " ++ "following is NOT a problem!!!~n"), p(Z), ClientS2 end, {Client7, {ok, ok}} = thrift_client:call(Client6, zip, []), io:format("zip~n", []), {_Client8, ok} = thrift_client:close(Client7), ok. thrift-0.16.0/tutorial/erl/server.erl000066400000000000000000000046311420101504100175250ustar00rootroot00000000000000%% %% Licensed to the Apache Software Foundation (ASF) under one %% or more contributor license agreements. See the NOTICE file %% distributed with this work for additional information %% regarding copyright ownership. The ASF licenses this file %% to you under the Apache License, Version 2.0 (the %% "License"); you may not use this file except in compliance %% with the License. You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, %% software distributed under the License is distributed on an %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. %% -module(server). -include("calculator_thrift.hrl"). -export([start/0, start/1, handle_function/2, stop/1, ping/0, add/2, calculate/2, getStruct/1, zip/0]). debug(Format, Data) -> error_logger:info_msg(Format, Data). ping() -> debug("ping()",[]), ok. add(N1, N2) -> debug("add(~p,~p)",[N1,N2]), N1+N2. calculate(Logid, Work) -> { Op, Num1, Num2 } = { Work#'Work'.op, Work#'Work'.num1, Work#'Work'.num2 }, debug("calculate(~p, {~p,~p,~p})", [Logid, Op, Num1, Num2]), case Op of ?TUTORIAL_OPERATION_ADD -> Num1 + Num2; ?TUTORIAL_OPERATION_SUBTRACT -> Num1 - Num2; ?TUTORIAL_OPERATION_MULTIPLY -> Num1 * Num2; ?TUTORIAL_OPERATION_DIVIDE when Num2 == 0 -> throw(#'InvalidOperation'{whatOp=Op, why="Cannot divide by 0"}); ?TUTORIAL_OPERATION_DIVIDE -> Num1 div Num2; _Else -> throw(#'InvalidOperation'{whatOp=Op, why="Invalid operation"}) end. getStruct(Key) -> debug("getStruct(~p)", [Key]), #'SharedStruct'{key=Key, value="RARG"}. zip() -> debug("zip", []), ok. %% start() -> start(9090). start(Port) -> Handler = ?MODULE, thrift_socket_server:start([{handler, Handler}, {service, calculator_thrift}, {port, Port}, {name, tutorial_server}]). stop(Server) -> thrift_socket_server:stop(Server). handle_function(Function, Args) when is_atom(Function), is_tuple(Args) -> case apply(?MODULE, Function, tuple_to_list(Args)) of ok -> ok; Reply -> {reply, Reply} end. thrift-0.16.0/tutorial/erl/server.sh000077500000000000000000000023341420101504100173560ustar00rootroot00000000000000#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ERL_THRIFT=../../lib/erl if ! [ -d ${ERL_THRIFT}/ebin ]; then echo "Please build the Thrift library by running \`make' in ${ERL_THRIFT}" exit 1 fi if ! [ -d gen-erl ]; then ../../compiler/cpp/thrift -r --gen erl ../tutorial.thrift fi erlc -I ${ERL_THRIFT}/include -I ${ERL_THRIFT}/ebin \ -I gen-erl -o gen-erl gen-erl/*.erl && erlc -I ${ERL_THRIFT}/include -I gen-erl *.erl && erl +K true -pa ${ERL_THRIFT}/ebin -pa gen-erl thrift-0.16.0/tutorial/go/000077500000000000000000000000001420101504100153325ustar00rootroot00000000000000thrift-0.16.0/tutorial/go/Makefile.am000066400000000000000000000032571420101504100173750ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-go/tutorial/calculator.go gen-go/shared/shared_service.go: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen go:thrift_import=github.com/apache/thrift/lib/go/thrift,package_prefix=github.com/apache/thrift/tutorial/go/gen-go/$(COMPILER_EXTRAFLAG) -r $< all-local: gen-go/tutorial/calculator.go check: thirdparty-dep all $(GO) build -mod=mod -o go-tutorial ./src $(GO) build -mod=mod -o calculator-remote ./gen-go/tutorial/calculator-remote/calculator-remote.go thirdparty-dep: tutorialserver: all $(GO) run -mod=mod src/*.go -server=true tutorialclient: all $(GO) run -mod=mod src/*.go tutorialsecureserver: all $(GO) run -mod=mod src/*.go -server=true -secure=true tutorialsecureclient: all $(GO) run -mod=mod src/*.go -secure=true clean-local: $(RM) -r gen-* go-tutorial calculator-remote EXTRA_DIST = \ src/client.go \ src/handler.go \ src/server.go \ src/main.go \ server.crt \ server.key thrift-0.16.0/tutorial/go/server.crt000066400000000000000000000027611420101504100173600ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3 DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6 L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg 2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5 U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD 1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0 -----END CERTIFICATE----- thrift-0.16.0/tutorial/go/server.key000066400000000000000000000032501420101504100173520ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq 57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9 7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU 8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/ LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3 SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791 Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1 Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc rdPUV9/uQkdx8VrShxlD8A== -----END PRIVATE KEY----- thrift-0.16.0/tutorial/go/src/000077500000000000000000000000001420101504100161215ustar00rootroot00000000000000thrift-0.16.0/tutorial/go/src/client.go000066400000000000000000000054071420101504100177340ustar00rootroot00000000000000package main /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import ( "context" "fmt" "github.com/apache/thrift/lib/go/thrift" "github.com/apache/thrift/tutorial/go/gen-go/tutorial" ) var defaultCtx = context.Background() func handleClient(client *tutorial.CalculatorClient) (err error) { client.Ping(defaultCtx) fmt.Println("ping()") sum, _ := client.Add(defaultCtx, 1, 1) fmt.Print("1+1=", sum, "\n") work := tutorial.NewWork() work.Op = tutorial.Operation_DIVIDE work.Num1 = 1 work.Num2 = 0 quotient, err := client.Calculate(defaultCtx, 1, work) if err != nil { switch v := err.(type) { case *tutorial.InvalidOperation: fmt.Println("Invalid operation:", v) default: fmt.Println("Error during operation:", err) } } else { fmt.Println("Whoa we can divide by 0 with new value:", quotient) } work.Op = tutorial.Operation_SUBTRACT work.Num1 = 15 work.Num2 = 10 diff, err := client.Calculate(defaultCtx, 1, work) if err != nil { switch v := err.(type) { case *tutorial.InvalidOperation: fmt.Println("Invalid operation:", v) default: fmt.Println("Error during operation:", err) } return err } else { fmt.Print("15-10=", diff, "\n") } log, err := client.GetStruct(defaultCtx, 1) if err != nil { fmt.Println("Unable to get struct:", err) return err } else { fmt.Println("Check log:", log.Value) } return err } func runClient(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool, cfg *thrift.TConfiguration) error { var transport thrift.TTransport if secure { transport = thrift.NewTSSLSocketConf(addr, cfg) } else { transport = thrift.NewTSocketConf(addr, cfg) } transport, err := transportFactory.GetTransport(transport) if err != nil { return err } defer transport.Close() if err := transport.Open(); err != nil { return err } iprot := protocolFactory.GetProtocol(transport) oprot := protocolFactory.GetProtocol(transport) return handleClient(tutorial.NewCalculatorClient(thrift.NewTStandardClient(iprot, oprot))) } thrift-0.16.0/tutorial/go/src/handler.go000066400000000000000000000053741420101504100200760ustar00rootroot00000000000000package main /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import ( "context" "fmt" "strconv" "github.com/apache/thrift/tutorial/go/gen-go/shared" "github.com/apache/thrift/tutorial/go/gen-go/tutorial" ) type CalculatorHandler struct { log map[int]*shared.SharedStruct } func NewCalculatorHandler() *CalculatorHandler { return &CalculatorHandler{log: make(map[int]*shared.SharedStruct)} } func (p *CalculatorHandler) Ping(ctx context.Context) (err error) { fmt.Print("ping()\n") return nil } func (p *CalculatorHandler) Add(ctx context.Context, num1 int32, num2 int32) (retval17 int32, err error) { fmt.Print("add(", num1, ",", num2, ")\n") return num1 + num2, nil } func (p *CalculatorHandler) Calculate(ctx context.Context, logid int32, w *tutorial.Work) (val int32, err error) { fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n") switch w.Op { case tutorial.Operation_ADD: val = w.Num1 + w.Num2 case tutorial.Operation_SUBTRACT: val = w.Num1 - w.Num2 case tutorial.Operation_MULTIPLY: val = w.Num1 * w.Num2 case tutorial.Operation_DIVIDE: if w.Num2 == 0 { ouch := tutorial.NewInvalidOperation() ouch.WhatOp = int32(w.Op) ouch.Why = "Cannot divide by 0" err = ouch return } val = w.Num1 / w.Num2 default: ouch := tutorial.NewInvalidOperation() ouch.WhatOp = int32(w.Op) ouch.Why = "Unknown operation" err = ouch return } entry := shared.NewSharedStruct() entry.Key = logid entry.Value = strconv.Itoa(int(val)) k := int(logid) /* oldvalue, exists := p.log[k] if exists { fmt.Print("Replacing ", oldvalue, " with ", entry, " for key ", k, "\n") } else { fmt.Print("Adding ", entry, " for key ", k, "\n") } */ p.log[k] = entry return val, err } func (p *CalculatorHandler) GetStruct(ctx context.Context, key int32) (*shared.SharedStruct, error) { fmt.Print("getStruct(", key, ")\n") v := p.log[int(key)] return v, nil } func (p *CalculatorHandler) Zip(ctx context.Context) (err error) { fmt.Print("zip()\n") return nil } thrift-0.16.0/tutorial/go/src/main.go000066400000000000000000000051711420101504100174000ustar00rootroot00000000000000package main /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import ( "crypto/tls" "flag" "fmt" "os" "github.com/apache/thrift/lib/go/thrift" ) func Usage() { fmt.Fprint(os.Stderr, "Usage of ", os.Args[0], ":\n") flag.PrintDefaults() fmt.Fprint(os.Stderr, "\n") } func main() { flag.Usage = Usage server := flag.Bool("server", false, "Run server") protocol := flag.String("P", "binary", "Specify the protocol (binary, compact, json, simplejson)") framed := flag.Bool("framed", false, "Use framed transport") buffered := flag.Bool("buffered", false, "Use buffered transport") addr := flag.String("addr", "localhost:9090", "Address to listen to") secure := flag.Bool("secure", false, "Use tls secure transport") flag.Parse() var protocolFactory thrift.TProtocolFactory switch *protocol { case "compact": protocolFactory = thrift.NewTCompactProtocolFactoryConf(nil) case "simplejson": protocolFactory = thrift.NewTSimpleJSONProtocolFactoryConf(nil) case "json": protocolFactory = thrift.NewTJSONProtocolFactory() case "binary", "": protocolFactory = thrift.NewTBinaryProtocolFactoryConf(nil) default: fmt.Fprint(os.Stderr, "Invalid protocol specified", protocol, "\n") Usage() os.Exit(1) } var transportFactory thrift.TTransportFactory cfg := &thrift.TConfiguration{ TLSConfig: &tls.Config{ InsecureSkipVerify: true, }, } if *buffered { transportFactory = thrift.NewTBufferedTransportFactory(8192) } else { transportFactory = thrift.NewTTransportFactory() } if *framed { transportFactory = thrift.NewTFramedTransportFactoryConf(transportFactory, cfg) } if *server { if err := runServer(transportFactory, protocolFactory, *addr, *secure); err != nil { fmt.Println("error running server:", err) } } else { if err := runClient(transportFactory, protocolFactory, *addr, *secure, cfg); err != nil { fmt.Println("error running client:", err) } } } thrift-0.16.0/tutorial/go/src/server.go000066400000000000000000000033731420101504100177640ustar00rootroot00000000000000package main /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import ( "crypto/tls" "fmt" "github.com/apache/thrift/lib/go/thrift" "github.com/apache/thrift/tutorial/go/gen-go/tutorial" ) func runServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error { var transport thrift.TServerTransport var err error if secure { cfg := new(tls.Config) if cert, err := tls.LoadX509KeyPair("server.crt", "server.key"); err == nil { cfg.Certificates = append(cfg.Certificates, cert) } else { return err } transport, err = thrift.NewTSSLServerSocket(addr, cfg) } else { transport, err = thrift.NewTServerSocket(addr) } if err != nil { return err } fmt.Printf("%T\n", transport) handler := NewCalculatorHandler() processor := tutorial.NewCalculatorProcessor(handler) server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory) fmt.Println("Starting the simple server... on ", addr) return server.Serve() } thrift-0.16.0/tutorial/haxe/000077500000000000000000000000001420101504100156525ustar00rootroot00000000000000thrift-0.16.0/tutorial/haxe/Makefile.am000066400000000000000000000044221420101504100177100ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # BIN_CPP = bin/Main-debug BIN_PHP = bin/php/Main-debug.php BIN_PHP_WEB = bin/php-web-server/Main-debug.php gen-haxe/tutorial/calculator.hx gen-haxe/shared/shared_service.hx: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen haxe -r $< all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB) check: gen-haxe/tutorial/calculator.hx $(BIN_CPP): \ src/*.hx \ ../../lib/haxe/src/org/apache/thrift/**/*.hx \ gen-haxe/tutorial/calculator.hx $(HAXE) --cwd . cpp.hxml $(BIN_PHP): \ src/*.hx \ ../../lib/haxe/src/org/apache/thrift/**/*.hx \ gen-haxe/tutorial/calculator.hx $(HAXE) --cwd . php.hxml $(BIN_PHP_WEB): \ src/*.hx \ ../../lib/haxe/src/org/apache/thrift/**/*.hx \ gen-haxe/tutorial/calculator.hx $(HAXE) --cwd . php-web-server.hxml tutorialserver: all $(BIN_CPP) server tutorialserver_php: all php -f $(BIN_PHP) server tutorialclient: all $(BIN_CPP) tutorialclient_php: all php -f $(BIN_PHP) tutorialsecureserver: all $(BIN_CPP) server secure tutorialsecureserver_php: all php -f $(BIN_PHP) server secure tutorialsecureclient: all $(BIN_CPP) secure tutorialsecureclient_php: all php -f $(BIN_PHP) secure tutorialserver_php_http: all php -S 127.0.0.1:9090 router.php tutorialclient_http: all $(BIN_CPP) client http clean-local: $(RM) -r gen-haxe bin EXTRA_DIST = \ src \ cpp.hxml \ csharp.hxml \ flash.hxml \ java.hxml \ javascript.hxml \ php-web-server.hxml \ neko.hxml \ php.hxml \ python.hxml \ router.php \ project.hide \ Tutorial.hxproj \ make_all.bat \ make_all.sh thrift-0.16.0/tutorial/haxe/Tutorial.hxproj000066400000000000000000000037631420101504100207220ustar00rootroot00000000000000 thrift -r -gen haxe ../tutorial.thrift thrift-0.16.0/tutorial/haxe/cpp.hxml000066400000000000000000000023621420101504100173310ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #CPP target -cpp bin #To produce 64 bit binaries the file should define the HXCPP_M64 compile variable: #-D HXCPP_M64 #Add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce fullthrift-0.16.0/tutorial/haxe/csharp.hxml000066400000000000000000000022371420101504100200300ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #CSHARP target -cs bin/Tutorial.exe #Add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce fullthrift-0.16.0/tutorial/haxe/flash.hxml000066400000000000000000000023421420101504100176420ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #Flash target -swf bin/Tutorial.swf #Add debug information -debug # we need some goodies from sys.net # --macro allowPackage("sys") #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce fullthrift-0.16.0/tutorial/haxe/java.hxml000066400000000000000000000022401420101504100174630ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #Java target -java bin/Tutorial.jar #Add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce fullthrift-0.16.0/tutorial/haxe/javascript.hxml000066400000000000000000000027061420101504100207170ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #JavaScript target -js bin/Tutorial.js #You can use -D source-map-content (requires Haxe 3.1+) to have the .hx #files directly embedded into the map file, this way you only have to #upload it, and it will be always in sync with the compiled .js even if #you modify your .hx files. -D source-map-content #Generate source map and add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce fullthrift-0.16.0/tutorial/haxe/make_all.bat000066400000000000000000000035051420101504100201120ustar00rootroot00000000000000@echo off rem /* rem * Licensed to the Apache Software Foundation (ASF) under one rem * or more contributor license agreements. See the NOTICE file rem * distributed with this work for additional information rem * regarding copyright ownership. The ASF licenses this file rem * to you under the Apache License, Version 2.0 (the rem * "License"); you may not use this file except in compliance rem * with the License. You may obtain a copy of the License at rem * rem * http://www.apache.org/licenses/LICENSE-2.0 rem * rem * Unless required by applicable law or agreed to in writing, rem * software distributed under the License is distributed on an rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY rem * KIND, either express or implied. See the License for the rem * specific language governing permissions and limitations rem * under the License. rem */ setlocal if "%HOMEDRIVE%"=="" goto MISSINGVARS if "%HOMEPATH%"=="" goto MISSINGVARS if "%HAXEPATH%"=="" goto NOTINSTALLED set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path% rem # invoke Thrift comnpiler thrift -r -gen haxe ..\tutorial.thrift if errorlevel 1 goto STOP rem # invoke Haxe compiler for all targets for %%a in (*.hxml) do ( rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4) if not "%%a"=="python.hxml" ( echo -------------------------- echo Building %%a ... echo -------------------------- haxe --cwd . %%a ) ) echo. echo done. pause goto eof :NOTINSTALLED echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set. pause goto eof :MISSINGVARS echo FATAL: Unable to locate home folder. echo. echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder. echo The current values are: echo HOMEDRIVE=%HOMEDRIVE% echo HOMEPATH=%HOMEPATH% pause goto eof :STOP pause goto eof :eof thrift-0.16.0/tutorial/haxe/make_all.sh000066400000000000000000000022221420101504100177510ustar00rootroot00000000000000#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # invoke Thrift comnpiler thrift -r -gen haxe ../tutorial.thrift # output folder if [ ! -d bin ]; then mkdir bin fi # invoke Haxe compoiler for target in *.hxml; do echo -------------------------- echo Building ${target} ... echo -------------------------- if [ ! -d bin/${target} ]; then mkdir bin/${target} fi haxe --cwd . ${target} done #eof thrift-0.16.0/tutorial/haxe/neko.hxml000066400000000000000000000022351420101504100175020ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #neko target -neko bin/Tutorial.n #Add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce fullthrift-0.16.0/tutorial/haxe/php-web-server.hxml000066400000000000000000000023301420101504100214100ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #PHP target -php bin/php-web-server/ -D php-front=Main-debug.php #defines -D phpwebserver #Add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce full thrift-0.16.0/tutorial/haxe/php.hxml000066400000000000000000000022621420101504100173350ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #PHP target -php bin/php/ -D php-front=Main-debug.php #Add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce full thrift-0.16.0/tutorial/haxe/project.hide000066400000000000000000000052241420101504100201560ustar00rootroot00000000000000{ "type" : 0 ,"target" : 4 ,"name" : "Apache Thrift Tutorial" ,"main" : null ,"projectPackage" : "" ,"company" : "Apache Software Foundation (ASF)" ,"license" : "Apache License, Version 2.0" ,"url" : "http://www.apache.org/licenses/LICENSE-2.0" ,"targetData" : [ { "pathToHxml" : "flash.hxml" ,"runActionType" : 1 ,"runActionText" : "bin/Tutorial.swf" } ,{ "pathToHxml" : "javascript.hxml" ,"runActionType" : 1 ,"runActionText" : "bin\\index.html" } ,{ "pathToHxml" : "neko.hxml" ,"runActionType" : 2 ,"runActionText" : "neko bin/Tutorial.n" } ,{ "pathToHxml" : "php.hxml" } ,{ "pathToHxml" : "cpp.hxml" ,"runActionType" : 2 ,"runActionText" : "bin/Main-debug.exe" } ,{ "pathToHxml" : "java.hxml" } ,{ "pathToHxml" : "csharp.hxml" ,"runActionType" : 2 ,"runActionText" : "bin\\Tutorial.exe\\bin\\Main-Debug.exe" } ,{ "pathToHxml" : "python.hxml" ,"runActionType" : 2 ,"runActionText" : "python bin/Tutorial.py" } ] ,"files" : [ { "path" : "src\\org\\apache\\thrift\\server\\TServer.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] ,"activeLine" : 76 } ,{ "path" : "src\\org\\apache\\thrift\\server\\TSimpleServer.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] ,"activeLine" : 100 } ,{ "path" : "src\\shared\\SharedServiceProcessor.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] ,"activeLine" : 20 } ,{ "path" : "src\\tutorial\\CalculatorProcessor.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] ,"activeLine" : 79 } ,{ "path" : "src\\Main.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] ,"activeLine" : 0 } ] ,"activeFile" : "src\\Main.hx" ,"openFLTarget" : null ,"openFLBuildMode" : "Debug" ,"runActionType" : null ,"runActionText" : null ,"buildActionCommand" : null ,"hiddenItems" : [ ] ,"showHiddenItems" : false }thrift-0.16.0/tutorial/haxe/python.hxml000066400000000000000000000022421420101504100200650ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #integrate files to classpath -cp src -cp gen-haxe -cp ../../lib/haxe/src #this class wil be used as entry point for your app. -main Main #Python target -python bin/Tutorial.py #Add debug information -debug #dead code elimination : remove unused code #"-dce no" : do not remove unused code #"-dce std" : remove unused code in the std lib (default) #"-dce full" : remove all unused code -dce fullthrift-0.16.0/tutorial/haxe/router.php000066400000000000000000000017141420101504100177060ustar00rootroot00000000000000(); public function new() { } public function ping() : Void { trace("ping()"); } public function add( num1 : haxe.Int32, num2 : haxe.Int32) : haxe.Int32 { trace('add( $num1, $num2)'); return num1 + num2; } public function calculate( logid : haxe.Int32, work : Work) : haxe.Int32 { trace('calculate( $logid, '+work.op+","+work.num1+","+work.num2+")"); var val : haxe.Int32 = 0; switch (work.op) { case Operation.ADD: val = work.num1 + work.num2; case Operation.SUBTRACT: val = work.num1 - work.num2; case Operation.MULTIPLY: val = work.num1 * work.num2; case Operation.DIVIDE: if (work.num2 == 0) { var io = new InvalidOperation(); io.whatOp = work.op; io.why = "Cannot divide by 0"; throw io; } val = Std.int( work.num1 / work.num2); default: var io = new InvalidOperation(); io.whatOp = work.op; io.why = "Unknown operation"; throw io; } var entry = new SharedStruct(); entry.key = logid; entry.value = '$val'; log.set(logid, entry); return val; } public function getStruct( key : haxe.Int32) : SharedStruct { trace('getStruct($key)'); return log.get(key); } // oneway method, no args public function zip() : Void { trace("zip()"); } } thrift-0.16.0/tutorial/haxe/src/Main.hx000066400000000000000000000252541420101504100176760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package; import org.apache.thrift.*; import org.apache.thrift.protocol.*; import org.apache.thrift.transport.*; import org.apache.thrift.server.*; import org.apache.thrift.meta_data.*; import tutorial.*; import shared.*; enum Prot { binary; json; compact; } enum Trns { socket; http; } class Main { private static var server : Bool = false; private static var framed : Bool = false; private static var buffered : Bool = false; private static var prot : Prot = binary; private static var trns : Trns = socket; private static var targetHost : String = "localhost"; private static var targetPort : Int = 9090; static function main() { #if ! (flash || js || phpwebserver) try { ParseArgs(); } catch (e : String) { trace(e); trace(GetHelp()); return; } #elseif phpwebserver //forcing server server = true; trns = http; initPhpWebServer(); //check method if(php.Web.getMethod() != 'POST') { Sys.println('http endpoint for thrift test server'); return; } #end try { if (server) RunServer(); else RunClient(); } catch (e : String) { trace(e); } trace("Completed."); } #if phpwebserver private static function initPhpWebServer() { //remap trace to error log haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) { // handle trace var newValue : Dynamic; if (infos != null && infos.customParams!=null) { var extra:String = ""; for( v in infos.customParams ) extra += "," + v; newValue = v + extra; } else { newValue = v; } var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : ''; Sys.stderr().writeString('${msg}${newValue}\n'); } } #end #if ! (flash || js) private static function GetHelp() : String { return Sys.programPath+" modus layered transport protocol\n" +"Options:\n" +" modus: client, server (default: client)\n" +" layered: framed, buffered (default: none)\n" +" transport: socket, http (default: socket)\n" +" protocol: binary, json, compact (default: binary)\n" +"\n" +"All arguments are optional.\n"; } private static function ParseArgs() : Void { var step = 0; for (arg in Sys.args()) { // server|client switch(step) { case 0: ++step; if ( arg == "client") server = false; else if ( arg == "server") server = true; else throw "First argument must be 'server' or 'client'"; case 1: if ( arg == "framed") { framed = true; } else if ( arg == "buffered") { buffered = true; } else if ( arg == "socket") { trns = socket; ++step; } else if ( arg == "http") { trns = http; ++step; } else { throw "Unknown transport "+arg; } case 2: if ( arg == "binary") { prot = binary; ++step; } else if ( arg == "json") { prot = json; ++step; } else if ( arg == "compact") { prot = compact; ++step; } else { throw "Unknown protocol "+arg; } default: throw "Unexpected argument "+arg; } if ( framed && buffered) { trace("WN: framed supersedes buffered"); } } } #end private static function ClientSetup() : Calculator { trace("Client configuration:"); // endpoint transport var transport : TTransport; switch(trns) { case socket: trace('- socket transport $targetHost:$targetPort'); transport = new TSocket( targetHost, targetPort); case http: var uri = 'http://${targetHost}:${targetPort}'; trace('- HTTP transport $uri'); transport = new THttpClient(uri); default: throw "Unhandled transport"; } // optinal layered transport if ( framed) { trace("- framed transport"); transport = new TFramedTransport(transport); } else if ( buffered) { trace("- buffered transport"); transport = new TBufferedTransport(transport); } // protocol var protocol : TProtocol; switch(prot) { case binary: trace("- binary protocol"); protocol = new TBinaryProtocol( transport); case json: trace("- JSON protocol"); protocol = new TJSONProtocol( transport); case compact: trace("- compact protocol"); protocol = new TCompactProtocol( transport); default: throw "Unhandled protocol"; } // put everything together transport.open(); return new CalculatorImpl(protocol,protocol); } private static function RunClient() : Void { var client = ClientSetup(); try { client.ping(); trace("ping() successful"); } catch(error : TException) { trace('ping() failed: $error'); } catch(error : Dynamic) { trace('ping() failed: $error'); } try { var sum = client.add( 1, 1); trace('1+1=$sum'); } catch(error : TException) { trace('add() failed: $error'); } catch(error : Dynamic) { trace('add() failed: $error'); } var work = new tutorial.Work(); work.op = tutorial.Operation.DIVIDE; work.num1 = 1; work.num2 = 0; try { var quotient = client.calculate( 1, work); trace('Whoa we can divide by 0! Result = $quotient'); } catch(error : TException) { trace('calculate() failed: $error'); } catch(error : Dynamic) { trace('calculate() failed: $error'); } work.op = tutorial.Operation.SUBTRACT; work.num1 = 15; work.num2 = 10; try { var diff = client.calculate( 1, work); trace('15-10=$diff'); } catch(error : TException) { trace('calculate() failed: $error'); } catch(error : Dynamic) { trace('calculate() failed: $error'); } try { var log : SharedStruct = client.getStruct( 1); var logval = log.value; trace('Check log: $logval'); } catch(error : TException) { trace('getStruct() failed: $error'); } catch(error : Dynamic) { trace('getStruct() failed: $error'); } } private static function ServerSetup() : TServer { trace("Server configuration:"); // endpoint transport var transport : TServerTransport = null; switch(trns) { case socket: #if (flash || js) throw 'current platform does not support socket servers'; #else trace('- socket transport port $targetPort'); transport = new TServerSocket( targetPort); #end case http: #if !phpwebserver throw "HTTP server not implemented yet"; //trace("- http transport"); //transport = new THttpClient( targetHost); #else trace("- http transport"); transport = new TWrappingServerTransport( new TStreamTransport( new TFileStream("php://input", Read), new TFileStream("php://output", Append), null ) ); #end default: throw "Unhandled transport"; } // optional: layered transport var transfactory : TTransportFactory = null; if ( framed) { trace("- framed transport"); transfactory = new TFramedTransportFactory(); } else if ( buffered) { trace("- buffered transport"); transfactory = new TBufferedTransportFactory(); } // protocol var protfactory : TProtocolFactory = null; switch(prot) { case binary: trace("- binary protocol"); protfactory = new TBinaryProtocolFactory(); case json: trace("- JSON protocol"); protfactory = new TJSONProtocolFactory(); case compact: trace("- compact protocol"); protfactory = new TCompactProtocolFactory(); default: throw "Unhandled protocol"; } var handler : Calculator_service = new CalculatorHandler(); var processor = new CalculatorProcessor(handler); var server = new TSimpleServer( processor, transport, transfactory, protfactory); #if phpwebserver server.runOnce = true; #end return server; } private static function RunServer() : Void { try { var server = ServerSetup(); trace("\nStarting the server..."); server.Serve(); } catch( e : Dynamic) { trace('RunServer() failed: $e'); } trace("done."); } } thrift-0.16.0/tutorial/java/000077500000000000000000000000001420101504100156465ustar00rootroot00000000000000thrift-0.16.0/tutorial/java/Makefile.am000077500000000000000000000023351420101504100177100ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # export CLASSPATH # Make sure this doesn't fail if ant is not configured. clean-local: ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ $$ANT $(ANT_FLAGS) clean all-local: $(ANT) $(ANT_FLAGS) compile check-local: all $(ANT) $(ANT_FLAGS) test tutorial: all $(ANT) $(ANT_FLAGS) tutorial tutorialserver: all $(ANT) $(ANT_FLAGS) tutorialserver tutorialclient: all $(ANT) $(ANT_FLAGS) tutorialclient EXTRA_DIST = \ build.xml \ src \ README.md thrift-0.16.0/tutorial/java/README.md000066400000000000000000000007061420101504100171300ustar00rootroot00000000000000Thrift Java Tutorial ================================================== 1) Compile the Java library thrift/lib/java$ make or: thrift/lib/java$ ant 4) Run the tutorial: start server and client with one step: thrift/tutorial/java$ make tutorial or: thrift/tutorial/java$ make tutorialserver thrift/tutorial/java$ make tutorialclient or: thrift/tutorial/java$ ant tutorialserver thrift/tutorial/java$ ant tutorialclient thrift-0.16.0/tutorial/java/build.xml000066400000000000000000000076271420101504100175030ustar00rootroot00000000000000 Thrift Java Tutorial tutorial client simple: tutorial client secure: tutorial client simple: tutorial client secure: thrift-0.16.0/tutorial/java/src/000077500000000000000000000000001420101504100164355ustar00rootroot00000000000000thrift-0.16.0/tutorial/java/src/CalculatorHandler.java000066400000000000000000000046411420101504100226740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.thrift.TException; // Generated code import tutorial.*; import shared.*; import java.util.HashMap; public class CalculatorHandler implements Calculator.Iface { private HashMap log; public CalculatorHandler() { log = new HashMap(); } public void ping() { System.out.println("ping()"); } public int add(int n1, int n2) { System.out.println("add(" + n1 + "," + n2 + ")"); return n1 + n2; } public int calculate(int logid, Work work) throws InvalidOperation { System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})"); int val = 0; switch (work.op) { case ADD: val = work.num1 + work.num2; break; case SUBTRACT: val = work.num1 - work.num2; break; case MULTIPLY: val = work.num1 * work.num2; break; case DIVIDE: if (work.num2 == 0) { InvalidOperation io = new InvalidOperation(); io.whatOp = work.op.getValue(); io.why = "Cannot divide by 0"; throw io; } val = work.num1 / work.num2; break; default: InvalidOperation io = new InvalidOperation(); io.whatOp = work.op.getValue(); io.why = "Unknown operation"; throw io; } SharedStruct entry = new SharedStruct(); entry.key = logid; entry.value = Integer.toString(val); log.put(logid, entry); return val; } public SharedStruct getStruct(int key) { System.out.println("getStruct(" + key + ")"); return log.get(key); } public void zip() { System.out.println("zip()"); } } thrift-0.16.0/tutorial/java/src/JavaClient.java000066400000000000000000000066661420101504100213360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // Generated code import tutorial.*; import shared.*; import org.apache.thrift.TException; import org.apache.thrift.transport.TSSLTransportFactory; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; public class JavaClient { public static void main(String [] args) { if (args.length != 1) { System.out.println("Please enter 'simple' or 'secure'"); System.exit(0); } try { TTransport transport; if (args[0].contains("simple")) { transport = new TSocket("localhost", 9090); transport.open(); } else { /* * Similar to the server, you can use the parameters to setup client parameters or * use the default settings. On the client side, you will need a TrustStore which * contains the trusted certificate along with the public key. * For this example it's a self-signed cert. */ TSSLTransportParameters params = new TSSLTransportParameters(); params.setTrustStore("../../lib/java/test/.truststore", "thrift", "SunX509", "JKS"); /* * Get a client transport instead of a server transport. The connection is opened on * invocation of the factory method, no need to specifically call open() */ transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params); } TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); perform(client); transport.close(); } catch (TException x) { x.printStackTrace(); } } private static void perform(Calculator.Client client) throws TException { client.ping(); System.out.println("ping()"); int sum = client.add(1,1); System.out.println("1+1=" + sum); Work work = new Work(); work.op = Operation.DIVIDE; work.num1 = 1; work.num2 = 0; try { int quotient = client.calculate(1, work); System.out.println("Whoa we can divide by 0"); } catch (InvalidOperation io) { System.out.println("Invalid operation: " + io.why); } work.op = Operation.SUBTRACT; work.num1 = 15; work.num2 = 10; try { int diff = client.calculate(1, work); System.out.println("15-10=" + diff); } catch (InvalidOperation io) { System.out.println("Invalid operation: " + io.why); } SharedStruct log = client.getStruct(1); System.out.println("Check log: " + log.value); } } thrift-0.16.0/tutorial/java/src/JavaServer.java000066400000000000000000000076111420101504100213550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.thrift.server.TServer; import org.apache.thrift.server.TServer.Args; import org.apache.thrift.server.TSimpleServer; import org.apache.thrift.server.TThreadPoolServer; import org.apache.thrift.transport.TSSLTransportFactory; import org.apache.thrift.transport.TServerSocket; import org.apache.thrift.transport.TServerTransport; import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters; // Generated code import tutorial.*; import shared.*; import java.util.HashMap; public class JavaServer { public static CalculatorHandler handler; public static Calculator.Processor processor; public static void main(String [] args) { try { handler = new CalculatorHandler(); processor = new Calculator.Processor(handler); Runnable simple = new Runnable() { public void run() { simple(processor); } }; Runnable secure = new Runnable() { public void run() { secure(processor); } }; new Thread(simple).start(); new Thread(secure).start(); } catch (Exception x) { x.printStackTrace(); } } public static void simple(Calculator.Processor processor) { try { TServerTransport serverTransport = new TServerSocket(9090); TServer server = new TSimpleServer(new Args(serverTransport).processor(processor)); // Use this for a multithreaded server // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor)); System.out.println("Starting the simple server..."); server.serve(); } catch (Exception e) { e.printStackTrace(); } } public static void secure(Calculator.Processor processor) { try { /* * Use TSSLTransportParameters to setup the required SSL parameters. In this example * we are setting the keystore and the keystore password. Other things like algorithms, * cipher suites, client auth etc can be set. */ TSSLTransportParameters params = new TSSLTransportParameters(); // The Keystore contains the private key params.setKeyStore("../../lib/java/test/.keystore", "thrift", null, null); /* * Use any of the TSSLTransportFactory to get a server transport with the appropriate * SSL configuration. You can use the default settings if properties are set in the command line. * Ex: -Djavax.net.ssl.keyStore=.keystore and -Djavax.net.ssl.keyStorePassword=thrift * * Note: You need not explicitly call open(). The underlying server socket is bound on return * from the factory class. */ TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(9091, 0, null, params); TServer server = new TSimpleServer(new Args(serverTransport).processor(processor)); // Use this for a multi threaded server // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor)); System.out.println("Starting the secure server..."); server.serve(); } catch (Exception e) { e.printStackTrace(); } } } thrift-0.16.0/tutorial/js/000077500000000000000000000000001420101504100153415ustar00rootroot00000000000000thrift-0.16.0/tutorial/js/Makefile.am000077500000000000000000000021731420101504100174030ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # export CLASSPATH # Make sure this doesn't fail if ant is not configured. clean-local: ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \ $$ANT $(ANT_FLAGS) clean all-local: $(ANT) $(ANT_FLAGS) compile check-local: all $(ANT) $(ANT_FLAGS) test tutorialserver: all $(ANT) $(ANT_FLAGS) tutorialserver EXTRA_DIST = \ build.xml \ src \ tutorial.html thrift-0.16.0/tutorial/js/build.xml000066400000000000000000000064161420101504100171710ustar00rootroot00000000000000 Thrift JavaScript Tutorial thrift-0.16.0/tutorial/js/src/000077500000000000000000000000001420101504100161305ustar00rootroot00000000000000thrift-0.16.0/tutorial/js/src/Httpd.java000066400000000000000000000303011420101504100200530ustar00rootroot00000000000000/* * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.URLDecoder; import java.util.Locale; import org.apache.http.ConnectionClosedException; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpServerConnection; import org.apache.http.HttpStatus; import org.apache.http.MethodNotSupportedException; import org.apache.http.entity.ContentProducer; import org.apache.http.entity.EntityTemplate; import org.apache.http.entity.FileEntity; import org.apache.http.impl.DefaultHttpResponseFactory; import org.apache.http.impl.DefaultHttpServerConnection; import org.apache.http.impl.NoConnectionReuseStrategy; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.BasicHttpProcessor; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpProcessor; import org.apache.http.protocol.HttpRequestHandler; import org.apache.http.protocol.HttpRequestHandlerRegistry; import org.apache.http.protocol.HttpService; import org.apache.http.util.EntityUtils; import org.apache.thrift.TProcessor; import org.apache.thrift.protocol.TJSONProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TMemoryBuffer; // Generated code import tutorial.*; import shared.*; import java.util.HashMap; /** * Basic, yet fully functional and spec compliant, HTTP/1.1 file server. *

* Please note the purpose of this application is demonstrate the usage of * HttpCore APIs. It is NOT intended to demonstrate the most efficient way of * building an HTTP file server. * * */ public class Httpd { public static void main(String[] args) throws Exception { if (args.length < 1) { System.err.println("Please specify document root directory"); System.exit(1); } Thread t = new RequestListenerThread(8088, args[0]); t.setDaemon(false); t.start(); } static class HttpFileHandler implements HttpRequestHandler { private final String docRoot; public HttpFileHandler(final String docRoot) { super(); this.docRoot = docRoot; } public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException { String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH); if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) { throw new MethodNotSupportedException(method + " method not supported"); } String target = request.getRequestLine().getUri(); if (request instanceof HttpEntityEnclosingRequest && target.equals("/thrift/service/tutorial/")) { HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); byte[] entityContent = EntityUtils.toByteArray(entity); System.out.println("Incoming content: " + new String(entityContent)); final String output = this.thriftRequest(entityContent); System.out.println("Outgoing content: "+output); EntityTemplate body = new EntityTemplate(new ContentProducer() { public void writeTo(final OutputStream outstream) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); writer.write(output); writer.flush(); } }); body.setContentType("text/html; charset=UTF-8"); response.setEntity(body); } else { final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8")); if (!file.exists()) { response.setStatusCode(HttpStatus.SC_NOT_FOUND); EntityTemplate body = new EntityTemplate(new ContentProducer() { public void writeTo(final OutputStream outstream) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); writer.write("

"); writer.write("File "); writer.write(file.getPath()); writer.write(" not found"); writer.write("

"); writer.flush(); } }); body.setContentType("text/html; charset=UTF-8"); response.setEntity(body); System.out.println("File " + file.getPath() + " not found"); } else if (!file.canRead() || file.isDirectory()) { response.setStatusCode(HttpStatus.SC_FORBIDDEN); EntityTemplate body = new EntityTemplate(new ContentProducer() { public void writeTo(final OutputStream outstream) throws IOException { OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8"); writer.write("

"); writer.write("Access denied"); writer.write("

"); writer.flush(); } }); body.setContentType("text/html; charset=UTF-8"); response.setEntity(body); System.out.println("Cannot read file " + file.getPath()); } else { response.setStatusCode(HttpStatus.SC_OK); FileEntity body = new FileEntity(file, "text/html"); response.setEntity(body); System.out.println("Serving file " + file.getPath()); } } } private String thriftRequest(byte[] input){ try{ //Input TMemoryBuffer inbuffer = new TMemoryBuffer(input.length); inbuffer.write(input); TProtocol inprotocol = new TJSONProtocol(inbuffer); //Output TMemoryBuffer outbuffer = new TMemoryBuffer(100); TProtocol outprotocol = new TJSONProtocol(outbuffer); TProcessor processor = new Calculator.Processor(new CalculatorHandler()); processor.process(inprotocol, outprotocol); byte[] output = new byte[outbuffer.length()]; outbuffer.readAll(output, 0, output.length); return new String(output,"UTF-8"); }catch(Throwable t){ return "Error:"+t.getMessage(); } } } static class RequestListenerThread extends Thread { private final ServerSocket serversocket; private final HttpParams params; private final HttpService httpService; public RequestListenerThread(int port, final String docroot) throws IOException { this.serversocket = new ServerSocket(port); this.params = new BasicHttpParams(); this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 1000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); // Set up the HTTP protocol processor HttpProcessor httpproc = new BasicHttpProcessor(); // Set up request handlers HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); reqistry.register("*", new HttpFileHandler(docroot)); // Set up the HTTP service this.httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory()); this.httpService.setParams(this.params); this.httpService.setHandlerResolver(reqistry); } public void run() { System.out.println("Listening on port " + this.serversocket.getLocalPort()); System.out.println("Point your browser to http://localhost:8088/tutorial/js/tutorial.html"); while (!Thread.interrupted()) { try { // Set up HTTP connection Socket socket = this.serversocket.accept(); DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); System.out.println("Incoming connection from " + socket.getInetAddress()); conn.bind(socket, this.params); // Start worker thread Thread t = new WorkerThread(this.httpService, conn); t.setDaemon(true); t.start(); } catch (InterruptedIOException ex) { break; } catch (IOException e) { System.err.println("I/O error initialising connection thread: " + e.getMessage()); break; } } } } static class WorkerThread extends Thread { private final HttpService httpservice; private final HttpServerConnection conn; public WorkerThread(final HttpService httpservice, final HttpServerConnection conn) { super(); this.httpservice = httpservice; this.conn = conn; } public void run() { System.out.println("New connection thread"); HttpContext context = new BasicHttpContext(null); try { while (!Thread.interrupted() && this.conn.isOpen()) { this.httpservice.handleRequest(this.conn, context); } } catch (ConnectionClosedException ex) { System.err.println("Client closed connection"); } catch (IOException ex) { System.err.println("I/O error: " + ex.getMessage()); } catch (HttpException ex) { System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage()); } finally { try { this.conn.shutdown(); } catch (IOException ignore) { } } } } } thrift-0.16.0/tutorial/js/tutorial.html000077500000000000000000000075631420101504100201100ustar00rootroot00000000000000 Thrift Javascript Bindings - Tutorial Example

Thrift Javascript Bindings

num1
Operation
num2
result
autoupdate

This Java Script example uses tutorial.thrift and a Thrift server using JSON protocol and HTTP transport.

Valid XHTML 1.0!

thrift-0.16.0/tutorial/netstd/000077500000000000000000000000001420101504100162265ustar00rootroot00000000000000thrift-0.16.0/tutorial/netstd/Client/000077500000000000000000000000001420101504100174445ustar00rootroot00000000000000thrift-0.16.0/tutorial/netstd/Client/Client.csproj000066400000000000000000000033321420101504100221050ustar00rootroot00000000000000 net6.0 9.0 Client Client Exe 0.16.0.0 false false false false thrift-0.16.0/tutorial/netstd/Client/Program.cs000066400000000000000000000337021420101504100214070ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; using Thrift; using Thrift.Protocol; using Thrift.Transport; using Thrift.Transport.Client; using tutorial; using shared; #pragma warning disable IDE0063 // using #pragma warning disable IDE0057 // substr namespace Client { public static class LoggingHelper { public static ILoggerFactory LogFactory { get; } = LoggerFactory.Create(builder => { ConfigureLogging(builder); }); public static void ConfigureLogging(ILoggingBuilder logging) { logging.SetMinimumLevel(LogLevel.Trace); logging.AddConsole(); logging.AddDebug(); } public static ILogger CreateLogger() => LogFactory.CreateLogger(); } public class Program { private static readonly ILogger Logger = LoggingHelper.CreateLogger(); private static readonly TConfiguration Configuration = null; // new TConfiguration() if needed private static void DisplayHelp() { Logger.LogInformation(@" Usage: Client -help will diplay help information Client -tr: -bf: -pr: [-mc:] [-multiplex] will run client with specified arguments (tcp transport and binary protocol by default) and with 1 client Options: -tr (transport): tcp - (default) tcp transport (localhost:9090) tcptls - tcp tls transport (localhost:9090) namedpipe - namedpipe transport (pipe "".test"") http - http transport (http://localhost:9090) -bf (buffering): none - (default) no buffering buffered - buffered transport framed - framed transport -pr (protocol): binary - (default) binary protocol compact - compact protocol json - json protocol -multiplex - adds multiplexed protocol -mc (multiple clients): - number of multiple clients to connect to server (max 100, default 1) Sample: Client -tr:tcp -pr:binary "); } public static void Main(string[] args) { args ??= Array.Empty(); if (args.Any(x => x.StartsWith("-help", StringComparison.OrdinalIgnoreCase))) { DisplayHelp(); return; } Logger.LogInformation("Starting client..."); using (var source = new CancellationTokenSource()) { RunAsync(args, source.Token).GetAwaiter().GetResult(); } } private static async Task RunAsync(string[] args, CancellationToken cancellationToken) { var numClients = GetNumberOfClients(args); Logger.LogInformation("Selected # of clients: {numClients}", numClients); var transport = GetTransport(args); Logger.LogInformation("Selected client transport: {transport}", transport); var protocol = MakeProtocol( args, MakeTransport(args)); Logger.LogInformation("Selected client protocol: {GetProtocol(args)}", GetProtocol(args)); var mplex = GetMultiplex(args); Logger.LogInformation("Multiplex {mplex}", mplex); var tasks = new Task[numClients]; for (int i = 0; i < numClients; i++) { var task = RunClientAsync(protocol, mplex, cancellationToken); tasks[i] = task; } Task.WaitAll(tasks,cancellationToken); await Task.CompletedTask; } private static bool GetMultiplex(string[] args) { var mplex = args.FirstOrDefault(x => x.StartsWith("-multiplex")); return !string.IsNullOrEmpty(mplex); } private static Protocol GetProtocol(string[] args) { var protocol = args.FirstOrDefault(x => x.StartsWith("-pr"))?.Split(':')?[1]; if (string.IsNullOrEmpty(protocol)) return Protocol.Binary; protocol = protocol.Substring(0, 1).ToUpperInvariant() + protocol.Substring(1).ToLowerInvariant(); if (Enum.TryParse(protocol, true, out Protocol selectedProtocol)) return selectedProtocol; else return Protocol.Binary; } private static Buffering GetBuffering(string[] args) { var buffering = args.FirstOrDefault(x => x.StartsWith("-bf"))?.Split(":")?[1]; if (string.IsNullOrEmpty(buffering)) return Buffering.None; buffering = buffering.Substring(0, 1).ToUpperInvariant() + buffering.Substring(1).ToLowerInvariant(); if (Enum.TryParse(buffering, out var selectedBuffering)) return selectedBuffering; else return Buffering.None; } private static Transport GetTransport(string[] args) { var transport = args.FirstOrDefault(x => x.StartsWith("-tr"))?.Split(':')?[1]; if (string.IsNullOrEmpty(transport)) return Transport.Tcp; transport = transport.Substring(0, 1).ToUpperInvariant() + transport.Substring(1).ToLowerInvariant(); if (Enum.TryParse(transport, true, out Transport selectedTransport)) return selectedTransport; else return Transport.Tcp; } private static TTransport MakeTransport(string[] args) { // construct endpoint transport TTransport transport = null; Transport selectedTransport = GetTransport(args); { switch (selectedTransport) { case Transport.Tcp: transport = new TSocketTransport(IPAddress.Loopback, 9090, Configuration); break; case Transport.NamedPipe: transport = new TNamedPipeTransport(".test", Configuration); break; case Transport.Http: transport = new THttpTransport(new Uri("http://localhost:9090"), Configuration); break; case Transport.TcpTls: transport = new TTlsSocketTransport(IPAddress.Loopback, 9090, Configuration, GetCertificate(), CertValidator, LocalCertificateSelectionCallback); break; default: Debug.Assert(false, "unhandled case"); break; } } // optionally add layered transport(s) Buffering selectedBuffering = GetBuffering(args); switch (selectedBuffering) { case Buffering.Buffered: transport = new TBufferedTransport(transport); break; case Buffering.Framed: transport = new TFramedTransport(transport); break; default: // layered transport(s) are optional Debug.Assert(selectedBuffering == Buffering.None, "unhandled case"); break; } return transport; } private static int GetNumberOfClients(string[] args) { var numClients = args.FirstOrDefault(x => x.StartsWith("-mc"))?.Split(':')?[1]; Logger.LogInformation("Selected # of clients: {numClients}", numClients); if (int.TryParse(numClients, out int c) && (0 < c) && (c <= 100)) return c; else return 1; } private static X509Certificate2 GetCertificate() { // due to files location in net core better to take certs from top folder var certFile = GetCertPath(Directory.GetParent(Directory.GetCurrentDirectory())); return new X509Certificate2(certFile, "ThriftTest"); } private static string GetCertPath(DirectoryInfo di, int maxCount = 6) { var topDir = di; var certFile = topDir.EnumerateFiles("ThriftTest.pfx", SearchOption.AllDirectories) .FirstOrDefault(); if (certFile == null) { if (maxCount == 0) throw new FileNotFoundException("Cannot find file in directories"); return GetCertPath(di.Parent, maxCount - 1); } return certFile.FullName; } private static X509Certificate LocalCertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) { return GetCertificate(); } private static bool CertValidator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } private static TProtocol MakeProtocol(string[] args, TTransport transport) { Protocol selectedProtocol = GetProtocol(args); return selectedProtocol switch { Protocol.Binary => new TBinaryProtocol(transport), Protocol.Compact => new TCompactProtocol(transport), Protocol.Json => new TJsonProtocol(transport), _ => throw new Exception("unhandled protocol"), }; } private static async Task RunClientAsync(TProtocol protocol, bool multiplex, CancellationToken cancellationToken) { try { try { if( multiplex) protocol = new TMultiplexedProtocol(protocol, nameof(Calculator)); var client = new Calculator.Client(protocol); await ExecuteCalculatorClientOperations(client, cancellationToken); } catch (Exception ex) { Logger.LogError("{ex}",ex); } finally { protocol.Transport.Close(); } } catch (TApplicationException x) { Logger.LogError("{x}",x); } } private static async Task ExecuteCalculatorClientOperations( Calculator.Client client, CancellationToken cancellationToken) { await client.OpenTransportAsync(cancellationToken); // Async version Logger.LogInformation("{client.ClientId} Ping()", client.ClientId); await client.ping(cancellationToken); Logger.LogInformation("{client.ClientId} Add(1,1)", client.ClientId); var sum = await client.add(1, 1, cancellationToken); Logger.LogInformation("{client.ClientId} Add(1,1)={sum}", client.ClientId, sum); var work = new Work { Op = Operation.DIVIDE, Num1 = 1, Num2 = 0 }; try { Logger.LogInformation("{client.ClientId} Calculate(1)", client.ClientId); await client.calculate(1, work, cancellationToken); Logger.LogInformation("{client.ClientId} Whoa we can divide by 0", client.ClientId); } catch (InvalidOperation io) { Logger.LogInformation("{client.ClientId} Invalid operation: {io}", client.ClientId, io); } work.Op = Operation.SUBTRACT; work.Num1 = 15; work.Num2 = 10; try { Logger.LogInformation("{client.ClientId} Calculate(1)", client.ClientId); var diff = await client.calculate(1, work, cancellationToken); Logger.LogInformation("{client.ClientId} 15-10={diff}", client.ClientId, diff); } catch (InvalidOperation io) { Logger.LogInformation("{client.ClientId} Invalid operation: {io}", client.ClientId, io); } Logger.LogInformation("{client.ClientId} GetStruct(1)", client.ClientId); var log = await client.getStruct(1, cancellationToken); Logger.LogInformation("{client.ClientId} Check log: {log.Value}", client.ClientId, log.Value); Logger.LogInformation("{client.ClientId} Zip() with delay 100mc on server side", client.ClientId); await client.zip(cancellationToken); } private enum Transport { Tcp, NamedPipe, Http, TcpBuffered, Framed, TcpTls } private enum Protocol { Binary, Compact, Json, } private enum Buffering { None, Buffered, Framed } } } thrift-0.16.0/tutorial/netstd/Client/Properties/000077500000000000000000000000001420101504100216005ustar00rootroot00000000000000thrift-0.16.0/tutorial/netstd/Client/Properties/AssemblyInfo.cs000066400000000000000000000032611420101504100245240ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("The Apache Software Foundation")] [assembly: AssemblyProduct("Thrift")] [assembly: AssemblyCopyright("The Apache Software Foundation")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("de78a01b-f7c6-49d1-97da-669d2ed37641")]thrift-0.16.0/tutorial/netstd/Client/ThriftTest.pfx000066400000000000000000000051451420101504100222700ustar00rootroot000000000000000 a0  *H   0 0 *H 00 *H  00 *H  0P:D9)wg;b B_4Ʒu"wKbEKڀ cX&Hl>A0;ߐ{a2vLOl 7V/]aFNx4T-n`PEu6;=C& ϖ-Iy┹!ĤGϲ'ɵA XQ2QFRN_j-?@h'yUH enHVߊ%}:sy%ePj呡_es)PÍ&VKP;0։`H:v7p+왫FͦxY嫈f~$`fZlr.sQ1Ǔ v 6v .]Hc4ӿ;}w^w)U⋉f.] $=Gr)da]`i n?a`חZ HOҫ؞&lI2Jt;xHPRz# 騲 ]RGd=GW@JGSG:}߶KMm|(U&H疓Fzſ6x>y:ˮäL>C8ob gx,P~h~i~t$aN̐t"4ۥj_1 Bwd^RѸ׆^j:ue.ˮwȤv 8/1o{icÂ/|bZ'ێ*Ff05$,U J( \`[l=]$2Ol`H p`|fxU9GxwoձU,$DNgb];,b}+7``rlײl5&x|1>{Z\N iԄT>aeټqE-sB^'Ԉ:_d^!g*6g)(E5x2JLЪ*tMU9GBҨ l+@r@)5_Ah ƀS: z[:#&aY< \,I%X4#íM (1]7;F9:6 }Qښr=s&imV7R7)R56V Fo{"!ϣW6s@+;-Pa-rX>StVSax͡_6.gpǝr:٨Z&Apw@Xq?10  +710 *H  10] *H  1PNte-017de0ac-82d9-4478-8b4f-a6370451f3bf0] +71PNMicrosoft Software Key Storage Provider0 *H 00 *H 0 *H  0v޴]ЀפWc!i}%bH  їhR-x0jq!)$޺~=; E;}' +R?tfRmF@"x<JQ-# ]2L5FcxwHpd د\{Wp:er#8Ͽ9PpQQek ")$)NuV!"8eȌK @50̂r?dͺ]:V?n+cꈯDV8T!:7G(}]T+j`꒼?WVC=tH'v%e#y{J}&<U=Ej@CکL ui"HqZG3B"J~?.@cȅW8l9­F9ggK8x{y^Gd@=ʉL\w%C"ɽaFx 7<;elNiîtP{]Sje01 hʗd=Ř@+CȐGF=#8i6_'j- \@L0@`,+ ǵlil('ѿj80s^0f}VX>O/]Ӵe=|$0~&MqI:֮%wZ GiÌ-u Յ')#H"%Rsv!)r3m'nc 6f}U+Ob}wBDr\~L#n֊蕎xn\fYZ7bh@X*FV4a$۫\M3Yd0uj~fi$sl|]H=.y@<|n^Ҏtݧ,W'p-Th9\ָjd~SiIdLbfbzV~FFl L90;00++7I%-j3^?8]9 3thrift-0.16.0/tutorial/netstd/Interfaces/000077500000000000000000000000001420101504100203115ustar00rootroot00000000000000thrift-0.16.0/tutorial/netstd/Interfaces/GlobalSuppressions.cs000066400000000000000000000024051420101504100244770ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Performance", "CA1822", Justification = "", Scope = "module")] [assembly: SuppressMessage("Style", "IDE0083", Justification = "", Scope = "module")] thrift-0.16.0/tutorial/netstd/Interfaces/Interfaces.csproj000066400000000000000000000044761420101504100236310ustar00rootroot00000000000000 net6.0 Interfaces Interfaces 0.16.0.0 false false false false thrift-0.16.0/tutorial/netstd/Interfaces/Properties/000077500000000000000000000000001420101504100224455ustar00rootroot00000000000000thrift-0.16.0/tutorial/netstd/Interfaces/Properties/AssemblyInfo.cs000066400000000000000000000032611420101504100253710ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("The Apache Software Foundation")] [assembly: AssemblyProduct("Thrift")] [assembly: AssemblyCopyright("The Apache Software Foundation")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("4d13163d-9067-4c9c-8af0-64e08451397d")]thrift-0.16.0/tutorial/netstd/Makefile.am000066400000000000000000000021401420101504100202570ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # SUBDIRS = . all-local: $(DOTNETCORE) build -c Release clean-local: $(RM) Interfaces.dll $(RM) -r Client/bin $(RM) -r Client/obj $(RM) -r Server/bin $(RM) -r Server/obj $(RM) -r Interfaces/bin $(RM) -r Interfaces/obj EXTRA_DIST = \ Client \ Interfaces \ README.md \ Server \ Tutorial.sln \ build.cmd \ build.sh thrift-0.16.0/tutorial/netstd/README.md000066400000000000000000000202271420101504100175100ustar00rootroot00000000000000# Building of samples for different platforms # Requirements - NET Core Standard 3.1 (LTS) runtime or SDK (see below for further info) # How to build - Download and install the latest .NET Core SDK for your platform https://dotnet.microsoft.com/download/dotnet-core - Ensure that you have thrift.exe which supports netstd lib and it added to PATH - Go to current folder - Run **build.sh** or **build.cmd** from the root of cloned repository - Check tests in **src/Tests** folder - Continue with /tutorials/netstd # How to run Depending on the platform, the name of the generated executables will vary. On Linux, it is just "Client" or "Server", on Windows it is "Client.exe" and "Server.exe". In the following, we use the abbreviated form "Client" and "Server". - build - go to folder (Client/Server) - run the generated executables: server first, then client from a second console # Known issues - In trace logging mode you can see some not important internal exceptions # Running of samples On machines that do not have the SDK installed, you need to install the NET Core runtime first. The SDK is only needed to build programs, otherwise the runtime is sufficient. # NetCore Server Usage: Server -help will diplay help information Server -tr: -pr: will run server with specified arguments (tcp transport and binary protocol by default) Options: -tr (transport): tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090) namedpipe - namedpipe transport will be used (pipe address - "".test"") http - http transport will be used (http address - ""localhost:9090"") tcptls - tcp transport with tls will be used (host - ""localhost"", port - 9090) -bf (buffering): none - (default) no transport factory will be used buffered - buffered transport factory will be used framed - framed transport factory will be used (this must match the client) -pr (protocol): binary - (default) binary protocol will be used compact - compact protocol will be used json - json protocol will be used multiplexed - multiplexed protocol will be used Sample: Server -tr:tcp **Remarks**: For TcpTls mode certificate's file ThriftTest.pfx should be in directory with binaries in case of command line usage (or at project level in case of debugging from IDE). Password for certificate - "ThriftTest". # NetCore Client Usage: Client -help will diplay help information Client -tr: -pr: -mc: will run client with specified arguments (tcp transport and binary protocol by default) Options: -tr (transport): tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090) namedpipe - namedpipe transport will be used (pipe address - "".test"") http - http transport will be used (address - ""http://localhost:9090"") tcptls - tcp tls transport will be used (host - ""localhost"", port - 9090) -bf (buffering): none - (default) no transport factory will be used buffered - buffered transport factory will be used framed - framed transport factory will be used (this must match the client) -pr (protocol): binary - (default) binary protocol will be used compact - compact protocol will be used json - json protocol will be used multiplexed - multiplexed protocol will be used -mc (multiple clients): - number of multiple clients to connect to server (max 100, default 1) Sample: Client -tr:tcp -pr:binary -mc:10 Remarks: For TcpTls mode certificate's file ThriftTest.pfx should be in directory with binaries in case of command line usage (or at project level in case of debugging from IDE). Password for certificate - "ThriftTest". # How to test communication between NetCore and Python * Generate code with the latest **thrift** utility * Ensure that **thrift** generated folder **gen-py** with generated code for Python exists * Create **client.py** and **server.py** from the code examples below and save them to the folder with previosly generated folder **gen-py** * Run netstd samples (client and server) and python samples (client and server) Remarks: Samples of client and server code below use correct methods (operations) and fields (properties) according to generated contracts from *.thrift files At Windows 10 add record **127.0.0.1 testserver** to **C:\Windows\System32\drivers\etc\hosts** file for correct work of python server **Python Client:** ```python import sys import glob sys.path.append('gen-py') from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation, Work from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol def main(): # Make socket transport = TSocket.TSocket('127.0.0.1', 9090) # Buffering is critical. Raw sockets are very slow transport = TTransport.TBufferedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = Calculator.Client(protocol) # Connect! transport.open() client.Ping() print('ping()') sum = client.Add(1, 1) print(('1+1=%d' % (sum))) work = Work() work.Op = Operation.Divide work.Num1 = 1 work.Num2 = 0 try: quotient = client.Calculate(1, work) print('Whoa? You know how to divide by zero?') print('FYI the answer is %d' % quotient) except InvalidOperation as e: print(('InvalidOperation: %r' % e)) work.Op = Operation.Substract work.Num1 = 15 work.Num2 = 10 diff = client.Calculate(1, work) print(('15-10=%d' % (diff))) log = client.GetStruct(1) print(('Check log: %s' % (log.Value))) client.Zip() print('zip()') # Close! transport.close() if __name__ == '__main__': try: main() except Thrift.TException as tx: print('%s' % tx.message) ``` **Python Server:** ```python import glob import sys sys.path.append('gen-py') from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation from shared.ttypes import SharedStruct from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer class CalculatorHandler: def __init__(self): self.log = {} def Ping(self): print('ping()') def Add(self, n1, n2): print('add(%d,%d)' % (n1, n2)) return n1 + n2 def Calculate(self, logid, work): print('calculate(%d, %r)' % (logid, work)) if work.Op == Operation.Add: val = work.Num1 + work.Num2 elif work.Op == Operation.Substract: val = work.Num1 - work.Num2 elif work.Op == Operation.Multiply: val = work.Num1 * work.Num2 elif work.Op == Operation.Divide: if work.Num2 == 0: raise InvalidOperation(work.Op, 'Cannot divide by 0') val = work.Num1 / work.Num2 else: raise InvalidOperation(work.Op, 'Invalid operation') log = SharedStruct() log.Key = logid log.Value = '%d' % (val) self.log[logid] = log return val def GetStruct(self, key): print('getStruct(%d)' % (key)) return self.log[key] def Zip(self): print('zip()') if __name__ == '__main__': handler = CalculatorHandler() processor = Calculator.Processor(handler) transport = TSocket.TServerSocket(host="testserver", port=9090) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) print('Starting the server...') server.serve() print('done.') # You could do one of these for a multithreaded server # server = TServer.TThreadedServer(processor, transport, tfactory, pfactory) # server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory) ``` thrift-0.16.0/tutorial/netstd/Server/000077500000000000000000000000001420101504100174745ustar00rootroot00000000000000thrift-0.16.0/tutorial/netstd/Server/Program.cs000066400000000000000000000413321420101504100214350ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Thrift; using Thrift.Protocol; using Thrift.Server; using Thrift.Transport; using Thrift.Transport.Server; using tutorial; using shared; using Thrift.Processor; using System.Diagnostics; #pragma warning disable IDE0057 // substr namespace Server { public static class LoggingHelper { public static ILoggerFactory LogFactory { get; } = LoggerFactory.Create(builder => { ConfigureLogging(builder); }); public static void ConfigureLogging(ILoggingBuilder logging) { logging.SetMinimumLevel(LogLevel.Trace); logging.AddConsole(); logging.AddDebug(); } public static ILogger CreateLogger() => LogFactory.CreateLogger(); } public class Program { private static readonly ILogger Logger = LoggingHelper.CreateLogger(); private static readonly TConfiguration Configuration = null; // new TConfiguration() if needed public static void Main(string[] args) { args ??= Array.Empty(); if (args.Any(x => x.StartsWith("-help", StringComparison.OrdinalIgnoreCase))) { DisplayHelp(); return; } using (var source = new CancellationTokenSource()) { RunAsync(args, source.Token).GetAwaiter().GetResult(); Logger.LogInformation("Press any key to stop..."); Console.ReadLine(); source.Cancel(); } Logger.LogInformation("Server stopped"); } private static void DisplayHelp() { Logger.LogInformation(@" Usage: Server -help will diplay help information Server -tr: -bf: -pr: [-multiplex] will run server with specified arguments (tcp transport, no buffering, and binary protocol by default) Options: -tr (transport): tcp - (default) tcp transport (localhost:9090) tcptls - tcp transport with tls (localhost:9090) namedpipe - namedpipe transport (pipe "".test"") http - http transport (localhost:9090) -bf (buffering): none - (default) no buffering buffered - buffered transport framed - framed transport -pr (protocol): binary - (default) binary protocol compact - compact protocol json - json protocol -multiplex - adds multiplexed protocol Sample: Server -tr:tcp "); } private static async Task RunAsync(string[] args, CancellationToken cancellationToken) { var selectedTransport = GetTransport(args); var selectedBuffering = GetBuffering(args); var selectedProtocol = GetProtocol(args); var multiplex = GetMultiplex(args); if (selectedTransport == Transport.Http) { if (multiplex) throw new Exception("This tutorial semple code does not yet allow multiplex over http (although Thrift itself of course does)"); new HttpServerSample().Run(cancellationToken); } else { await RunSelectedConfigurationAsync(selectedTransport, selectedBuffering, selectedProtocol, multiplex, cancellationToken); } } private static bool GetMultiplex(string[] args) { var mplex = args.FirstOrDefault(x => x.StartsWith("-multiplex")); return !string.IsNullOrEmpty(mplex); } private static Protocol GetProtocol(string[] args) { var protocol = args.FirstOrDefault(x => x.StartsWith("-pr"))?.Split(':')?[1]; if (string.IsNullOrEmpty(protocol)) return Protocol.Binary; protocol = protocol.Substring(0, 1).ToUpperInvariant() + protocol.Substring(1).ToLowerInvariant(); if (Enum.TryParse(protocol, true, out Protocol selectedProtocol)) return selectedProtocol; else return Protocol.Binary; } private static Buffering GetBuffering(string[] args) { var buffering = args.FirstOrDefault(x => x.StartsWith("-bf"))?.Split(":")?[1]; if (string.IsNullOrEmpty(buffering)) return Buffering.None; buffering = buffering.Substring(0, 1).ToUpperInvariant() + buffering.Substring(1).ToLowerInvariant(); if( Enum.TryParse(buffering, out var selectedBuffering)) return selectedBuffering; else return Buffering.None; } private static Transport GetTransport(string[] args) { var transport = args.FirstOrDefault(x => x.StartsWith("-tr"))?.Split(':')?[1]; if (string.IsNullOrEmpty(transport)) return Transport.Tcp; transport = transport.Substring(0, 1).ToUpperInvariant() + transport.Substring(1).ToLowerInvariant(); if( Enum.TryParse(transport, true, out Transport selectedTransport)) return selectedTransport; else return Transport.Tcp; } private static async Task RunSelectedConfigurationAsync(Transport transport, Buffering buffering, Protocol protocol, bool multiplex, CancellationToken cancellationToken) { TServerTransport serverTransport = transport switch { Transport.Tcp => new TServerSocketTransport(9090, Configuration), Transport.NamedPipe => new TNamedPipeServerTransport(".test", Configuration, NamedPipeClientFlags.None), Transport.TcpTls => new TTlsServerSocketTransport(9090, Configuration, GetCertificate(), ClientCertValidator, LocalCertificateSelectionCallback), _ => throw new ArgumentException("unsupported value $transport", nameof(transport)), }; TTransportFactory transportFactory = buffering switch { Buffering.Buffered => new TBufferedTransport.Factory(), Buffering.Framed => new TFramedTransport.Factory(), // layered transport(s) are optional Buffering.None => null, _ => throw new ArgumentException("unsupported value $buffering", nameof(buffering)), }; TProtocolFactory protocolFactory = protocol switch { Protocol.Binary => new TBinaryProtocol.Factory(), Protocol.Compact => new TCompactProtocol.Factory(), Protocol.Json => new TJsonProtocol.Factory(), _ => throw new ArgumentException("unsupported value $protocol", nameof(protocol)), }; var handler = new CalculatorAsyncHandler(); ITAsyncProcessor processor = new Calculator.AsyncProcessor(handler); if (multiplex) { var multiplexedProcessor = new TMultiplexedProcessor(); multiplexedProcessor.RegisterProcessor(nameof(Calculator), processor); processor = multiplexedProcessor; } try { Logger.LogInformation( "TSimpleAsyncServer with \n{transport} transport\n{buffering} buffering\nmultiplex = {multiplex}\n{protocol} protocol", transport, buffering, multiplex ? "yes" : "no", protocol ); var server = new TSimpleAsyncServer( itProcessorFactory: new TSingletonProcessorFactory(processor), serverTransport: serverTransport, inputTransportFactory: transportFactory, outputTransportFactory: transportFactory, inputProtocolFactory: protocolFactory, outputProtocolFactory: protocolFactory, logger: LoggingHelper.CreateLogger()); Logger.LogInformation("Starting the server..."); await server.ServeAsync(cancellationToken); } catch (Exception x) { Logger.LogInformation("{x}",x); } } private static X509Certificate2 GetCertificate() { // due to files location in net core better to take certs from top folder var certFile = GetCertPath(Directory.GetParent(Directory.GetCurrentDirectory())); return new X509Certificate2(certFile, "ThriftTest"); } private static string GetCertPath(DirectoryInfo di, int maxCount = 6) { var topDir = di; var certFile = topDir.EnumerateFiles("ThriftTest.pfx", SearchOption.AllDirectories) .FirstOrDefault(); if (certFile == null) { if (maxCount == 0) throw new FileNotFoundException("Cannot find file in directories"); return GetCertPath(di.Parent, maxCount - 1); } return certFile.FullName; } private static X509Certificate LocalCertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) { return GetCertificate(); } private static bool ClientCertValidator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } private enum Transport { Tcp, NamedPipe, Http, TcpTls, } private enum Buffering { None, Buffered, Framed, } private enum Protocol { Binary, Compact, Json, } public class HttpServerSample { public void Run(CancellationToken cancellationToken) { var config = new ConfigurationBuilder() .AddEnvironmentVariables(prefix: "ASPNETCORE_") .Build(); var host = new WebHostBuilder() .UseConfiguration(config) .UseKestrel() .UseUrls("http://localhost:9090") .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup() .ConfigureLogging((ctx,logging) => LoggingHelper.ConfigureLogging(logging)) .Build(); Logger.LogTrace("test"); Logger.LogCritical("test"); host.RunAsync(cancellationToken).GetAwaiter().GetResult(); } public class Startup { public Startup(IWebHostEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // NOTE: this is not really the recommended way to do it // because the HTTP server cannot be configured properly to e.g. accept framed or multiplex services.AddTransient(); services.AddTransient(); services.AddTransient(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { _ = env; _ = loggerFactory; app.UseMiddleware(); } } } public class CalculatorAsyncHandler : Calculator.IAsync { private readonly Dictionary _log = new(); public CalculatorAsyncHandler() { } public async Task getStruct(int key, CancellationToken cancellationToken) { Logger.LogInformation("GetStruct({key})", key); return await Task.FromResult(_log[key]); } public async Task ping(CancellationToken cancellationToken) { Logger.LogInformation("Ping()"); await Task.CompletedTask; } public async Task add(int num1, int num2, CancellationToken cancellationToken) { Logger.LogInformation("Add({num1},{num2})", num1, num2); return await Task.FromResult(num1 + num2); } public async Task calculate(int logid, Work w, CancellationToken cancellationToken) { Logger.LogInformation("Calculate({logid}, [{w.Op},{w.Num1},{w.Num2}])", logid, w.Op, w.Num1, w.Num2); int val; switch (w.Op) { case Operation.ADD: val = w.Num1 + w.Num2; break; case Operation.SUBTRACT: val = w.Num1 - w.Num2; break; case Operation.MULTIPLY: val = w.Num1 * w.Num2; break; case Operation.DIVIDE: if (w.Num2 == 0) { var io = new InvalidOperation { WhatOp = (int) w.Op, Why = "Cannot divide by 0" }; throw io; } val = w.Num1 / w.Num2; break; default: { var io = new InvalidOperation { WhatOp = (int) w.Op, Why = "Unknown operation" }; throw io; } } var entry = new SharedStruct { Key = logid, Value = val.ToString() }; _log[logid] = entry; return await Task.FromResult(val); } public async Task zip(CancellationToken cancellationToken) { Logger.LogInformation("Zip() with delay 100mc"); await Task.Delay(100, CancellationToken.None); } } public class SharedServiceAsyncHandler : SharedService.IAsync { public async Task getStruct(int key, CancellationToken cancellationToken) { Logger.LogInformation("GetStruct({key})", key); return await Task.FromResult(new SharedStruct() { Key = key, Value = "GetStruct" }); } } } } thrift-0.16.0/tutorial/netstd/Server/Properties/000077500000000000000000000000001420101504100216305ustar00rootroot00000000000000thrift-0.16.0/tutorial/netstd/Server/Properties/AssemblyInfo.cs000066400000000000000000000032611420101504100245540ustar00rootroot00000000000000// Licensed to the Apache Software Foundation(ASF) under one // or more contributor license agreements.See the NOTICE file // distributed with this work for additional information // regarding copyright ownership.The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("The Apache Software Foundation")] [assembly: AssemblyProduct("Thrift")] [assembly: AssemblyCopyright("The Apache Software Foundation")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("e210fc10-5aff-4b04-ac21-58afc7b74b0c")]thrift-0.16.0/tutorial/netstd/Server/Server.csproj000066400000000000000000000037441420101504100221740ustar00rootroot00000000000000 net6.0 9.0 Server Server Exe 0.16.0.0 false false false false thrift-0.16.0/tutorial/netstd/Server/ThriftTest.pfx000066400000000000000000000051451420101504100223200ustar00rootroot000000000000000 a0  *H   0 0 *H 00 *H  00 *H  0P:D9)wg;b B_4Ʒu"wKbEKڀ cX&Hl>A0;ߐ{a2vLOl 7V/]aFNx4T-n`PEu6;=C& ϖ-Iy┹!ĤGϲ'ɵA XQ2QFRN_j-?@h'yUH enHVߊ%}:sy%ePj呡_es)PÍ&VKP;0։`H:v7p+왫FͦxY嫈f~$`fZlr.sQ1Ǔ v 6v .]Hc4ӿ;}w^w)U⋉f.] $=Gr)da]`i n?a`חZ HOҫ؞&lI2Jt;xHPRz# 騲 ]RGd=GW@JGSG:}߶KMm|(U&H疓Fzſ6x>y:ˮäL>C8ob gx,P~h~i~t$aN̐t"4ۥj_1 Bwd^RѸ׆^j:ue.ˮwȤv 8/1o{icÂ/|bZ'ێ*Ff05$,U J( \`[l=]$2Ol`H p`|fxU9GxwoձU,$DNgb];,b}+7``rlײl5&x|1>{Z\N iԄT>aeټqE-sB^'Ԉ:_d^!g*6g)(E5x2JLЪ*tMU9GBҨ l+@r@)5_Ah ƀS: z[:#&aY< \,I%X4#íM (1]7;F9:6 }Qښr=s&imV7R7)R56V Fo{"!ϣW6s@+;-Pa-rX>StVSax͡_6.gpǝr:٨Z&Apw@Xq?10  +710 *H  10] *H  1PNte-017de0ac-82d9-4478-8b4f-a6370451f3bf0] +71PNMicrosoft Software Key Storage Provider0 *H 00 *H 0 *H  0v޴]ЀפWc!i}%bH  їhR-x0jq!)$޺~=; E;}' +R?tfRmF@"x<JQ-# ]2L5FcxwHpd د\{Wp:er#8Ͽ9PpQQek ")$)NuV!"8eȌK @50̂r?dͺ]:V?n+cꈯDV8T!:7G(}]T+j`꒼?WVC=tH'v%e#y{J}&<U=Ej@CکL ui"HqZG3B"J~?.@cȅW8l9­F9ggK8x{y^Gd@=ʉL\w%C"ɽaFx 7<;elNiîtP{]Sje01 hʗd=Ř@+CȐGF=#8i6_'j- \@L0@`,+ ǵlil('ѿj80s^0f}VX>O/]Ӵe=|$0~&MqI:֮%wZ GiÌ-u Յ')#H"%Rsv!)r3m'nc 6f}U+Ob}wBDr\~L#n֊蕎xn\fYZ7bh@X*FV4a$۫\M3Yd0uj~fi$sl|]H=.y@<|n^Ҏtݧ,W'p-Th9\ָjd~SiIdLbfbzV~FFl L90;00++7I%-j3^?8]9 3thrift-0.16.0/tutorial/netstd/Tutorial.sln000066400000000000000000000117701420101504100205550ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26114.2 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "..\..\lib\netstd\Thrift\Thrift.csproj", "{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Interfaces", "Interfaces\Interfaces.csproj", "{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.Build.0 = Debug|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.ActiveCfg = Debug|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.Build.0 = Debug|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.ActiveCfg = Debug|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.Build.0 = Debug|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.ActiveCfg = Release|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.Build.0 = Release|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.ActiveCfg = Release|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.Build.0 = Release|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.ActiveCfg = Release|Any CPU {C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.Build.0 = Release|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x64.ActiveCfg = Debug|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x64.Build.0 = Debug|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x86.ActiveCfg = Debug|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x86.Build.0 = Debug|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|Any CPU.Build.0 = Release|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x64.ActiveCfg = Release|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x64.Build.0 = Release|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x86.ActiveCfg = Release|Any CPU {B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x86.Build.0 = Release|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|Any CPU.Build.0 = Debug|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x64.ActiveCfg = Debug|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x64.Build.0 = Debug|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x86.ActiveCfg = Debug|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x86.Build.0 = Debug|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|Any CPU.ActiveCfg = Release|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|Any CPU.Build.0 = Release|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x64.ActiveCfg = Release|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x64.Build.0 = Release|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x86.ActiveCfg = Release|Any CPU {E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x86.Build.0 = Release|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|Any CPU.Build.0 = Debug|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x64.ActiveCfg = Debug|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x64.Build.0 = Debug|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x86.ActiveCfg = Debug|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x86.Build.0 = Debug|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|Any CPU.ActiveCfg = Release|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|Any CPU.Build.0 = Release|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x64.ActiveCfg = Release|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x64.Build.0 = Release|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x86.ActiveCfg = Release|Any CPU {E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {070A5D1D-B29D-4603-999D-693DB444AD0D} EndGlobalSection EndGlobal thrift-0.16.0/tutorial/netstd/build.cmd000066400000000000000000000016411420101504100200140ustar00rootroot00000000000000@echo off rem /* rem * Licensed to the Apache Software Foundation (ASF) under one rem * or more contributor license agreements. See the NOTICE file rem * distributed with this work for additional information rem * regarding copyright ownership. The ASF licenses this file rem * to you under the Apache License, Version 2.0 (the rem * "License"); you may not use this file except in compliance rem * with the License. You may obtain a copy of the License at rem * rem * http://www.apache.org/licenses/LICENSE-2.0 rem * rem * Unless required by applicable law or agreed to in writing, rem * software distributed under the License is distributed on an rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY rem * KIND, either express or implied. See the License for the rem * specific language governing permissions and limitations rem * under the License. rem */ setlocal dotnet --info dotnet build :eof thrift-0.16.0/tutorial/netstd/build.sh000077500000000000000000000015451420101504100176710ustar00rootroot00000000000000#!/usr/bin/env bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #exit if any command fails set -e dotnet --info dotnet build thrift-0.16.0/tutorial/nodejs/000077500000000000000000000000001420101504100162075ustar00rootroot00000000000000thrift-0.16.0/tutorial/nodejs/Makefile.am000066400000000000000000000031201420101504100202370ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-nodejs/Calculator.js gen-nodejs/SharedService.js: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen js:node -r $< all-local: gen-nodejs/Calculator.js tutorialserver: all NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServer.js tutorialclient: all NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClient.js tutorialserver_promise: all NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServerPromise.js tutorialclient_promise: all NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClientPromise.js clean-local: $(RM) -r gen-* EXTRA_DIST = \ NodeServer.js \ NodeClient.js \ NodeServerPromise.js \ NodeClientPromise.js thrift-0.16.0/tutorial/nodejs/NodeClient.js000066400000000000000000000040731420101504100205750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require('thrift'); var Calculator = require('./gen-nodejs/Calculator'); var ttypes = require('./gen-nodejs/tutorial_types'); const assert = require('assert'); var transport = thrift.TBufferedTransport; var protocol = thrift.TBinaryProtocol; var connection = thrift.createConnection("localhost", 9090, { transport : transport, protocol : protocol }); connection.on('error', function(err) { assert(false, err); }); // Create a Calculator client with the connection var client = thrift.createClient(Calculator, connection); client.ping(function(err, response) { console.log('ping()'); }); client.add(1,1, function(err, response) { console.log("1+1=" + response); }); work = new ttypes.Work(); work.op = ttypes.Operation.DIVIDE; work.num1 = 1; work.num2 = 0; client.calculate(1, work, function(err, message) { if (err) { console.log("InvalidOperation " + err); } else { console.log('Whoa? You know how to divide by zero?'); } }); work.op = ttypes.Operation.SUBTRACT; work.num1 = 15; work.num2 = 10; client.calculate(1, work, function(err, message) { console.log('15-10=' + message); client.getStruct(1, function(err, message){ console.log('Check log: ' + message.value); //close the connection once we're done connection.end(); }); }); thrift-0.16.0/tutorial/nodejs/NodeClientPromise.js000066400000000000000000000041541420101504100221340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require('thrift'); var Calculator = require('./gen-nodejs/Calculator'); var ttypes = require('./gen-nodejs/tutorial_types'); const assert = require('assert'); var transport = thrift.TBufferedTransport; var protocol = thrift.TBinaryProtocol; var connection = thrift.createConnection("localhost", 9090, { transport : transport, protocol : protocol }); connection.on('error', function(err) { assert(false, err); }); // Create a Calculator client with the connection var client = thrift.createClient(Calculator, connection); client.ping() .then(function() { console.log('ping()'); }); client.add(1,1) .then(function(response) { console.log("1+1=" + response); }); work = new ttypes.Work(); work.op = ttypes.Operation.DIVIDE; work.num1 = 1; work.num2 = 0; client.calculate(1, work) .then(function(message) { console.log('Whoa? You know how to divide by zero?'); }) .fail(function(err) { console.log("InvalidOperation " + err); }); work.op = ttypes.Operation.SUBTRACT; work.num1 = 15; work.num2 = 10; client.calculate(1, work) .then(function(value) { console.log('15-10=' + value); return client.getStruct(1); }) .then(function(message) { console.log('Check log: ' + message.value); }) .fin(function() { //close the connection once we're done connection.end(); }); thrift-0.16.0/tutorial/nodejs/NodeServer.js000066400000000000000000000045431420101504100206270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require("thrift"); var Calculator = require("./gen-nodejs/Calculator"); var ttypes = require("./gen-nodejs/tutorial_types"); var SharedStruct = require("./gen-nodejs/shared_types").SharedStruct; var data = {}; var server = thrift.createServer(Calculator, { ping: function(result) { console.log("ping()"); result(null); }, add: function(n1, n2, result) { console.log("add(", n1, ",", n2, ")"); result(null, n1 + n2); }, calculate: function(logid, work, result) { console.log("calculate(", logid, ",", work, ")"); var val = 0; if (work.op == ttypes.Operation.ADD) { val = work.num1 + work.num2; } else if (work.op === ttypes.Operation.SUBTRACT) { val = work.num1 - work.num2; } else if (work.op === ttypes.Operation.MULTIPLY) { val = work.num1 * work.num2; } else if (work.op === ttypes.Operation.DIVIDE) { if (work.num2 === 0) { var x = new ttypes.InvalidOperation(); x.whatOp = work.op; x.why = 'Cannot divide by 0'; result(x); return; } val = work.num1 / work.num2; } else { var x = new ttypes.InvalidOperation(); x.whatOp = work.op; x.why = 'Invalid operation'; result(x); return; } var entry = new SharedStruct(); entry.key = logid; entry.value = ""+val; data[logid] = entry; result(null, val); }, getStruct: function(key, result) { console.log("getStruct(", key, ")"); result(null, data[key]); }, zip: function() { console.log("zip()"); } }); server.listen(9090); thrift-0.16.0/tutorial/nodejs/NodeServerPromise.js000066400000000000000000000043651420101504100221700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var thrift = require("thrift"); var Calculator = require("./gen-nodejs/Calculator"); var ttypes = require("./gen-nodejs/tutorial_types"); var SharedStruct = require("./gen-nodejs/shared_types").SharedStruct; var data = {}; var server = thrift.createServer(Calculator, { ping: function() { console.log("ping()"); }, add: function(n1, n2) { console.log("add(", n1, ",", n2, ")"); return n1 + n2; }, calculate: function(logid, work) { console.log("calculate(", logid, ",", work, ")"); var val = 0; if (work.op == ttypes.Operation.ADD) { val = work.num1 + work.num2; } else if (work.op === ttypes.Operation.SUBTRACT) { val = work.num1 - work.num2; } else if (work.op === ttypes.Operation.MULTIPLY) { val = work.num1 * work.num2; } else if (work.op === ttypes.Operation.DIVIDE) { if (work.num2 === 0) { var x = new ttypes.InvalidOperation(); x.whatOp = work.op; x.why = 'Cannot divide by 0'; throw x; } val = work.num1 / work.num2; } else { var x = new ttypes.InvalidOperation(); x.whatOp = work.op; x.why = 'Invalid operation'; throw x; } var entry = new SharedStruct(); entry.key = logid; entry.value = ""+val; data[logid] = entry; return val; }, getStruct: function(key) { console.log("getStruct(", key, ")"); return data[key]; }, zip: function() { console.log("zip()"); } }); server.listen(9090); thrift-0.16.0/tutorial/ocaml/000077500000000000000000000000001420101504100160205ustar00rootroot00000000000000thrift-0.16.0/tutorial/ocaml/CalcClient.ml000077500000000000000000000044741420101504100203670ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Arg open Thrift open Tutorial_types open Shared_types exception Die;; let sod = function Some v -> v | None -> raise Die;; type connection = { trans : Transport.t ; proto : Thrift.Protocol.t; calc : Calculator.client ; } let connect ~host port = let tx = new TSocket.t host port in let proto = new TBinaryProtocol.t tx in let calc = new Calculator.client proto proto in tx#opn; { trans = tx ; proto = proto; calc = calc } ;; let doclient () = let cli = connect ~host:"127.0.0.1" 9090 in try cli.calc#ping ; Printf.printf "ping()\n" ; flush stdout ; (let sum = cli.calc#add (Int32.of_int 1) (Int32.of_int 1) in Printf.printf "1+1=%ld\n" sum ; flush stdout) ; (let w = new work in w#set_op Operation.DIVIDE ; w#set_num1 (Int32.of_int 1) ; w#set_num2 (Int32.of_int 0) ; try let quotient = cli.calc#calculate (Int32.of_int 1) w in Printf.printf "Whoa? We can divide by zero!\n" ; flush stdout with InvalidOperation io -> Printf.printf "InvalidOperation: %s\n" io#grab_why ; flush stdout) ; (let w = new work in w#set_op Operation.SUBTRACT ; w#set_num1 (Int32.of_int 15) ; w#set_num2 (Int32.of_int 10) ; let diff = cli.calc#calculate (Int32.of_int 1) w in Printf.printf "15-10=%ld\n" diff ; flush stdout) ; (let ss = cli.calc#getStruct (Int32.of_int 1) in Printf.printf "Check log: %s\n" ss#grab_value ; flush stdout) ; cli.trans#close with Transport.E (_,what) -> Printf.printf "ERROR: %s\n" what ; flush stdout ;; doclient();; thrift-0.16.0/tutorial/ocaml/CalcServer.ml000077500000000000000000000047351420101504100204170ustar00rootroot00000000000000(* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *) open Arg open Thrift open Tutorial_types open Shared_types exception Die;; let sod = function Some v -> v | None -> raise Die;; class calc_handler = object (self) inherit Calculator.iface val log = Hashtbl.create 23 method ping = Printf.printf "ping()\n" ; flush stdout method add a b = Printf.printf"add(%ld,%ld)\n" (sod a) (sod b); flush stdout ; Int32.add (sod a) (sod b) method calculate logid w = let w = sod w in Printf.printf "calculate(%ld,{%ld,%ld,%ld})\n" (sod logid) (Operation.to_i w#grab_op) w#grab_num1 w#grab_num2; flush stdout ; let rv = match w#grab_op with Operation.ADD -> Int32.add w#grab_num1 w#grab_num2 | Operation.SUBTRACT -> Int32.sub w#grab_num1 w#grab_num2 | Operation.MULTIPLY -> Int32.mul w#grab_num1 w#grab_num2 | Operation.DIVIDE -> if w#grab_num2 = Int32.zero then let io = new invalidOperation in io#set_whatOp (Operation.to_i w#grab_op) ; io#set_why "Cannot divide by 0" ; raise (InvalidOperation io) else Int32.div w#grab_num1 w#grab_num2 in let ss = new sharedStruct in ss#set_key (sod logid) ; let buffer = Int32.to_string rv in ss#set_value buffer ; Hashtbl.add log (sod logid) ss ; rv method zip = Printf.printf "zip()\n"; flush stdout method getStruct logid = Printf.printf "getStruct(%ld)\n" (sod logid) ; flush stdout ; Hashtbl.find log (sod logid) end let doserver () = let h = new calc_handler in let proc = new Calculator.processor h in let port = 9090 in let pf = new TBinaryProtocol.factory in let server = new TThreadedServer.t proc (new TServerSocket.t port) (new Transport.factory) pf pf in server#serve ;; doserver();; thrift-0.16.0/tutorial/ocaml/README.md000066400000000000000000000011101420101504100172700ustar00rootroot00000000000000 This is the ocaml tutorial example. It assumes that you've already built and installed the thrift ocaml runtime libraries in lib/ocaml. To compile this, you will need to generate the Thrift sources for ocaml in this directory (due to limitations in the OASIS build-tool): % thrift -r --gen ocaml ../tutorial.thrift % oasis setup % make This will produce two executables Calc{Server,Client}. where is one of "byte" or "native", depending on your ocaml installation. Just run the server in the background, then the client (as you would do for the C++ example). thrift-0.16.0/tutorial/ocaml/_oasis000066400000000000000000000014341420101504100172220ustar00rootroot00000000000000Name: tutorial Version: 0.16.0 OASISFormat: 0.3 Synopsis: OCaml Tutorial example Authors: Apache Thrift Developers License: Apache-2.0 Homepage: http://thrift.apache.org BuildTools: ocamlbuild Plugins: META (0.3), DevFiles (0.3) Library tutorial_thrift Path: gen-ocaml FindlibName: tutorial_thrift buildTools: ocamlbuild BuildDepends: threads,thrift Modules: Calculator,Shared_consts,Tutorial_consts,SharedService,Shared_types,Tutorial_types XMETARequires: threads Executable CalcClient Path: . MainIs: CalcClient.ml Build$: true CompiledObject: best BuildDepends: thrift, tutorial_thrift, threads Executable CalcServer Path: . MainIs: CalcServer.ml Build$: true CompiledObject: best BuildDepends: thrift, tutorial_thrift, threads thrift-0.16.0/tutorial/perl/000077500000000000000000000000001420101504100156675ustar00rootroot00000000000000thrift-0.16.0/tutorial/perl/Makefile.am000077500000000000000000000021511420101504100177250ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-perl/tutorial/Calculator.pm gen-perl/shared/SharedService.pm: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen perl -r $< all-local: gen-perl/tutorial/Calculator.pm tutorialserver: all ${PERL} PerlServer.pl tutorialclient: all ${PERL} PerlClient.pl clean-local: $(RM) -r gen-* EXTRA_DIST = \ PerlServer.pl \ PerlClient.pl thrift-0.16.0/tutorial/perl/PerlClient.pl000066400000000000000000000040011420101504100202600ustar00rootroot00000000000000#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use strict; use warnings; use lib '../../lib/perl/lib'; use lib 'gen-perl'; use Thrift; use Thrift::BinaryProtocol; use Thrift::Socket; use Thrift::BufferedTransport; use shared::SharedService; use tutorial::Calculator; use shared::Types; use tutorial::Types; use Data::Dumper; my $socket = Thrift::Socket->new('localhost',9090); my $transport = Thrift::BufferedTransport->new($socket,1024,1024); my $protocol = Thrift::BinaryProtocol->new($transport); my $client = tutorial::CalculatorClient->new($protocol); eval{ $transport->open(); $client->ping(); print "ping()\n"; my $sum = $client->add(1,1); print "1+1=$sum\n"; my $work = tutorial::Work->new(); $work->op(tutorial::Operation::DIVIDE); $work->num1(1); $work->num2(0); eval { $client->calculate(1, $work); print "Whoa! We can divide by zero?\n"; }; if($@) { warn 'InvalidOperation: '.Dumper($@); } $work->op(tutorial::Operation::SUBTRACT); $work->num1(15); $work->num2(10); my $diff = $client->calculate(1, $work); print "15-10=$diff\n"; my $log = $client->getStruct(1); print "Log: $log->{value}\n"; $transport->close(); }; if($@){ warn(Dumper($@)); } thrift-0.16.0/tutorial/perl/PerlServer.pl000066400000000000000000000055311420101504100203210ustar00rootroot00000000000000#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use strict; use lib '../../lib/perl/lib'; use lib 'gen-perl'; use Thrift::Socket; use Thrift::Server; use Thrift::ServerSocket; use tutorial::Calculator; package CalculatorHandler; use base qw(tutorial::CalculatorIf); sub new { my $classname = shift; my $self = {}; return bless($self,$classname); } sub ping { print "ping()\n"; } sub add { my($self, $n1, $n2) = @_; printf("add(%d,%d)\n", $n1, $n2); return $n1 + $n2; } sub calculate { my($self, $logid, $work) = @_; my $op = $work->{op}; my $num1 = $work->{num1}; my $num2 = $work->{num2}; printf("calculate(%d, %d %d %d)\n", $logid, $num1, $num2, $op); my $val; if ($op == tutorial::Operation::ADD) { $val = $num1 + $num2; } elsif ($op == tutorial::Operation::SUBTRACT) { $val = $num1 - $num2; } elsif ($op == tutorial::Operation::MULTIPLY) { $val = $num1 * $num2; } elsif ($op == tutorial::Operation::DIVIDE) { if ($num2 == 0) { my $x = tutorial::InvalidOperation->new(); $x->whatOp($op); $x->why('Cannot divide by 0'); die $x; } $val = $num1 / $num2; } else { my $x = tutorial::InvalidOperation->new(); $x->whatOp($op); $x->why('Invalid operation'); die $x; } my $log = shared::SharedStruct->new(); $log->key($logid); $log->value(int($val)); $self->{log}->{$logid} = $log; return $val; } sub getStruct { my($self, $key) = @_; printf("getStruct(%d)\n", $key); return $self->{log}->{$key}; } sub zip { my($self) = @_; print "zip()\n"; } eval { my $handler = CalculatorHandler->new(); my $processor = tutorial::CalculatorProcessor->new($handler); my $serversocket = Thrift::ServerSocket->new(9090); my $forkingserver = Thrift::ForkingServer->new($processor, $serversocket); print "Starting the server...\n"; $forkingserver->serve(); print "done.\n"; }; if ($@) { if ($@ =~ m/TException/ and exists $@->{message}) { my $message = $@->{message}; my $code = $@->{code}; my $out = $code . ':' . $message; die $out; } else { die $@; } } thrift-0.16.0/tutorial/php/000077500000000000000000000000001420101504100155145ustar00rootroot00000000000000thrift-0.16.0/tutorial/php/Makefile.am000077500000000000000000000022061420101504100175530ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-php/tutorial/Calculator.php gen-php/shared/SharedService.php: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen php:server -r $< all-local: gen-php/tutorial/Calculator.php tutorialserver: all ${PYTHON} runserver.py tutorialclient: all ${PHP} PhpClient.php --http clean-local: $(RM) -r gen-* EXTRA_DIST = \ PhpServer.php \ PhpClient.php \ runserver.py thrift-0.16.0/tutorial/php/PhpClient.php000077500000000000000000000046771420101504100201340ustar00rootroot00000000000000#!/usr/bin/env php registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib'); $loader->registerNamespace('shared', $GEN_DIR); $loader->registerNamespace('tutorial', $GEN_DIR); $loader->register(); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ use Thrift\Protocol\TBinaryProtocol; use Thrift\Transport\TSocket; use Thrift\Transport\THttpClient; use Thrift\Transport\TBufferedTransport; use Thrift\Exception\TException; try { if (array_search('--http', $argv)) { $socket = new THttpClient('localhost', 8080, '/php/PhpServer.php'); } else { $socket = new TSocket('localhost', 9090); } $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $client = new \tutorial\CalculatorClient($protocol); $transport->open(); $client->ping(); print "ping()\n"; $sum = $client->add(1,1); print "1+1=$sum\n"; $work = new \tutorial\Work(); $work->op = \tutorial\Operation::DIVIDE; $work->num1 = 1; $work->num2 = 0; try { $client->calculate(1, $work); print "Whoa! We can divide by zero?\n"; } catch (\tutorial\InvalidOperation $io) { print "InvalidOperation: $io->why\n"; } $work->op = \tutorial\Operation::SUBTRACT; $work->num1 = 15; $work->num2 = 10; $diff = $client->calculate(1, $work); print "15-10=$diff\n"; $log = $client->getStruct(1); print "Log: $log->value\n"; $transport->close(); } catch (TException $tx) { print 'TException: '.$tx->getMessage()."\n"; } ?> thrift-0.16.0/tutorial/php/PhpServer.php000077500000000000000000000073701420101504100201550ustar00rootroot00000000000000#!/usr/bin/env php registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib'); $loader->registerNamespace('shared', $GEN_DIR); $loader->registerNamespace('tutorial', $GEN_DIR); $loader->register(); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* * This is not a stand-alone server. It should be run as a normal * php web script (like through Apache's mod_php) or as a cgi script * (like with the included runserver.py). You can connect to it with * THttpClient in any language that supports it. The PHP tutorial client * will work if you pass it the argument "--http". */ if (php_sapi_name() == 'cli') { ini_set("display_errors", "stderr"); } use Thrift\Protocol\TBinaryProtocol; use Thrift\Transport\TPhpStream; use Thrift\Transport\TBufferedTransport; class CalculatorHandler implements \tutorial\CalculatorIf { protected $log = array(); public function ping() { error_log("ping()"); } public function add($num1, $num2) { error_log("add({$num1}, {$num2})"); return $num1 + $num2; } public function calculate($logid, \tutorial\Work $w) { error_log("calculate({$logid}, {{$w->op}, {$w->num1}, {$w->num2}})"); switch ($w->op) { case \tutorial\Operation::ADD: $val = $w->num1 + $w->num2; break; case \tutorial\Operation::SUBTRACT: $val = $w->num1 - $w->num2; break; case \tutorial\Operation::MULTIPLY: $val = $w->num1 * $w->num2; break; case \tutorial\Operation::DIVIDE: if ($w->num2 == 0) { $io = new \tutorial\InvalidOperation(); $io->whatOp = $w->op; $io->why = "Cannot divide by 0"; throw $io; } $val = $w->num1 / $w->num2; break; default: $io = new \tutorial\InvalidOperation(); $io->whatOp = $w->op; $io->why = "Invalid Operation"; throw $io; } $log = new \shared\SharedStruct(); $log->key = $logid; $log->value = (string)$val; $this->log[$logid] = $log; return $val; } public function getStruct($key) { error_log("getStruct({$key})"); // This actually doesn't work because the PHP interpreter is // restarted for every request. //return $this->log[$key]; return new \shared\SharedStruct(array("key" => $key, "value" => "PHP is stateless!")); } public function zip() { error_log("zip()"); } }; header('Content-Type', 'application/x-thrift'); if (php_sapi_name() == 'cli') { echo "\r\n"; } $handler = new CalculatorHandler(); $processor = new \tutorial\CalculatorProcessor($handler); $transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W)); $protocol = new TBinaryProtocol($transport, true, true); $transport->open(); $processor->process($protocol, $protocol); $transport->close(); thrift-0.16.0/tutorial/php/runserver.py000077500000000000000000000021441420101504100201250ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os import BaseHTTPServer import CGIHTTPServer # chdir(2) into the tutorial directory. os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) class Handler(CGIHTTPServer.CGIHTTPRequestHandler): cgi_directories = ['/php'] BaseHTTPServer.HTTPServer(('', 8080), Handler).serve_forever() thrift-0.16.0/tutorial/py.tornado/000077500000000000000000000000001420101504100170225ustar00rootroot00000000000000thrift-0.16.0/tutorial/py.tornado/Makefile.am000077500000000000000000000022151420101504100210610ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-py.tornado/tutorial/Calculator.py gen-py.tornado/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen py:tornado -r $< all-local: gen-py.tornado/tutorial/Calculator.py tutorialserver: all ${PYTHON} PythonServer.py tutorialclient: all ${PYTHON} PythonClient.py clean-local: $(RM) -r gen-* EXTRA_DIST = \ PythonServer.py \ PythonClient.py thrift-0.16.0/tutorial/py.tornado/PythonClient.py000077500000000000000000000056071420101504100220270ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import glob import logging import sys sys.path.append('gen-py.tornado') sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) from tutorial import Calculator from tutorial.ttypes import Operation, Work, InvalidOperation from thrift import TTornado from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from tornado import gen from tornado import ioloop @gen.coroutine def communicate(): # create client transport = TTornado.TTornadoStreamTransport('localhost', 9090) # open the transport, bail on error try: yield transport.open() print('Transport is opened') except TTransport.TTransportException as ex: logging.error(ex) raise gen.Return() pfactory = TBinaryProtocol.TBinaryProtocolFactory() client = Calculator.Client(transport, pfactory) # ping yield client.ping() print("ping()") # add sum_ = yield client.add(1, 1) print("1 + 1 = {0}".format(sum_)) # make a oneway call without a callback (schedule the write and continue # without blocking) client.zip() print("zip() without callback") # make a oneway call with a callback (we'll wait for the stream write to # complete before continuing) client.zip() print("zip() with callback") # calculate 1/0 work = Work() work.op = Operation.DIVIDE work.num1 = 1 work.num2 = 0 try: quotient = yield client.calculate(1, work) print("Whoa? You know how to divide by zero ? -> {0}".format(quotient)) except InvalidOperation as io: print("InvalidOperation: {0}".format(io)) # calculate 15-10 work.op = Operation.SUBTRACT work.num1 = 15 work.num2 = 10 diff = yield client.calculate(1, work) print("15 - 10 = {0}".format(diff)) # getStruct log = yield client.getStruct(1) print("Check log: {0}".format(log.value)) # close the transport client._transport.close() raise gen.Return() def main(): # create an ioloop, do the above, then stop ioloop.IOLoop.current().run_sync(communicate) if __name__ == "__main__": main() thrift-0.16.0/tutorial/py.tornado/PythonServer.py000077500000000000000000000051251420101504100220520ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import glob import sys sys.path.append('gen-py.tornado') sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) from tutorial import Calculator from tutorial.ttypes import Operation, InvalidOperation from shared.ttypes import SharedStruct from thrift import TTornado from thrift.protocol import TBinaryProtocol from tornado import ioloop class CalculatorHandler(object): def __init__(self): self.log = {} def ping(self): print("ping()") def add(self, n1, n2): print("add({}, {})".format(n1, n2)) return n1 + n2 def calculate(self, logid, work): print("calculate({}, {})".format(logid, work)) if work.op == Operation.ADD: val = work.num1 + work.num2 elif work.op == Operation.SUBTRACT: val = work.num1 - work.num2 elif work.op == Operation.MULTIPLY: val = work.num1 * work.num2 elif work.op == Operation.DIVIDE: if work.num2 == 0: raise InvalidOperation(work.op, "Cannot divide by 0") val = work.num1 / work.num2 else: raise InvalidOperation(work.op, "Invalid operation") log = SharedStruct() log.key = logid log.value = '%d' % (val) self.log[logid] = log return val def getStruct(self, key): print("getStruct({})".format(key)) return self.log[key] def zip(self): print("zip()") def main(): handler = CalculatorHandler() processor = Calculator.Processor(handler) pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TTornado.TTornadoServer(processor, pfactory) print("Starting the server...") server.bind(9090) server.start(1) ioloop.IOLoop.instance().start() print("done.") if __name__ == "__main__": main() thrift-0.16.0/tutorial/py.twisted/000077500000000000000000000000001420101504100170375ustar00rootroot00000000000000thrift-0.16.0/tutorial/py.twisted/Makefile.am000077500000000000000000000022111420101504100210720ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen py:twisted -r $< all-local: gen-py/tutorial/Calculator.py tutorialserver: all ${PYTHON} PythonServer.py tutorialclient: all ${PYTHON} PythonClient.py clean-local: $(RM) -r gen-* EXTRA_DIST = \ PythonClient.py \ PythonServer.py \ PythonServer.tac thrift-0.16.0/tutorial/py.twisted/PythonClient.py000077500000000000000000000044271420101504100220430ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import glob import sys sys.path.append('gen-py.twisted') sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation, Work from twisted.internet.defer import inlineCallbacks from twisted.internet import reactor from twisted.internet.protocol import ClientCreator from thrift.transport import TTwisted from thrift.protocol import TBinaryProtocol @inlineCallbacks def main(client): yield client.ping() print('ping()') sum = yield client.add(1, 1) print(('1+1=%d' % (sum))) work = Work() work.op = Operation.DIVIDE work.num1 = 1 work.num2 = 0 try: quotient = yield client.calculate(1, work) print('Whoa? You know how to divide by zero?') print('FYI the answer is %d' % quotient) except InvalidOperation as e: print(('InvalidOperation: %r' % e)) work.op = Operation.SUBTRACT work.num1 = 15 work.num2 = 10 diff = yield client.calculate(1, work) print(('15-10=%d' % (diff))) log = yield client.getStruct(1) print(('Check log: %s' % (log.value))) reactor.stop() if __name__ == '__main__': d = ClientCreator(reactor, TTwisted.ThriftClientProtocol, Calculator.Client, TBinaryProtocol.TBinaryProtocolFactory(), ).connectTCP("127.0.0.1", 9090) d.addCallback(lambda conn: conn.client) d.addCallback(main) reactor.run() thrift-0.16.0/tutorial/py.twisted/PythonServer.py000077500000000000000000000051341420101504100220670ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import glob import sys sys.path.append('gen-py.twisted') sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation from shared.ttypes import SharedStruct from zope.interface import implements from twisted.internet import reactor from thrift.transport import TTwisted from thrift.protocol import TBinaryProtocol class CalculatorHandler: implements(Calculator.Iface) def __init__(self): self.log = {} def ping(self): print('ping()') def add(self, n1, n2): print('add(%d,%d)' % (n1, n2)) return n1 + n2 def calculate(self, logid, work): print('calculate(%d, %r)' % (logid, work)) if work.op == Operation.ADD: val = work.num1 + work.num2 elif work.op == Operation.SUBTRACT: val = work.num1 - work.num2 elif work.op == Operation.MULTIPLY: val = work.num1 * work.num2 elif work.op == Operation.DIVIDE: if work.num2 == 0: raise InvalidOperation(work.op, 'Cannot divide by 0') val = work.num1 / work.num2 else: raise InvalidOperation(work.op, 'Invalid operation') log = SharedStruct() log.key = logid log.value = '%d' % (val) self.log[logid] = log return val def getStruct(self, key): print('getStruct(%d)' % (key)) return self.log[key] def zip(self): print('zip()') if __name__ == '__main__': handler = CalculatorHandler() processor = Calculator.Processor(handler) pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = reactor.listenTCP( 9090, TTwisted.ThriftServerFactory(processor, pfactory), interface="127.0.0.1") reactor.run() thrift-0.16.0/tutorial/py.twisted/PythonServer.tac000077500000000000000000000032421420101504100222040ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # from twisted.application import internet, service from thrift.transport import TTwisted import glob import sys sys.path.append('gen-py.twisted') sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) from tutorial import Calculator from PythonServer import CalculatorHandler from thrift.protocol import TBinaryProtocol def make_application(): application = service.Application('CalcServer') handler = CalculatorHandler() processor = Calculator.Processor(handler) serverFactory = TTwisted.ThriftServerFactory( processor, TBinaryProtocol.TBinaryProtocolFactory()) calcService = internet.TCPServer(9090, serverFactory) multiService = service.MultiService() calcService.setServiceParent(multiService) multiService.setServiceParent(application) return application if __name__ == '__main__': application = make_application() thrift-0.16.0/tutorial/py/000077500000000000000000000000001420101504100153555ustar00rootroot00000000000000thrift-0.16.0/tutorial/py/Makefile.am000077500000000000000000000021721420101504100174160ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen py -r $< all-local: gen-py/tutorial/Calculator.py tutorialserver: all ${PYTHON} PythonServer.py tutorialclient: all ${PYTHON} PythonClient.py clean-local: $(RM) -r gen-* EXTRA_DIST = \ setup.cfg \ PythonServer.py \ PythonClient.py thrift-0.16.0/tutorial/py/PythonClient.py000077500000000000000000000044621420101504100203600ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import sys import glob sys.path.append('gen-py') sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation, Work from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol def main(): # Make socket transport = TSocket.TSocket('localhost', 9090) # Buffering is critical. Raw sockets are very slow transport = TTransport.TBufferedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = Calculator.Client(protocol) # Connect! transport.open() client.ping() print('ping()') sum_ = client.add(1, 1) print('1+1=%d' % sum_) work = Work() work.op = Operation.DIVIDE work.num1 = 1 work.num2 = 0 try: quotient = client.calculate(1, work) print('Whoa? You know how to divide by zero?') print('FYI the answer is %d' % quotient) except InvalidOperation as e: print('InvalidOperation: %r' % e) work.op = Operation.SUBTRACT work.num1 = 15 work.num2 = 10 diff = client.calculate(1, work) print('15-10=%d' % diff) log = client.getStruct(1) print('Check log: %s' % log.value) # Close! transport.close() if __name__ == '__main__': try: main() except Thrift.TException as tx: print('%s' % tx.message) thrift-0.16.0/tutorial/py/PythonServer.py000077500000000000000000000056351420101504100204130ustar00rootroot00000000000000#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import glob import sys sys.path.append('gen-py') sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0]) from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation from shared.ttypes import SharedStruct from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer class CalculatorHandler: def __init__(self): self.log = {} def ping(self): print('ping()') def add(self, n1, n2): print('add(%d,%d)' % (n1, n2)) return n1 + n2 def calculate(self, logid, work): print('calculate(%d, %r)' % (logid, work)) if work.op == Operation.ADD: val = work.num1 + work.num2 elif work.op == Operation.SUBTRACT: val = work.num1 - work.num2 elif work.op == Operation.MULTIPLY: val = work.num1 * work.num2 elif work.op == Operation.DIVIDE: if work.num2 == 0: raise InvalidOperation(work.op, 'Cannot divide by 0') val = work.num1 / work.num2 else: raise InvalidOperation(work.op, 'Invalid operation') log = SharedStruct() log.key = logid log.value = '%d' % (val) self.log[logid] = log return val def getStruct(self, key): print('getStruct(%d)' % (key)) return self.log[key] def zip(self): print('zip()') if __name__ == '__main__': handler = CalculatorHandler() processor = Calculator.Processor(handler) transport = TSocket.TServerSocket(host='127.0.0.1', port=9090) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) # You could do one of these for a multithreaded server # server = TServer.TThreadedServer( # processor, transport, tfactory, pfactory) # server = TServer.TThreadPoolServer( # processor, transport, tfactory, pfactory) print('Starting the server...') server.serve() print('done.') thrift-0.16.0/tutorial/py/setup.cfg000066400000000000000000000000271420101504100171750ustar00rootroot00000000000000[flake8] ignore = E402 thrift-0.16.0/tutorial/rb/000077500000000000000000000000001420101504100153305ustar00rootroot00000000000000thrift-0.16.0/tutorial/rb/Makefile.am000077500000000000000000000021111420101504100173620ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # gen-rb/calculator.rb gen-rb/shared_service.rb: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) --gen rb -r $< all-local: gen-rb/calculator.rb tutorialserver: all ${RUBY} RubyServer.rb tutorialclient: all ${RUBY} RubyClient.rb clean-local: $(RM) -r gen-* EXTRA_DIST = \ RubyServer.rb \ RubyClient.rb thrift-0.16.0/tutorial/rb/RubyClient.rb000077500000000000000000000034751420101504100177510ustar00rootroot00000000000000#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # $:.push('gen-rb') $:.unshift '../../lib/rb/lib' require 'thrift' require 'calculator' begin port = ARGV[0] || 9090 transport = Thrift::BufferedTransport.new(Thrift::Socket.new('localhost', port)) protocol = Thrift::BinaryProtocol.new(transport) client = Calculator::Client.new(protocol) transport.open() client.ping() print "ping()\n" sum = client.add(1,1) print "1+1=", sum, "\n" sum = client.add(1,4) print "1+4=", sum, "\n" work = Work.new() work.op = Operation::SUBTRACT work.num1 = 15 work.num2 = 10 diff = client.calculate(1, work) print "15-10=", diff, "\n" log = client.getStruct(1) print "Log: ", log.value, "\n" begin work.op = Operation::DIVIDE work.num1 = 1 work.num2 = 0 quot = client.calculate(1, work) puts "Whoa, we can divide by 0 now?" rescue InvalidOperation => io print "InvalidOperation: ", io.why, "\n" end client.zip() print "zip\n" transport.close() rescue Thrift::Exception => tx print 'Thrift::Exception: ', tx.message, "\n" end thrift-0.16.0/tutorial/rb/RubyServer.rb000077500000000000000000000044541420101504100177770ustar00rootroot00000000000000#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # $:.push('gen-rb') $:.unshift '../../lib/rb/lib' require 'thrift' require 'calculator' require 'shared_types' class CalculatorHandler def initialize() @log = {} end def ping() puts "ping()" end def add(n1, n2) print "add(", n1, ",", n2, ")\n" return n1 + n2 end def calculate(logid, work) print "calculate(", logid, ", {", work.op, ",", work.num1, ",", work.num2,"})\n" if work.op == Operation::ADD val = work.num1 + work.num2 elsif work.op == Operation::SUBTRACT val = work.num1 - work.num2 elsif work.op == Operation::MULTIPLY val = work.num1 * work.num2 elsif work.op == Operation::DIVIDE if work.num2 == 0 x = InvalidOperation.new() x.whatOp = work.op x.why = "Cannot divide by 0" raise x end val = work.num1 / work.num2 else x = InvalidOperation.new() x.whatOp = work.op x.why = "Invalid operation" raise x end entry = SharedStruct.new() entry.key = logid entry.value = "#{val}" @log[logid] = entry return val end def getStruct(key) print "getStruct(", key, ")\n" return @log[key] end def zip() print "zip\n" end end handler = CalculatorHandler.new() processor = Calculator::Processor.new(handler) transport = Thrift::ServerSocket.new(9090) transportFactory = Thrift::BufferedTransportFactory.new() server = Thrift::SimpleServer.new(processor, transport, transportFactory) puts "Starting the server..." server.serve() puts "done." thrift-0.16.0/tutorial/rs/000077500000000000000000000000001420101504100153515ustar00rootroot00000000000000thrift-0.16.0/tutorial/rs/Cargo.toml000066400000000000000000000004771420101504100173110ustar00rootroot00000000000000[package] name = "thrift-tutorial" version = "0.1.0" edition = "2018" license = "Apache-2.0" authors = ["Apache Thrift Developers "] exclude = ["Makefile*", "shared.rs", "tutorial.rs"] publish = false [dependencies] clap = "~2.33" bitflags = "=1.2" [dependencies.thrift] path = "../../lib/rs" thrift-0.16.0/tutorial/rs/Makefile.am000066400000000000000000000027511420101504100174120ustar00rootroot00000000000000# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # THRIFT = $(top_builddir)/compiler/cpp/thrift gen-rs/tutorial.rs gen-rs/shared.rs: $(top_srcdir)/tutorial/tutorial.thrift $(THRIFT) -out src --gen rs -r $< all-local: gen-rs/tutorial.rs $(CARGO) build $(CARGO) fmt --all -- --check $(CARGO) clippy --all -- -D warnings [ -d bin ] || mkdir bin cp target/debug/tutorial_server bin/tutorial_server cp target/debug/tutorial_client bin/tutorial_client check: all tutorialserver: all bin/tutorial_server tutorialclient: all bin/tutorial_client clean-local: $(CARGO) clean -$(RM) Cargo.lock -$(RM) src/shared.rs -$(RM) src/tutorial.rs -$(RM) -r bin EXTRA_DIST = \ Cargo.toml \ src/lib.rs \ src/bin/tutorial_server.rs \ src/bin/tutorial_client.rs \ README.md thrift-0.16.0/tutorial/rs/README.md000066400000000000000000000145461420101504100166420ustar00rootroot00000000000000# Rust Language Bindings for Thrift ## Getting Started 1. Get the [Thrift compiler](https://thrift.apache.org). 2. Add the thrift crate to your `Cargo.toml`. ```toml thrift = "x.y.z" # x.y.z is the version of the thrift compiler ``` 3. Generate Rust sources for your IDL (for example, `Tutorial.thrift`). ```shell thrift -out my_rust_program/src --gen rs -r Tutorial.thrift ``` 4. Use the generated source in your code. ```rust // generated Rust module from Thrift IDL mod tutorial; use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol}; use thrift::protocol::{TInputProtocol, TOutputProtocol}; use thrift::transport::{TFramedReadTransport, TFramedWriteTransport}; use thrift::transport::{TIoChannel, TTcpChannel}; use tutorial::{CalculatorSyncClient, TCalculatorSyncClient}; use tutorial::{Operation, Work}; fn main() { match run() { Ok(()) => println!("client ran successfully"), Err(e) => { println!("client failed with {:?}", e); std::process::exit(1); } } } fn run() -> thrift::Result<()> { // // build client // println!("connect to server on 127.0.0.1:9090"); let mut c = TTcpChannel::new(); c.open("127.0.0.1:9090")?; let (i_chan, o_chan) = c.split()?; let i_prot = TCompactInputProtocol::new( TFramedReadTransport::new(i_chan) ); let o_prot = TCompactOutputProtocol::new( TFramedWriteTransport::new(o_chan) ); let mut client = CalculatorSyncClient::new(i_prot, o_prot); // // alright! - let's make some calls // // two-way, void return client.ping()?; // two-way with some return let res = client.calculate( 72, Work::new(7, 8, Operation::Multiply, None) )?; println!("multiplied 7 and 8, got {}", res); // two-way and returns a Thrift-defined exception let res = client.calculate( 77, Work::new(2, 0, Operation::Divide, None) ); match res { Ok(v) => panic!("shouldn't have succeeded with result {}", v), Err(e) => println!("divide by zero failed with {:?}", e), } // one-way client.zip()?; // done! Ok(()) } ``` ## Code Generation ### Thrift Files and Generated Modules The Thrift code generator takes each Thrift file and generates a Rust module with the same name snake-cased. For example, running the compiler on `ThriftTest.thrift` creates `thrift_test.rs`. To use these generated files add `mod ...` and `use ...` declarations to your `lib.rs` or `main.rs` - one for each generated file. ### Results and Errors The Thrift runtime library defines a `thrift::Result` and a `thrift::Error` type, both of which are used throughout the runtime library and in all generated code. Conversions are defined from `std::io::Error`, `str` and `String` into `thrift::Error`. ### Thrift Type and their Rust Equivalents Thrift defines a number of types, each of which is translated into its Rust equivalent by the code generator. * Primitives (bool, i8, i16, i32, i64, double, string, binary) * Typedefs * Enums * Containers * Structs * Unions * Exceptions * Services * Constants (primitives, containers, structs) In addition, unless otherwise noted, thrift includes are translated into `use ...` statements in the generated code, and all declarations, parameters, traits and types in the generated code are namespaced appropriately. The following subsections cover each type and their generated Rust equivalent. ### Primitives Thrift primitives have straightforward Rust equivalents. * bool: `bool` * i8: `i8` * i16: `i16` * i32: `i32` * i64: `i64` * double: `OrderedFloat` * string: `String` * binary: `Vec` ### Typedefs A typedef is translated to a `pub type` declaration. ```thrift typedef i64 UserId typedef map MapType ``` ```rust pub type UserId = i64; pub type MapType = BTreeMap; ``` ### Enums A Thrift enum is represented as a Rust enum, and each variant is transcribed 1:1. ```thrift enum Numberz { ONE = 1, TWO, THREE, FIVE = 5, SIX, EIGHT = 8 } ``` ```rust #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum Numberz { ONE = 1, TWO = 2, THREE = 3, FIVE = 5, SIX = 6, EIGHT = 8, } impl TryFrom for Numberz { // ... } ``` ### Containers Thrift has three container types: list, set and map. They are translated into Rust `Vec`, `BTreeSet` and `BTreeMap` respectively. Any Thrift type (this includes structs, enums and typedefs) can be a list/set element or a map key/value. #### List ```thrift list numbers ``` ```rust numbers: Vec ``` #### Set ```thrift set numbers ``` ```rust numbers: BTreeSet ``` #### Map ```thrift map numbers ``` ```rust numbers: BTreeMap ``` ### Structs A Thrift struct is represented as a Rust struct, and each field transcribed 1:1. ```thrift struct CrazyNesting { 1: string string_field, 2: optional set set_field, 3: required list< map, map>>>> > 4: binary binary_field } ``` ```rust #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct CrazyNesting { pub string_field: Option, pub set_field: Option>, pub list_field: Vec< BTreeMap< BTreeSet, BTreeMap>>> > >, pub binary_field: Option>, } impl CrazyNesting { pub fn read_from_in_protocol(i_prot: &mut TInputProtocol) -> thrift::Result { // ... } pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) -> thrift::Result<()> { // ... } } ``` ##### Optionality Thrift has 3 "optionality" types: 1. Required 2. Optional 3. Default The Rust code generator encodes *Required* fields as the bare type itself, while *Optional* and *Default* fields are encoded as `Option`. ```thrift struct Foo { 1: required string bar // 1. required 2: optional string baz // 2. optional 3: string qux // 3. default } ``` ```rust pub struct Foo { bar: String, // 1. required baz: Option, // 2. optional qux: Option, // 3. default } ``` ## Known Issues * Struct constants are not supported * Map, list and set constants require a const holder struct thrift-0.16.0/tutorial/rs/src/000077500000000000000000000000001420101504100161405ustar00rootroot00000000000000thrift-0.16.0/tutorial/rs/src/bin/000077500000000000000000000000001420101504100167105ustar00rootroot00000000000000thrift-0.16.0/tutorial/rs/src/bin/tutorial_client.rs000066400000000000000000000104421420101504100224600ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use clap::{clap_app, value_t}; use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol}; use thrift::transport::{ ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel, TTcpChannel, WriteHalf, }; use thrift_tutorial::shared::TSharedServiceSyncClient; use thrift_tutorial::tutorial::{CalculatorSyncClient, Operation, TCalculatorSyncClient, Work}; fn main() { match run() { Ok(()) => println!("tutorial client ran successfully"), Err(e) => { println!("tutorial client failed with error {:?}", e); std::process::exit(1); } } } fn run() -> thrift::Result<()> { let options = clap_app!(rust_tutorial_client => (version: "0.1.0") (author: "Apache Thrift Developers ") (about: "Thrift Rust tutorial client") (@arg host: --host +takes_value "host on which the tutorial server listens") (@arg port: --port +takes_value "port on which the tutorial server listens") ); let matches = options.get_matches(); // get any passed-in args or the defaults let host = matches.value_of("host").unwrap_or("127.0.0.1"); let port = value_t!(matches, "port", u16).unwrap_or(9090); // build our client and connect to the host:port let mut client = new_client(host, port)?; // alright! // let's start making some calls // let's start with a ping; the server should respond println!("ping!"); client.ping()?; // simple add println!("add"); let res = client.add(1, 2)?; println!("added 1, 2 and got {}", res); let logid = 32; // let's do...a multiply! let res = client.calculate(logid, Work::new(7, 8, Operation::MULTIPLY, None))?; println!("multiplied 7 and 8 and got {}", res); // let's get the log for it let res = client.get_struct(logid /* 32 */)?; println!("got log {:?} for operation {}", res, logid); // ok - let's be bad :( // do a divide by 0 // logid doesn't matter; won't be recorded let res = client.calculate(77, Work::new(2, 0, Operation::DIVIDE, "we bad".to_owned())); // we should have gotten an exception back match res { Ok(v) => panic!("should not have succeeded with result {}", v), Err(e) => println!("divide by zero failed with error {:?}", e), } // let's do a one-way call println!("zip"); client.zip()?; // and then close out with a final ping println!("ping!"); client.ping()?; Ok(()) } type ClientInputProtocol = TCompactInputProtocol>>; type ClientOutputProtocol = TCompactOutputProtocol>>; fn new_client( host: &str, port: u16, ) -> thrift::Result> { let mut c = TTcpChannel::new(); // open the underlying TCP stream println!("connecting to tutorial server on {}:{}", host, port); c.open(&format!("{}:{}", host, port))?; // clone the TCP channel into two halves, one which // we'll use for reading, the other for writing let (i_chan, o_chan) = c.split()?; // wrap the raw sockets (slow) with a buffered transport of some kind let i_tran = TFramedReadTransport::new(i_chan); let o_tran = TFramedWriteTransport::new(o_chan); // now create the protocol implementations let i_prot = TCompactInputProtocol::new(i_tran); let o_prot = TCompactOutputProtocol::new(o_tran); // we're done! Ok(CalculatorSyncClient::new(i_prot, o_prot)) } thrift-0.16.0/tutorial/rs/src/bin/tutorial_server.rs000066400000000000000000000140531420101504100225120ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::collections::HashMap; use std::convert::{From, Into}; use std::default::Default; use std::sync::Mutex; use clap::{clap_app, value_t}; use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory}; use thrift::server::TServer; use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory}; use thrift_tutorial::shared::{SharedServiceSyncHandler, SharedStruct}; use thrift_tutorial::tutorial::{CalculatorSyncHandler, CalculatorSyncProcessor}; use thrift_tutorial::tutorial::{InvalidOperation, Operation, Work}; fn main() { match run() { Ok(()) => println!("tutorial server ran successfully"), Err(e) => { println!("tutorial server failed with error {:?}", e); std::process::exit(1); } } } fn run() -> thrift::Result<()> { let options = clap_app!(rust_tutorial_server => (version: "0.1.0") (author: "Apache Thrift Developers ") (about: "Thrift Rust tutorial server") (@arg port: --port +takes_value "port on which the tutorial server listens") ); let matches = options.get_matches(); let port = value_t!(matches, "port", u16).unwrap_or(9090); let listen_address = format!("127.0.0.1:{}", port); println!("binding to {}", listen_address); let i_tran_fact = TFramedReadTransportFactory::new(); let i_prot_fact = TCompactInputProtocolFactory::new(); let o_tran_fact = TFramedWriteTransportFactory::new(); let o_prot_fact = TCompactOutputProtocolFactory::new(); // demux incoming messages let processor = CalculatorSyncProcessor::new(CalculatorServer { ..Default::default() }); // create the server and start listening let mut server = TServer::new( i_tran_fact, i_prot_fact, o_tran_fact, o_prot_fact, processor, 10, ); server.listen(&listen_address) } /// Handles incoming Calculator service calls. struct CalculatorServer { log: Mutex>, } impl Default for CalculatorServer { fn default() -> CalculatorServer { CalculatorServer { log: Mutex::new(HashMap::new()), } } } // since Calculator extends SharedService we have to implement the // handler for both traits. // // SharedService handler impl SharedServiceSyncHandler for CalculatorServer { fn handle_get_struct(&self, key: i32) -> thrift::Result { let log = self.log.lock().unwrap(); log.get(&key) .cloned() .ok_or_else(|| format!("could not find log for key {}", key).into()) } } // Calculator handler impl CalculatorSyncHandler for CalculatorServer { fn handle_ping(&self) -> thrift::Result<()> { println!("pong!"); Ok(()) } fn handle_add(&self, num1: i32, num2: i32) -> thrift::Result { println!("handling add: n1:{} n2:{}", num1, num2); Ok(num1 + num2) } fn handle_calculate(&self, logid: i32, w: Work) -> thrift::Result { println!("handling calculate: l:{}, w:{:?}", logid, w); let res = if let Some(ref op) = w.op { if w.num1.is_none() || w.num2.is_none() { Err(InvalidOperation { what_op: Some(op.into()), why: Some("no operands specified".to_owned()), }) } else { // so that I don't have to call unwrap() multiple times below let num1 = w.num1.as_ref().expect("operands checked"); let num2 = w.num2.as_ref().expect("operands checked"); match *op { Operation::ADD => Ok(num1 + num2), Operation::SUBTRACT => Ok(num1 - num2), Operation::MULTIPLY => Ok(num1 * num2), Operation::DIVIDE => { if *num2 == 0 { Err(InvalidOperation { what_op: Some(op.into()), why: Some("divide by 0".to_owned()), }) } else { Ok(num1 / num2) } } _ => { let op_val: i32 = op.into(); Err(InvalidOperation { what_op: Some(op_val), why: Some(format!("unsupported operation type '{}'", op_val)), }) } } } } else { Err(InvalidOperation::new( None, "no operation specified".to_owned(), )) }; // if the operation was successful log it if let Ok(ref v) = res { let mut log = self.log.lock().unwrap(); log.insert(logid, SharedStruct::new(logid, format!("{}", v))); } // the try! macro automatically maps errors // but, since we aren't using that here we have to map errors manually // // exception structs defined in the IDL have an auto-generated // impl of From::from res.map_err(From::from) } fn handle_zip(&self) -> thrift::Result<()> { println!("handling zip"); Ok(()) } } thrift-0.16.0/tutorial/rs/src/lib.rs000066400000000000000000000015001420101504100172500ustar00rootroot00000000000000// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. pub mod shared; pub mod tutorial; thrift-0.16.0/tutorial/shared.thrift000066400000000000000000000024021420101504100174130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * This Thrift file can be included by other Thrift files that want to share * these definitions. */ namespace cl shared namespace cpp shared namespace d share // "shared" would collide with the eponymous D keyword. namespace dart shared namespace java shared namespace perl shared namespace php shared namespace haxe shared namespace netstd shared struct SharedStruct { 1: i32 key 2: string value } service SharedService { SharedStruct getStruct(1: i32 key) } thrift-0.16.0/tutorial/tutorial.thrift000066400000000000000000000115321420101504100200140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ # Thrift Tutorial # Mark Slee (mcslee@facebook.com) # # This file aims to teach you how to use Thrift, in a .thrift file. Neato. The # first thing to notice is that .thrift files support standard shell comments. # This lets you make your thrift file executable and include your Thrift build # step on the top line. And you can place comments like this anywhere you like. # # Before running this file, you will need to have installed the thrift compiler # into /usr/local/bin. /** * The first thing to know about are types. The available types in Thrift are: * * bool Boolean, one byte * i8 (byte) Signed 8-bit integer * i16 Signed 16-bit integer * i32 Signed 32-bit integer * i64 Signed 64-bit integer * double 64-bit floating point value * string String * binary Blob (byte array) * map Map from one type to another * list Ordered list of one type * set Set of unique elements of one type * * Did you also notice that Thrift supports C style comments? */ // Just in case you were wondering... yes. We support simple C comments too. /** * Thrift files can reference other Thrift files to include common struct * and service definitions. These are found using the current path, or by * searching relative to any paths specified with the -I compiler flag. * * Included objects are accessed using the name of the .thrift file as a * prefix. i.e. shared.SharedObject */ include "shared.thrift" /** * Thrift files can namespace, package, or prefix their output in various * target languages. */ namespace cl tutorial namespace cpp tutorial namespace d tutorial namespace dart tutorial namespace java tutorial namespace php tutorial namespace perl tutorial namespace haxe tutorial namespace netstd tutorial /** * Thrift lets you do typedefs to get pretty names for your types. Standard * C style here. */ typedef i32 MyInteger /** * Thrift also lets you define constants for use across languages. Complex * types and structs are specified using JSON notation. */ const i32 INT32CONSTANT = 9853 const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} /** * You can define enums, which are just 32 bit integers. Values are optional * and start at 1 if not supplied, C style again. */ enum Operation { ADD = 1, SUBTRACT = 2, MULTIPLY = 3, DIVIDE = 4 } /** * Structs are the basic complex data structures. They are comprised of fields * which each have an integer identifier, a type, a symbolic name, and an * optional default value. * * Fields can be declared "optional", which ensures they will not be included * in the serialized output if they aren't set. Note that this requires some * manual management in some languages. */ struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } /** * Structs can also be exceptions, if they are nasty. */ exception InvalidOperation { 1: i32 whatOp, 2: string why } /** * Ahh, now onto the cool part, defining a service. Services just need a name * and can optionally inherit from another service using the extends keyword. */ service Calculator extends shared.SharedService { /** * A method definition looks like C code. It has a return type, arguments, * and optionally a list of exceptions that it may throw. Note that argument * lists and exception lists are specified using the exact same syntax as * field lists in struct or exception definitions. */ void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), /** * This method has a oneway modifier. That means the client only makes * a request and does not listen for any response at all. Oneway methods * must be void. */ oneway void zip() } /** * That just about covers the basics. Take a look in the test/ folder for more * detailed examples. After you run this file, your generated code shows up * in folders with names gen-. The generated code isn't too scary * to look at. It even has pretty indentation. */